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  }