zotregistry.io/zot@v1.4.4-0.20231124084042-02a8ed785457/pkg/extensions/sync/httpclient/client.go (about) 1 package client 2 3 import ( 4 "context" 5 "io" 6 "net/http" 7 "net/url" 8 "sync" 9 10 "zotregistry.io/zot/pkg/common" 11 "zotregistry.io/zot/pkg/log" 12 ) 13 14 type Config struct { 15 URL string 16 Username string 17 Password string 18 CertDir string 19 TLSVerify bool 20 } 21 22 type Client struct { 23 config *Config 24 client *http.Client 25 url *url.URL 26 lock *sync.RWMutex 27 log log.Logger 28 } 29 30 func New(config Config, log log.Logger) (*Client, error) { 31 client := &Client{log: log, lock: new(sync.RWMutex)} 32 if err := client.SetConfig(config); err != nil { 33 return nil, err 34 } 35 36 return client, nil 37 } 38 39 func (httpClient *Client) GetConfig() *Config { 40 httpClient.lock.RLock() 41 defer httpClient.lock.RUnlock() 42 43 return httpClient.config 44 } 45 46 func (httpClient *Client) GetHostname() string { 47 httpClient.lock.RLock() 48 defer httpClient.lock.RUnlock() 49 50 return httpClient.url.Host 51 } 52 53 func (httpClient *Client) SetConfig(config Config) error { 54 httpClient.lock.Lock() 55 defer httpClient.lock.Unlock() 56 57 clientURL, err := url.Parse(config.URL) 58 if err != nil { 59 return err 60 } 61 62 httpClient.url = clientURL 63 64 client, err := common.CreateHTTPClient(config.TLSVerify, clientURL.Host, config.CertDir) 65 if err != nil { 66 return err 67 } 68 69 httpClient.client = client 70 httpClient.config = &config 71 72 return nil 73 } 74 75 func (httpClient *Client) Ping() bool { 76 httpClient.lock.RLock() 77 defer httpClient.lock.RUnlock() 78 79 pingURL := *httpClient.url 80 81 pingURL = *pingURL.JoinPath("/v2/") 82 83 req, err := http.NewRequest(http.MethodGet, pingURL.String(), nil) //nolint 84 if err != nil { 85 return false 86 } 87 88 resp, err := httpClient.client.Do(req) 89 if err != nil { 90 httpClient.log.Error().Err(err).Str("url", pingURL.String()). 91 Msg("sync: failed to ping registry") 92 93 return false 94 } 95 96 defer resp.Body.Close() 97 98 if resp.StatusCode == http.StatusOK || resp.StatusCode == http.StatusUnauthorized { 99 return true 100 } 101 102 body, err := io.ReadAll(resp.Body) 103 if err != nil { 104 httpClient.log.Error().Err(err).Str("url", pingURL.String()). 105 Msg("failed to read body while pinging registry") 106 107 return false 108 } 109 110 httpClient.log.Error().Str("url", pingURL.String()).Str("body", string(body)).Int("statusCode", resp.StatusCode). 111 Msg("sync: failed to ping registry") 112 113 return false 114 } 115 116 func (httpClient *Client) MakeGetRequest(ctx context.Context, resultPtr interface{}, mediaType string, 117 route ...string, 118 ) ([]byte, string, int, error) { 119 httpClient.lock.RLock() 120 defer httpClient.lock.RUnlock() 121 122 url := *httpClient.url 123 124 for _, r := range route { 125 url = *url.JoinPath(r) 126 } 127 128 url.RawQuery = url.Query().Encode() 129 130 body, mediaType, statusCode, err := common.MakeHTTPGetRequest(ctx, httpClient.client, httpClient.config.Username, 131 httpClient.config.Password, resultPtr, 132 url.String(), mediaType, httpClient.log) 133 134 return body, mediaType, statusCode, err 135 }