Parcourir la source

Refactor utils/http.go, fixes #11899

Signed-off-by: Antonio Murdaca <me@runcom.ninja>
Antonio Murdaca il y a 10 ans
Parent
commit
0995ab5946

+ 2 - 0
pkg/requestdecorator/README.md

@@ -0,0 +1,2 @@
+This package provides helper functions for decorating a request with user agent
+versions, auth, meta headers.

+ 172 - 0
pkg/requestdecorator/requestdecorator.go

@@ -0,0 +1,172 @@
+// Package requestdecorator provides helper functions to decorate a request with
+// user agent versions, auth, meta headers.
+package requestdecorator
+
+import (
+	"errors"
+	"io"
+	"net/http"
+	"strings"
+
+	"github.com/Sirupsen/logrus"
+)
+
+var (
+	ErrNilRequest = errors.New("request cannot be nil")
+)
+
+// UAVersionInfo is used to model UserAgent versions.
+type UAVersionInfo struct {
+	Name    string
+	Version string
+}
+
+func NewUAVersionInfo(name, version string) UAVersionInfo {
+	return UAVersionInfo{
+		Name:    name,
+		Version: version,
+	}
+}
+
+func (vi *UAVersionInfo) isValid() bool {
+	const stopChars = " \t\r\n/"
+	name := vi.Name
+	vers := vi.Version
+	if len(name) == 0 || strings.ContainsAny(name, stopChars) {
+		return false
+	}
+	if len(vers) == 0 || strings.ContainsAny(vers, stopChars) {
+		return false
+	}
+	return true
+}
+
+// Convert versions to a string and append the string to the string base.
+//
+// Each UAVersionInfo will be converted to a string in the format of
+// "product/version", where the "product" is get from the name field, while
+// version is get from the version field. Several pieces of verson information
+// will be concatinated and separated by space.
+func appendVersions(base string, versions ...UAVersionInfo) string {
+	if len(versions) == 0 {
+		return base
+	}
+
+	verstrs := make([]string, 0, 1+len(versions))
+	if len(base) > 0 {
+		verstrs = append(verstrs, base)
+	}
+
+	for _, v := range versions {
+		if !v.isValid() {
+			continue
+		}
+		verstrs = append(verstrs, v.Name+"/"+v.Version)
+	}
+	return strings.Join(verstrs, " ")
+}
+
+// Decorator is used to change an instance of
+// http.Request. It could be used to add more header fields,
+// change body, etc.
+type Decorator interface {
+	// ChangeRequest() changes the request accordingly.
+	// The changed request will be returned or err will be non-nil
+	// if an error occur.
+	ChangeRequest(req *http.Request) (newReq *http.Request, err error)
+}
+
+// UserAgentDecorator appends the product/version to the user agent field
+// of a request.
+type UserAgentDecorator struct {
+	Versions []UAVersionInfo
+}
+
+func (h *UserAgentDecorator) ChangeRequest(req *http.Request) (*http.Request, error) {
+	if req == nil {
+		return req, ErrNilRequest
+	}
+
+	userAgent := appendVersions(req.UserAgent(), h.Versions...)
+	if len(userAgent) > 0 {
+		req.Header.Set("User-Agent", userAgent)
+	}
+	return req, nil
+}
+
+type MetaHeadersDecorator struct {
+	Headers map[string][]string
+}
+
+func (h *MetaHeadersDecorator) ChangeRequest(req *http.Request) (*http.Request, error) {
+	if h.Headers == nil {
+		return req, ErrNilRequest
+	}
+	for k, v := range h.Headers {
+		req.Header[k] = v
+	}
+	return req, nil
+}
+
+type AuthDecorator struct {
+	login    string
+	password string
+}
+
+func NewAuthDecorator(login, password string) Decorator {
+	return &AuthDecorator{
+		login:    login,
+		password: password,
+	}
+}
+
+func (self *AuthDecorator) ChangeRequest(req *http.Request) (*http.Request, error) {
+	if req == nil {
+		return req, ErrNilRequest
+	}
+	req.SetBasicAuth(self.login, self.password)
+	return req, nil
+}
+
+// RequestFactory creates an HTTP request
+// and applies a list of decorators on the request.
+type RequestFactory struct {
+	decorators []Decorator
+}
+
+func NewRequestFactory(d ...Decorator) *RequestFactory {
+	return &RequestFactory{
+		decorators: d,
+	}
+}
+
+func (f *RequestFactory) AddDecorator(d ...Decorator) {
+	f.decorators = append(f.decorators, d...)
+}
+
+func (f *RequestFactory) GetDecorators() []Decorator {
+	return f.decorators
+}
+
+// NewRequest() creates a new *http.Request,
+// applies all decorators in the Factory on the request,
+// then applies decorators provided by d on the request.
+func (h *RequestFactory) NewRequest(method, urlStr string, body io.Reader, d ...Decorator) (*http.Request, error) {
+	req, err := http.NewRequest(method, urlStr, body)
+	if err != nil {
+		return nil, err
+	}
+
+	// By default, a nil factory should work.
+	if h == nil {
+		return req, nil
+	}
+	for _, dec := range h.decorators {
+		req, _ = dec.ChangeRequest(req)
+	}
+	for _, dec := range d {
+		req, _ = dec.ChangeRequest(req)
+	}
+	logrus.Debugf("%v -- HEADERS: %v", req.URL, req.Header)
+	return req, err
+}

