Add WithIfModifiedSince to enable use of caching

The HTTP Getter can leverage the use of RFC7234 4.3.2 by setting the
HTTP Header 'If-Modified-Since'. This will enable callers to avoid
downloading index files when they haven't been modified since the
last get operation.

Signed-off-by: Paulo Gomes <pjbgf@linux.com>
pull/10916/head
Paulo Gomes 3 years ago
parent c477d697ec
commit 8a74d255eb
No known key found for this signature in database
GPG Key ID: 9995233870E99BEE

@ -45,6 +45,7 @@ type options struct {
registryClient *registry.Client
timeout time.Duration
transport *http.Transport
ifModifiedSince *time.Time
}
// Option allows specifying various settings configurable by the user for overriding the defaults
@ -121,6 +122,20 @@ func WithUntar() Option {
}
}
// WithIfModifiedSince leverages the HTTP caching mechanism
// defined on RFC7234 4.3.2. It prevents the HTTP getter from
// downloading index that haven't been modified based on `since`.
// If the file was not modified, getter will return a
// `304 Not Modified`, as per RFC.
//
// The caller is responsible for caching previously downloaded
// index files and handling the returning error.
func WithIfModifiedSince(since time.Time) Option {
return func(opts *options) {
opts.ifModifiedSince = &since
}
}
// WithTransport sets the http.Transport to allow overwriting the HTTPGetter default.
func WithTransport(transport *http.Transport) Option {
return func(opts *options) {

@ -22,6 +22,7 @@ import (
"net/http"
"net/url"
"sync"
"time"
"github.com/pkg/errors"
@ -58,6 +59,10 @@ func (g *HTTPGetter) get(href string) (*bytes.Buffer, error) {
req.Header.Set("User-Agent", g.opts.userAgent)
}
if g.opts.ifModifiedSince != nil {
req.Header.Set("If-Modified-Since", g.opts.ifModifiedSince.Format(time.RFC1123))
}
// Before setting the basic auth credentials, make sure the URL associated
// with the basic auth is the one being fetched.
u1, err := url.Parse(g.opts.url)

@ -530,3 +530,62 @@ func TestHTTPTransportOption(t *testing.T) {
t.Fatal("transport.TLSClientConfig should not be set")
}
}
func TestHTTPIfModifiedSinceOption(t *testing.T) {
sinceNow := time.Now()
sinceNowExpected := sinceNow.Format(time.RFC1123)
tests := []struct {
name string
since *time.Time
sinceExpected string
}{
{
name: "If-Modified-Since option set",
since: &sinceNow,
sinceExpected: sinceNowExpected,
},
{
name: "If-Modified-Since option not set",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var g Getter
var err error
if tt.since == nil {
g, err = NewHTTPGetter()
} else {
g, err = NewHTTPGetter(
WithIfModifiedSince(*tt.since),
)
}
if err != nil {
t.Fatal(err)
}
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
gotSince, found := r.Header["If-Modified-Since"]
if tt.since != nil && !found {
t.Errorf("Header If-Modified-Since was expected but was not set")
}
if tt.since != nil && gotSince[0] != tt.sinceExpected {
t.Errorf("Expected '%s', got '%s'", tt.sinceExpected, gotSince)
}
if tt.since == nil && found {
t.Errorf("Header If-Modified-Since was not expected but was set")
}
}))
defer srv.Close()
_, err = g.Get(srv.URL, WithURL(srv.URL))
if err != nil {
t.Fatal(err)
}
})
}
}

Loading…
Cancel
Save