Add user agent header to all requests

Currently the user agent is only being used on the initial
resolve request, then switching to the default user agent.
This ensures the correct user agent is always used. There is
a larger fix in progress which does this is a cleaner way, but
the scope of this change is fixing the user agent issue.

Signed-off-by: Derek McGowan <derek@mcgstyle.net>
This commit is contained in:
Derek McGowan 2019-06-11 22:57:36 +08:00
parent 02ed02eca5
commit bb00872800
No known key found for this signature in database
GPG Key ID: F58C5D0A4405ACDB
2 changed files with 29 additions and 7 deletions

View File

@ -31,6 +31,7 @@ import (
"github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/log" "github.com/containerd/containerd/log"
"github.com/containerd/containerd/version"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"golang.org/x/net/context/ctxhttp" "golang.org/x/net/context/ctxhttp"
@ -40,6 +41,7 @@ type dockerAuthorizer struct {
credentials func(string) (string, string, error) credentials func(string) (string, string, error)
client *http.Client client *http.Client
ua string
mu sync.Mutex mu sync.Mutex
auth map[string]string auth map[string]string
@ -54,6 +56,7 @@ func NewAuthorizer(client *http.Client, f func(string) (string, string, error))
return &dockerAuthorizer{ return &dockerAuthorizer{
credentials: f, credentials: f,
client: client, client: client,
ua: "containerd/" + version.Version,
auth: map[string]string{}, auth: map[string]string{},
} }
} }
@ -194,11 +197,16 @@ func (a *dockerAuthorizer) fetchTokenWithOAuth(ctx context.Context, to tokenOpti
form.Set("password", to.secret) form.Set("password", to.secret)
} }
resp, err := ctxhttp.Post( req, err := http.NewRequest("POST", to.realm, strings.NewReader(form.Encode()))
ctx, a.client, to.realm, if err != nil {
"application/x-www-form-urlencoded; charset=utf-8", return "", err
strings.NewReader(form.Encode()), }
) req.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=utf-8")
if a.ua != "" {
req.Header.Set("User-Agent", a.ua)
}
resp, err := ctxhttp.Do(ctx, a.client, req)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -244,6 +252,10 @@ func (a *dockerAuthorizer) fetchToken(ctx context.Context, to tokenOptions) (str
return "", err return "", err
} }
if a.ua != "" {
req.Header.Set("User-Agent", a.ua)
}
reqParams := req.URL.Query() reqParams := req.URL.Query()
if to.service != "" { if to.service != "" {

View File

@ -111,6 +111,7 @@ type dockerResolver struct {
auth Authorizer auth Authorizer
host func(string) (string, error) host func(string) (string, error)
headers http.Header headers http.Header
uagent string
plainHTTP bool plainHTTP bool
client *http.Client client *http.Client
tracker StatusTracker tracker StatusTracker
@ -135,16 +136,22 @@ func NewResolver(options ResolverOptions) remotes.Resolver {
ocispec.MediaTypeImageManifest, ocispec.MediaTypeImageManifest,
ocispec.MediaTypeImageIndex, "*"}, ", ")) ocispec.MediaTypeImageIndex, "*"}, ", "))
} }
if _, ok := options.Headers["User-Agent"]; !ok { ua := options.Headers.Get("User-Agent")
options.Headers.Set("User-Agent", "containerd/"+version.Version) if ua != "" {
options.Headers.Del("User-Agent")
} else {
ua = "containerd/" + version.Version
} }
if options.Authorizer == nil { if options.Authorizer == nil {
options.Authorizer = NewAuthorizer(options.Client, options.Credentials) options.Authorizer = NewAuthorizer(options.Client, options.Credentials)
options.Authorizer.(*dockerAuthorizer).ua = ua
} }
return &dockerResolver{ return &dockerResolver{
auth: options.Authorizer, auth: options.Authorizer,
host: options.Host, host: options.Host,
headers: options.Headers, headers: options.Headers,
uagent: ua,
plainHTTP: options.PlainHTTP, plainHTTP: options.PlainHTTP,
client: options.Client, client: options.Client,
tracker: options.Tracker, tracker: options.Tracker,
@ -351,6 +358,7 @@ func (r *dockerResolver) Pusher(ctx context.Context, ref string) (remotes.Pusher
type dockerBase struct { type dockerBase struct {
refspec reference.Spec refspec reference.Spec
base url.URL base url.URL
uagent string
client *http.Client client *http.Client
auth Authorizer auth Authorizer
@ -382,6 +390,7 @@ func (r *dockerResolver) base(refspec reference.Spec) (*dockerBase, error) {
return &dockerBase{ return &dockerBase{
refspec: refspec, refspec: refspec,
base: base, base: base,
uagent: r.uagent,
client: r.client, client: r.client,
auth: r.auth, auth: r.auth,
}, nil }, nil
@ -407,6 +416,7 @@ func (r *dockerBase) authorize(ctx context.Context, req *http.Request) error {
func (r *dockerBase) doRequest(ctx context.Context, req *http.Request) (*http.Response, error) { func (r *dockerBase) doRequest(ctx context.Context, req *http.Request) (*http.Response, error) {
ctx = log.WithLogger(ctx, log.G(ctx).WithField("url", req.URL.String())) ctx = log.WithLogger(ctx, log.G(ctx).WithField("url", req.URL.String()))
log.G(ctx).WithField("request.headers", req.Header).WithField("request.method", req.Method).Debug("do request") log.G(ctx).WithField("request.headers", req.Header).WithField("request.method", req.Method).Debug("do request")
req.Header.Set("User-Agent", r.uagent)
if err := r.authorize(ctx, req); err != nil { if err := r.authorize(ctx, req); err != nil {
return nil, errors.Wrap(err, "failed to authorize") return nil, errors.Wrap(err, "failed to authorize")
} }