+ 222 - 0
pkg/requestdecorator/requestdecorator_test.go

@@ -0,0 +1,222 @@
+package requestdecorator
+
+import (
+	"net/http"
+	"strings"
+	"testing"
+)
+
+func TestUAVersionInfo(t *testing.T) {
+	uavi := NewUAVersionInfo("foo", "bar")
+	if !uavi.isValid() {
+		t.Fatalf("UAVersionInfo should be valid")
+	}
+	uavi = NewUAVersionInfo("", "bar")
+	if uavi.isValid() {
+		t.Fatalf("Expected UAVersionInfo to be invalid")
+	}
+	uavi = NewUAVersionInfo("foo", "")
+	if uavi.isValid() {
+		t.Fatalf("Expected UAVersionInfo to be invalid")
+	}
+}
+
+func TestUserAgentDecorator(t *testing.T) {
+	httpVersion := make([]UAVersionInfo, 2)
+	httpVersion = append(httpVersion, NewUAVersionInfo("testname", "testversion"))
+	httpVersion = append(httpVersion, NewUAVersionInfo("name", "version"))
+	uad := &UserAgentDecorator{
+		Versions: httpVersion,
+	}
+
+	req, err := http.NewRequest("GET", "/something", strings.NewReader("test"))
+	if err != nil {
+		t.Fatal(err)
+	}
+	reqDecorated, err := uad.ChangeRequest(req)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if reqDecorated.Header.Get("User-Agent") != "testname/testversion name/version" {
+		t.Fatalf("Request should have User-Agent 'testname/testversion name/version'")
+	}
+}
+
+func TestUserAgentDecoratorErr(t *testing.T) {
+	httpVersion := make([]UAVersionInfo, 0)
+	uad := &UserAgentDecorator{
+		Versions: httpVersion,
+	}
+
+	var req *http.Request
+	_, err := uad.ChangeRequest(req)
+	if err == nil {
+		t.Fatalf("Expected to get ErrNilRequest instead no error was returned")
+	}
+}
+
+func TestMetaHeadersDecorator(t *testing.T) {
+	var headers = map[string][]string{
+		"key1": {"value1"},
+		"key2": {"value2"},
+	}
+	mhd := &MetaHeadersDecorator{
+		Headers: headers,
+	}
+
+	req, err := http.NewRequest("GET", "/something", strings.NewReader("test"))
+	if err != nil {
+		t.Fatal(err)
+	}
+	reqDecorated, err := mhd.ChangeRequest(req)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	v, ok := reqDecorated.Header["key1"]
+	if !ok {
+		t.Fatalf("Expected to have header key1")
+	}
+	if v[0] != "value1" {
+		t.Fatalf("Expected value for key1 isn't value1")
+	}
+
+	v, ok = reqDecorated.Header["key2"]
+	if !ok {
+		t.Fatalf("Expected to have header key2")
+	}
+	if v[0] != "value2" {
+		t.Fatalf("Expected value for key2 isn't value2")
+	}
+}
+
+func TestMetaHeadersDecoratorErr(t *testing.T) {
+	mhd := &MetaHeadersDecorator{}
+
+	var req *http.Request
+	_, err := mhd.ChangeRequest(req)
+	if err == nil {
+		t.Fatalf("Expected to get ErrNilRequest instead no error was returned")
+	}
+}
+
+func TestAuthDecorator(t *testing.T) {
+	ad := NewAuthDecorator("test", "password")
+
+	req, err := http.NewRequest("GET", "/something", strings.NewReader("test"))
+	if err != nil {
+		t.Fatal(err)
+	}
+	reqDecorated, err := ad.ChangeRequest(req)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	username, password, ok := reqDecorated.BasicAuth()
+	if !ok {
+		t.Fatalf("Cannot retrieve basic auth info from request")
+	}
+	if username != "test" {
+		t.Fatalf("Expected username to be test, got %s", username)
+	}
+	if password != "password" {
+		t.Fatalf("Expected password to be password, got %s", password)
+	}
+}
+
+func TestAuthDecoratorErr(t *testing.T) {
+	ad := &AuthDecorator{}
+
+	var req *http.Request
+	_, err := ad.ChangeRequest(req)
+	if err == nil {
+		t.Fatalf("Expected to get ErrNilRequest instead no error was returned")
+	}
+}
+
+func TestRequestFactory(t *testing.T) {
+	ad := NewAuthDecorator("test", "password")
+	httpVersion := make([]UAVersionInfo, 2)
+	httpVersion = append(httpVersion, NewUAVersionInfo("testname", "testversion"))
+	httpVersion = append(httpVersion, NewUAVersionInfo("name", "version"))
+	uad := &UserAgentDecorator{
+		Versions: httpVersion,
+	}
+
+	requestFactory := NewRequestFactory(ad, uad)
+
+	if dlen := requestFactory.GetDecorators(); len(dlen) != 2 {
+		t.Fatalf("Expected to have two decorators, got %d", dlen)
+	}
+
+	req, err := requestFactory.NewRequest("GET", "/test", strings.NewReader("test"))
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	username, password, ok := req.BasicAuth()
+	if !ok {
+		t.Fatalf("Cannot retrieve basic auth info from request")
+	}
+	if username != "test" {
+		t.Fatalf("Expected username to be test, got %s", username)
+	}
+	if password != "password" {
+		t.Fatalf("Expected password to be password, got %s", password)
+	}
+	if req.Header.Get("User-Agent") != "testname/testversion name/version" {
+		t.Fatalf("Request should have User-Agent 'testname/testversion name/version'")
+	}
+}
+
+func TestRequestFactoryNewRequestWithDecorators(t *testing.T) {
+	ad := NewAuthDecorator("test", "password")
+
+	requestFactory := NewRequestFactory(ad)
+
+	if dlen := requestFactory.GetDecorators(); len(dlen) != 1 {
+		t.Fatalf("Expected to have one decorators, got %d", dlen)
+	}
+
+	ad2 := NewAuthDecorator("test2", "password2")
+
+	req, err := requestFactory.NewRequest("GET", "/test", strings.NewReader("test"), ad2)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	username, password, ok := req.BasicAuth()
+	if !ok {
+		t.Fatalf("Cannot retrieve basic auth info from request")
+	}
+	if username != "test2" {
+		t.Fatalf("Expected username to be test, got %s", username)
+	}
+	if password != "password2" {
+		t.Fatalf("Expected password to be password, got %s", password)
+	}
+}
+
+func TestRequestFactoryAddDecorator(t *testing.T) {
+	requestFactory := NewRequestFactory()
+
+	if dlen := requestFactory.GetDecorators(); len(dlen) != 0 {
+		t.Fatalf("Expected to have zero decorators, got %d", dlen)
+	}
+
+	ad := NewAuthDecorator("test", "password")
+	requestFactory.AddDecorator(ad)
+
+	if dlen := requestFactory.GetDecorators(); len(dlen) != 1 {
+		t.Fatalf("Expected to have one decorators, got %d", dlen)
+	}
+}
+
+func TestRequestFactoryNil(t *testing.T) {
+	var requestFactory RequestFactory
+	_, err := requestFactory.NewRequest("GET", "/test", strings.NewReader("test"))
+	if err != nil {
+		t.Fatalf("Expected not to get and error, got %s", err)
+	}
+}

