mirror of
https://github.com/goharbor/harbor.git
synced 2025-01-08 00:48:17 +01:00
7bf8a2d044
In some perspectives to reduce the too many charts performence issue Signed-off-by: DQ <dengq@vmware.com>
143 lines
3.1 KiB
Go
143 lines
3.1 KiB
Go
package chartserver
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"net/url"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
commonhttp "github.com/goharbor/harbor/src/common/http"
|
|
"github.com/goharbor/harbor/src/lib/errors"
|
|
)
|
|
|
|
const (
|
|
clientTimeout = 30 * time.Second
|
|
maxIdleConnections = 10
|
|
idleConnectionTimeout = 30 * time.Second
|
|
)
|
|
|
|
var (
|
|
once sync.Once
|
|
chartTransport *http.Transport
|
|
)
|
|
|
|
// ChartClient is a http client to get the content from the external http server
|
|
type ChartClient struct {
|
|
// HTTP client
|
|
httpClient *http.Client
|
|
|
|
// Auth info
|
|
credential *Credential
|
|
}
|
|
|
|
// NewChartClient is constructor of ChartClient
|
|
// credential can be nil
|
|
func NewChartClient(credential *Credential) *ChartClient { // Create http client with customized timeouts
|
|
once.Do(func() {
|
|
chartTransport = commonhttp.GetHTTPTransport(commonhttp.SecureTransport).Clone()
|
|
chartTransport.MaxIdleConns = maxIdleConnections
|
|
chartTransport.IdleConnTimeout = idleConnectionTimeout
|
|
})
|
|
|
|
client := &http.Client{
|
|
Timeout: clientTimeout,
|
|
Transport: chartTransport,
|
|
}
|
|
|
|
return &ChartClient{
|
|
httpClient: client,
|
|
credential: credential,
|
|
}
|
|
}
|
|
|
|
// GetContent get the bytes from the specified url
|
|
func (cc *ChartClient) GetContent(addr string) ([]byte, error) {
|
|
response, err := cc.sendRequest(addr, http.MethodGet, nil)
|
|
if err != nil {
|
|
err = errors.Wrap(err, "get content failed")
|
|
return nil, err
|
|
}
|
|
|
|
content, err := ioutil.ReadAll(response.Body)
|
|
if err != nil {
|
|
err = errors.Wrap(err, "Read response body error")
|
|
return nil, err
|
|
}
|
|
defer response.Body.Close()
|
|
|
|
if response.StatusCode != http.StatusOK {
|
|
text, err := extractError(content)
|
|
if err != nil {
|
|
err = errors.Wrap(err, "Extract content error failed")
|
|
return nil, err
|
|
}
|
|
return nil, &commonhttp.Error{
|
|
Code: response.StatusCode,
|
|
Message: text,
|
|
}
|
|
}
|
|
return content, nil
|
|
}
|
|
|
|
// DeleteContent sends deleting request to the addr to delete content
|
|
func (cc *ChartClient) DeleteContent(addr string) error {
|
|
response, err := cc.sendRequest(addr, http.MethodDelete, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
content, err := ioutil.ReadAll(response.Body)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer response.Body.Close()
|
|
|
|
if response.StatusCode != http.StatusOK {
|
|
text, err := extractError(content)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return &commonhttp.Error{
|
|
Code: response.StatusCode,
|
|
Message: text,
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// sendRequest sends requests to the addr with the specified spec
|
|
func (cc *ChartClient) sendRequest(addr string, method string, body io.Reader) (*http.Response, error) {
|
|
if len(strings.TrimSpace(addr)) == 0 {
|
|
return nil, errors.New("empty url is not allowed")
|
|
}
|
|
|
|
fullURI, err := url.Parse(addr)
|
|
if err != nil {
|
|
err = errors.Wrap(err, "Invalid url")
|
|
return nil, err
|
|
}
|
|
|
|
request, err := http.NewRequest(method, addr, body)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Set basic auth
|
|
if cc.credential != nil {
|
|
request.SetBasicAuth(cc.credential.Username, cc.credential.Password)
|
|
}
|
|
|
|
response, err := cc.httpClient.Do(request)
|
|
if err != nil {
|
|
err = errors.Wrap(err, fmt.Sprintf("send request %s %s failed", method, fullURI.Path))
|
|
return nil, err
|
|
}
|
|
|
|
return response, nil
|
|
}
|