...

Source file src/github.com/theupdateframework/go-tuf/client/remote_store.go

Documentation: github.com/theupdateframework/go-tuf/client

     1  package client
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"net/http"
     7  	"net/url"
     8  	"path"
     9  	"strconv"
    10  	"strings"
    11  	"time"
    12  )
    13  
    14  type HTTPRemoteOptions struct {
    15  	MetadataPath string
    16  	TargetsPath  string
    17  	UserAgent    string
    18  	Retries      *HTTPRemoteRetries
    19  }
    20  
    21  type HTTPRemoteRetries struct {
    22  	Delay time.Duration
    23  	Total time.Duration
    24  }
    25  
    26  var DefaultHTTPRetries = &HTTPRemoteRetries{
    27  	Delay: time.Second,
    28  	Total: 10 * time.Second,
    29  }
    30  
    31  func HTTPRemoteStore(baseURL string, opts *HTTPRemoteOptions, client *http.Client) (RemoteStore, error) {
    32  	if !strings.HasPrefix(baseURL, "http") {
    33  		return nil, ErrInvalidURL{baseURL}
    34  	}
    35  	if opts == nil {
    36  		opts = &HTTPRemoteOptions{}
    37  	}
    38  	if opts.TargetsPath == "" {
    39  		opts.TargetsPath = "targets"
    40  	}
    41  	if client == nil {
    42  		client = http.DefaultClient
    43  	}
    44  	return &httpRemoteStore{baseURL, opts, client}, nil
    45  }
    46  
    47  type httpRemoteStore struct {
    48  	baseURL string
    49  	opts    *HTTPRemoteOptions
    50  	cli     *http.Client
    51  }
    52  
    53  func (h *httpRemoteStore) GetMeta(name string) (io.ReadCloser, int64, error) {
    54  	return h.get(path.Join(h.opts.MetadataPath, name))
    55  }
    56  
    57  func (h *httpRemoteStore) GetTarget(name string) (io.ReadCloser, int64, error) {
    58  	return h.get(path.Join(h.opts.TargetsPath, name))
    59  }
    60  
    61  func (h *httpRemoteStore) get(s string) (io.ReadCloser, int64, error) {
    62  	u := h.url(s)
    63  	req, err := http.NewRequest("GET", u, nil)
    64  	if err != nil {
    65  		return nil, 0, err
    66  	}
    67  	if h.opts.UserAgent != "" {
    68  		req.Header.Set("User-Agent", h.opts.UserAgent)
    69  	}
    70  	var res *http.Response
    71  	if r := h.opts.Retries; r != nil {
    72  		for start := time.Now(); time.Since(start) < r.Total; time.Sleep(r.Delay) {
    73  			res, err = h.cli.Do(req)
    74  			if err == nil && (res.StatusCode < 500 || res.StatusCode > 599) {
    75  				break
    76  			}
    77  		}
    78  	} else {
    79  		res, err = h.cli.Do(req)
    80  	}
    81  	if err != nil {
    82  		return nil, 0, err
    83  	}
    84  
    85  	if res.StatusCode == http.StatusNotFound {
    86  		res.Body.Close()
    87  		return nil, 0, ErrNotFound{s}
    88  	} else if res.StatusCode != http.StatusOK {
    89  		res.Body.Close()
    90  		return nil, 0, &url.Error{
    91  			Op:  "GET",
    92  			URL: u,
    93  			Err: fmt.Errorf("unexpected HTTP status %d", res.StatusCode),
    94  		}
    95  	}
    96  
    97  	size, err := strconv.ParseInt(res.Header.Get("Content-Length"), 10, 0)
    98  	if err != nil {
    99  		return res.Body, -1, nil
   100  	}
   101  	return res.Body, size, nil
   102  }
   103  
   104  func (h *httpRemoteStore) url(path string) string {
   105  	if !strings.HasPrefix(path, "/") {
   106  		path = "/" + path
   107  	}
   108  	return h.baseURL + path
   109  }
   110  

View as plain text