+ 6 - 6
registry/auth.go

@@ -14,7 +14,7 @@ import (
 	"time"
 	"time"
 
 
 	"github.com/Sirupsen/logrus"
 	"github.com/Sirupsen/logrus"
-	"github.com/docker/docker/utils"
+	"github.com/docker/docker/pkg/requestdecorator"
 )
 )
 
 
 const (
 const (
@@ -225,7 +225,7 @@ func SaveConfig(configFile *ConfigFile) error {
 }
 }
 
 
 // Login tries to register/login to the registry server.
 // Login tries to register/login to the registry server.
-func Login(authConfig *AuthConfig, registryEndpoint *Endpoint, factory *utils.HTTPRequestFactory) (string, error) {
+func Login(authConfig *AuthConfig, registryEndpoint *Endpoint, factory *requestdecorator.RequestFactory) (string, error) {
 	// Separates the v2 registry login logic from the v1 logic.
 	// Separates the v2 registry login logic from the v1 logic.
 	if registryEndpoint.Version == APIVersion2 {
 	if registryEndpoint.Version == APIVersion2 {
 		return loginV2(authConfig, registryEndpoint, factory)
 		return loginV2(authConfig, registryEndpoint, factory)
@@ -235,7 +235,7 @@ func Login(authConfig *AuthConfig, registryEndpoint *Endpoint, factory *utils.HT
 }
 }
 
 
 // loginV1 tries to register/login to the v1 registry server.
 // loginV1 tries to register/login to the v1 registry server.
-func loginV1(authConfig *AuthConfig, registryEndpoint *Endpoint, factory *utils.HTTPRequestFactory) (string, error) {
+func loginV1(authConfig *AuthConfig, registryEndpoint *Endpoint, factory *requestdecorator.RequestFactory) (string, error) {
 	var (
 	var (
 		status        string
 		status        string
 		reqBody       []byte
 		reqBody       []byte
@@ -348,7 +348,7 @@ func loginV1(authConfig *AuthConfig, registryEndpoint *Endpoint, factory *utils.
 // now, users should create their account through other means like directly from a web page
 // now, users should create their account through other means like directly from a web page
 // served by the v2 registry service provider. Whether this will be supported in the future
 // served by the v2 registry service provider. Whether this will be supported in the future
 // is to be determined.
 // is to be determined.
-func loginV2(authConfig *AuthConfig, registryEndpoint *Endpoint, factory *utils.HTTPRequestFactory) (string, error) {
+func loginV2(authConfig *AuthConfig, registryEndpoint *Endpoint, factory *requestdecorator.RequestFactory) (string, error) {
 	logrus.Debugf("attempting v2 login to registry endpoint %s", registryEndpoint)
 	logrus.Debugf("attempting v2 login to registry endpoint %s", registryEndpoint)
 	var (
 	var (
 		err       error
 		err       error
@@ -381,7 +381,7 @@ func loginV2(authConfig *AuthConfig, registryEndpoint *Endpoint, factory *utils.
 	return "", fmt.Errorf("no successful auth challenge for %s - errors: %s", registryEndpoint, allErrors)
 	return "", fmt.Errorf("no successful auth challenge for %s - errors: %s", registryEndpoint, allErrors)
 }
 }
 
 
-func tryV2BasicAuthLogin(authConfig *AuthConfig, params map[string]string, registryEndpoint *Endpoint, client *http.Client, factory *utils.HTTPRequestFactory) error {
+func tryV2BasicAuthLogin(authConfig *AuthConfig, params map[string]string, registryEndpoint *Endpoint, client *http.Client, factory *requestdecorator.RequestFactory) error {
 	req, err := factory.NewRequest("GET", registryEndpoint.Path(""), nil)
 	req, err := factory.NewRequest("GET", registryEndpoint.Path(""), nil)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
@@ -402,7 +402,7 @@ func tryV2BasicAuthLogin(authConfig *AuthConfig, params map[string]string, regis
 	return nil
 	return nil
 }
 }
 
 
-func tryV2TokenAuthLogin(authConfig *AuthConfig, params map[string]string, registryEndpoint *Endpoint, client *http.Client, factory *utils.HTTPRequestFactory) error {
+func tryV2TokenAuthLogin(authConfig *AuthConfig, params map[string]string, registryEndpoint *Endpoint, client *http.Client, factory *requestdecorator.RequestFactory) error {
 	token, err := getToken(authConfig.Username, authConfig.Password, params, registryEndpoint, client, factory)
 	token, err := getToken(authConfig.Username, authConfig.Password, params, registryEndpoint, client, factory)
 	if err != nil {
 	if err != nil {
 		return err
 		return err

+ 3 - 3
registry/endpoint.go

@@ -11,8 +11,8 @@ import (
 	"strings"
 	"strings"
 
 
 	"github.com/Sirupsen/logrus"
 	"github.com/Sirupsen/logrus"
+	"github.com/docker/docker/pkg/requestdecorator"
 	"github.com/docker/docker/registry/v2"
 	"github.com/docker/docker/registry/v2"
-	"github.com/docker/docker/utils"
 )
 )
 
 
 // for mocking in unit tests
 // for mocking in unit tests
@@ -162,7 +162,7 @@ func (e *Endpoint) Ping() (RegistryInfo, error) {
 	return RegistryInfo{}, fmt.Errorf("unable to ping registry endpoint %s\nv2 ping attempt failed with error: %s\n v1 ping attempt failed with error: %s", e, errV2, errV1)
 	return RegistryInfo{}, fmt.Errorf("unable to ping registry endpoint %s\nv2 ping attempt failed with error: %s\n v1 ping attempt failed with error: %s", e, errV2, errV1)
 }
 }
 
 
-func (e *Endpoint) pingV1(factory *utils.HTTPRequestFactory) (RegistryInfo, error) {
+func (e *Endpoint) pingV1(factory *requestdecorator.RequestFactory) (RegistryInfo, error) {
 	logrus.Debugf("attempting v1 ping for registry endpoint %s", e)
 	logrus.Debugf("attempting v1 ping for registry endpoint %s", e)
 
 
 	if e.String() == IndexServerAddress() {
 	if e.String() == IndexServerAddress() {
@@ -216,7 +216,7 @@ func (e *Endpoint) pingV1(factory *utils.HTTPRequestFactory) (RegistryInfo, erro
 	return info, nil
 	return info, nil
 }
 }
 
 
-func (e *Endpoint) pingV2(factory *utils.HTTPRequestFactory) (RegistryInfo, error) {
+func (e *Endpoint) pingV2(factory *requestdecorator.RequestFactory) (RegistryInfo, error) {
 	logrus.Debugf("attempting v2 ping for registry endpoint %s", e)
 	logrus.Debugf("attempting v2 ping for registry endpoint %s", e)
 
 
 	req, err := factory.NewRequest("GET", e.Path(""), nil)
 	req, err := factory.NewRequest("GET", e.Path(""), nil)

+ 14 - 30
registry/httpfactory.go

@@ -5,42 +5,26 @@ import (
 
 
 	"github.com/docker/docker/autogen/dockerversion"
 	"github.com/docker/docker/autogen/dockerversion"
 	"github.com/docker/docker/pkg/parsers/kernel"
 	"github.com/docker/docker/pkg/parsers/kernel"
-	"github.com/docker/docker/utils"
+	"github.com/docker/docker/pkg/requestdecorator"
 )
 )
 
 
-func HTTPRequestFactory(metaHeaders map[string][]string) *utils.HTTPRequestFactory {
+func HTTPRequestFactory(metaHeaders map[string][]string) *requestdecorator.RequestFactory {
 	// FIXME: this replicates the 'info' job.
 	// FIXME: this replicates the 'info' job.
-	httpVersion := make([]utils.VersionInfo, 0, 4)
-	httpVersion = append(httpVersion, &simpleVersionInfo{"docker", dockerversion.VERSION})
-	httpVersion = append(httpVersion, &simpleVersionInfo{"go", runtime.Version()})
-	httpVersion = append(httpVersion, &simpleVersionInfo{"git-commit", dockerversion.GITCOMMIT})
+	httpVersion := make([]requestdecorator.UAVersionInfo, 0, 4)
+	httpVersion = append(httpVersion, requestdecorator.NewUAVersionInfo("docker", dockerversion.VERSION))
+	httpVersion = append(httpVersion, requestdecorator.NewUAVersionInfo("go", runtime.Version()))
+	httpVersion = append(httpVersion, requestdecorator.NewUAVersionInfo("git-commit", dockerversion.GITCOMMIT))
 	if kernelVersion, err := kernel.GetKernelVersion(); err == nil {
 	if kernelVersion, err := kernel.GetKernelVersion(); err == nil {
-		httpVersion = append(httpVersion, &simpleVersionInfo{"kernel", kernelVersion.String()})
+		httpVersion = append(httpVersion, requestdecorator.NewUAVersionInfo("kernel", kernelVersion.String()))
 	}
 	}
-	httpVersion = append(httpVersion, &simpleVersionInfo{"os", runtime.GOOS})
-	httpVersion = append(httpVersion, &simpleVersionInfo{"arch", runtime.GOARCH})
-	ud := utils.NewHTTPUserAgentDecorator(httpVersion...)
-	md := &utils.HTTPMetaHeadersDecorator{
+	httpVersion = append(httpVersion, requestdecorator.NewUAVersionInfo("os", runtime.GOOS))
+	httpVersion = append(httpVersion, requestdecorator.NewUAVersionInfo("arch", runtime.GOARCH))
+	uad := &requestdecorator.UserAgentDecorator{
+		Versions: httpVersion,
+	}
+	mhd := &requestdecorator.MetaHeadersDecorator{
 		Headers: metaHeaders,
 		Headers: metaHeaders,
 	}
 	}
-	factory := utils.NewHTTPRequestFactory(ud, md)
+	factory := requestdecorator.NewRequestFactory(uad, mhd)
 	return factory
 	return factory
 }
 }
-
-// simpleVersionInfo is a simple implementation of
-// the interface VersionInfo, which is used
-// to provide version information for some product,
-// component, etc. It stores the product name and the version
-// in string and returns them on calls to Name() and Version().
-type simpleVersionInfo struct {
-	name    string
-	version string
-}
-
-func (v *simpleVersionInfo) Name() string {
-	return v.name
-}
-
-func (v *simpleVersionInfo) Version() string {
-	return v.version
-}

+ 3 - 3
registry/registry_test.go

@@ -7,7 +7,7 @@ import (
 	"strings"
 	"strings"
 	"testing"
 	"testing"
 
 
-	"github.com/docker/docker/utils"
+	"github.com/docker/docker/pkg/requestdecorator"
 )
 )
 
 
 var (
 var (
@@ -25,7 +25,7 @@ func spawnTestRegistrySession(t *testing.T) *Session {
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
-	r, err := NewSession(authConfig, utils.NewHTTPRequestFactory(), endpoint, true)
+	r, err := NewSession(authConfig, requestdecorator.NewRequestFactory(), endpoint, true)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -40,7 +40,7 @@ func TestPublicSession(t *testing.T) {
 		if err != nil {
 		if err != nil {
 			t.Fatal(err)
 			t.Fatal(err)
 		}
 		}
-		r, err := NewSession(authConfig, utils.NewHTTPRequestFactory(), endpoint, true)
+		r, err := NewSession(authConfig, requestdecorator.NewRequestFactory(), endpoint, true)
 		if err != nil {
 		if err != nil {
 			t.Fatal(err)
 			t.Fatal(err)
 		}
 		}

+ 4 - 3
registry/session.go

@@ -19,19 +19,20 @@ import (
 
 
 	"github.com/Sirupsen/logrus"
 	"github.com/Sirupsen/logrus"
 	"github.com/docker/docker/pkg/httputils"
 	"github.com/docker/docker/pkg/httputils"
+	"github.com/docker/docker/pkg/requestdecorator"
 	"github.com/docker/docker/pkg/tarsum"
 	"github.com/docker/docker/pkg/tarsum"
 	"github.com/docker/docker/utils"
 	"github.com/docker/docker/utils"
 )
 )
 
 
 type Session struct {
 type Session struct {
 	authConfig    *AuthConfig
 	authConfig    *AuthConfig
-	reqFactory    *utils.HTTPRequestFactory
+	reqFactory    *requestdecorator.RequestFactory
 	indexEndpoint *Endpoint
 	indexEndpoint *Endpoint
 	jar           *cookiejar.Jar
 	jar           *cookiejar.Jar
 	timeout       TimeoutType
 	timeout       TimeoutType
 }
 }
 
 
-func NewSession(authConfig *AuthConfig, factory *utils.HTTPRequestFactory, endpoint *Endpoint, timeout bool) (r *Session, err error) {
+func NewSession(authConfig *AuthConfig, factory *requestdecorator.RequestFactory, endpoint *Endpoint, timeout bool) (r *Session, err error) {
 	r = &Session{
 	r = &Session{
 		authConfig:    authConfig,
 		authConfig:    authConfig,
 		indexEndpoint: endpoint,
 		indexEndpoint: endpoint,
@@ -55,7 +56,7 @@ func NewSession(authConfig *AuthConfig, factory *utils.HTTPRequestFactory, endpo
 		}
 		}
 		if info.Standalone {
 		if info.Standalone {
 			logrus.Debugf("Endpoint %s is eligible for private registry. Enabling decorator.", r.indexEndpoint.String())
 			logrus.Debugf("Endpoint %s is eligible for private registry. Enabling decorator.", r.indexEndpoint.String())
-			dec := utils.NewHTTPAuthDecorator(authConfig.Username, authConfig.Password)
+			dec := requestdecorator.NewAuthDecorator(authConfig.Username, authConfig.Password)
 			factory.AddDecorator(dec)
 			factory.AddDecorator(dec)
 		}
 		}
 	}
 	}

+ 2 - 2
registry/token.go

@@ -8,14 +8,14 @@ import (
 	"net/url"
 	"net/url"
 	"strings"
 	"strings"
 
 
-	"github.com/docker/docker/utils"
+	"github.com/docker/docker/pkg/requestdecorator"
 )
 )
 
 
 type tokenResponse struct {
 type tokenResponse struct {
 	Token string `json:"token"`
 	Token string `json:"token"`
 }
 }
 
 
-func getToken(username, password string, params map[string]string, registryEndpoint *Endpoint, client *http.Client, factory *utils.HTTPRequestFactory) (token string, err error) {
+func getToken(username, password string, params map[string]string, registryEndpoint *Endpoint, client *http.Client, factory *requestdecorator.RequestFactory) (token string, err error) {
 	realm, ok := params["realm"]
 	realm, ok := params["realm"]
 	if !ok {
 	if !ok {
 		return "", errors.New("no realm specified for token auth challenge")
 		return "", errors.New("no realm specified for token auth challenge")

+ 0 - 168
utils/http.go

@@ -1,168 +0,0 @@
-package utils
-
-import (
-	"io"
-	"net/http"
-	"strings"
-
-	"github.com/Sirupsen/logrus"
-)
-
-// VersionInfo is used to model entities which has a version.
-// It is basically a tupple with name and version.
-type VersionInfo interface {
-	Name() string
-	Version() string
-}
-
-func validVersion(version VersionInfo) bool {
-	const stopChars = " \t\r\n/"
-	name := version.Name()
-	vers := version.Version()
-	if len(name) == 0 || strings.ContainsAny(name, stopChars) {
-		return false
-	}
-	if len(vers) == 0 || strings.ContainsAny(vers, stopChars) {
-		return false
-	}
-	return true
-}
-
-// Convert versions to a string and append the string to the string base.
-//
-// Each VersionInfo will be converted to a string in the format of
-// "product/version", where the "product" is get from the Name() method, while
-// version is get from the Version() method. Several pieces of verson information
-// will be concatinated and separated by space.
-func appendVersions(base string, versions ...VersionInfo) string {
-	if len(versions) == 0 {
-		return base
-	}
-
-	verstrs := make([]string, 0, 1+len(versions))
-	if len(base) > 0 {
-		verstrs = append(verstrs, base)
-	}
-
-	for _, v := range versions {
-		if !validVersion(v) {
-			continue
-		}
-		verstrs = append(verstrs, v.Name()+"/"+v.Version())
-	}
-	return strings.Join(verstrs, " ")
-}
-
-// HTTPRequestDecorator is used to change an instance of
-// http.Request. It could be used to add more header fields,
-// change body, etc.
-type HTTPRequestDecorator interface {
-	// ChangeRequest() changes the request accordingly.
-	// The changed request will be returned or err will be non-nil
-	// if an error occur.
-	ChangeRequest(req *http.Request) (newReq *http.Request, err error)
-}
-
-// HTTPUserAgentDecorator appends the product/version to the user agent field
-// of a request.
-type HTTPUserAgentDecorator struct {
-	versions []VersionInfo
-}
-
-func NewHTTPUserAgentDecorator(versions ...VersionInfo) HTTPRequestDecorator {
-	return &HTTPUserAgentDecorator{
-		versions: versions,
-	}
-}
-
-func (h *HTTPUserAgentDecorator) ChangeRequest(req *http.Request) (newReq *http.Request, err error) {
-	if req == nil {
-		return req, nil
-	}
-
-	userAgent := appendVersions(req.UserAgent(), h.versions...)
-	if len(userAgent) > 0 {
-		req.Header.Set("User-Agent", userAgent)
-	}
-	return req, nil
-}
-
-type HTTPMetaHeadersDecorator struct {
-	Headers map[string][]string
-}
-
-func (h *HTTPMetaHeadersDecorator) ChangeRequest(req *http.Request) (newReq *http.Request, err error) {
-	if h.Headers == nil {
-		return req, nil
-	}
-	for k, v := range h.Headers {
-		req.Header[k] = v
-	}
-	return req, nil
-}
-
-type HTTPAuthDecorator struct {
-	login    string
-	password string
-}
-
-func NewHTTPAuthDecorator(login, password string) HTTPRequestDecorator {
-	return &HTTPAuthDecorator{
-		login:    login,
-		password: password,
-	}
-}
-
-func (self *HTTPAuthDecorator) ChangeRequest(req *http.Request) (*http.Request, error) {
-	req.SetBasicAuth(self.login, self.password)
-	return req, nil
-}
-
-// HTTPRequestFactory creates an HTTP request
-// and applies a list of decorators on the request.
-type HTTPRequestFactory struct {
-	decorators []HTTPRequestDecorator
-}
-
-func NewHTTPRequestFactory(d ...HTTPRequestDecorator) *HTTPRequestFactory {
-	return &HTTPRequestFactory{
-		decorators: d,
-	}
-}
-
-func (self *HTTPRequestFactory) AddDecorator(d ...HTTPRequestDecorator) {
-	self.decorators = append(self.decorators, d...)
-}
-
-func (self *HTTPRequestFactory) GetDecorators() []HTTPRequestDecorator {
-	return self.decorators
-}
-
-// NewRequest() creates a new *http.Request,
-// applies all decorators in the HTTPRequestFactory on the request,
-// then applies decorators provided by d on the request.
-func (h *HTTPRequestFactory) NewRequest(method, urlStr string, body io.Reader, d ...HTTPRequestDecorator) (*http.Request, error) {
-	req, err := http.NewRequest(method, urlStr, body)
-	if err != nil {
-		return nil, err
-	}
-
-	// By default, a nil factory should work.
-	if h == nil {
-		return req, nil
-	}
-	for _, dec := range h.decorators {
-		req, err = dec.ChangeRequest(req)
-		if err != nil {
-			return nil, err
-		}
-	}
-	for _, dec := range d {
-		req, err = dec.ChangeRequest(req)
-		if err != nil {
-			return nil, err
-		}
-	}
-	logrus.Debugf("%v -- HEADERS: %v", req.URL, req.Header)
-	return req, err
-}