Browse code

Refactor utils/http.go, fixes #11899

Signed-off-by: Antonio Murdaca <me@runcom.ninja>

Antonio Murdaca authored on 2015/03/29 22:51:08
Showing 10 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,2 @@
0
+This package provides helper functions for decorating a request with user agent
1
+versions, auth, meta headers.
0 2
new file mode 100644
... ...
@@ -0,0 +1,172 @@
0
+// Package requestdecorator provides helper functions to decorate a request with
1
+// user agent versions, auth, meta headers.
2
+package requestdecorator
3
+
4
+import (
5
+	"errors"
6
+	"io"
7
+	"net/http"
8
+	"strings"
9
+
10
+	"github.com/Sirupsen/logrus"
11
+)
12
+
13
+var (
14
+	ErrNilRequest = errors.New("request cannot be nil")
15
+)
16
+
17
+// UAVersionInfo is used to model UserAgent versions.
18
+type UAVersionInfo struct {
19
+	Name    string
20
+	Version string
21
+}
22
+
23
+func NewUAVersionInfo(name, version string) UAVersionInfo {
24
+	return UAVersionInfo{
25
+		Name:    name,
26
+		Version: version,
27
+	}
28
+}
29
+
30
+func (vi *UAVersionInfo) isValid() bool {
31
+	const stopChars = " \t\r\n/"
32
+	name := vi.Name
33
+	vers := vi.Version
34
+	if len(name) == 0 || strings.ContainsAny(name, stopChars) {
35
+		return false
36
+	}
37
+	if len(vers) == 0 || strings.ContainsAny(vers, stopChars) {
38
+		return false
39
+	}
40
+	return true
41
+}
42
+
43
+// Convert versions to a string and append the string to the string base.
44
+//
45
+// Each UAVersionInfo will be converted to a string in the format of
46
+// "product/version", where the "product" is get from the name field, while
47
+// version is get from the version field. Several pieces of verson information
48
+// will be concatinated and separated by space.
49
+func appendVersions(base string, versions ...UAVersionInfo) string {
50
+	if len(versions) == 0 {
51
+		return base
52
+	}
53
+
54
+	verstrs := make([]string, 0, 1+len(versions))
55
+	if len(base) > 0 {
56
+		verstrs = append(verstrs, base)
57
+	}
58
+
59
+	for _, v := range versions {
60
+		if !v.isValid() {
61
+			continue
62
+		}
63
+		verstrs = append(verstrs, v.Name+"/"+v.Version)
64
+	}
65
+	return strings.Join(verstrs, " ")
66
+}
67
+
68
+// Decorator is used to change an instance of
69
+// http.Request. It could be used to add more header fields,
70
+// change body, etc.
71
+type Decorator interface {
72
+	// ChangeRequest() changes the request accordingly.
73
+	// The changed request will be returned or err will be non-nil
74
+	// if an error occur.
75
+	ChangeRequest(req *http.Request) (newReq *http.Request, err error)
76
+}
77
+
78
+// UserAgentDecorator appends the product/version to the user agent field
79
+// of a request.
80
+type UserAgentDecorator struct {
81
+	Versions []UAVersionInfo
82
+}
83
+
84
+func (h *UserAgentDecorator) ChangeRequest(req *http.Request) (*http.Request, error) {
85
+	if req == nil {
86
+		return req, ErrNilRequest
87
+	}
88
+
89
+	userAgent := appendVersions(req.UserAgent(), h.Versions...)
90
+	if len(userAgent) > 0 {
91
+		req.Header.Set("User-Agent", userAgent)
92
+	}
93
+	return req, nil
94
+}
95
+
96
+type MetaHeadersDecorator struct {
97
+	Headers map[string][]string
98
+}
99
+
100
+func (h *MetaHeadersDecorator) ChangeRequest(req *http.Request) (*http.Request, error) {
101
+	if h.Headers == nil {
102
+		return req, ErrNilRequest
103
+	}
104
+	for k, v := range h.Headers {
105
+		req.Header[k] = v
106
+	}
107
+	return req, nil
108
+}
109
+
110
+type AuthDecorator struct {
111
+	login    string
112
+	password string
113
+}
114
+
115
+func NewAuthDecorator(login, password string) Decorator {
116
+	return &AuthDecorator{
117
+		login:    login,
118
+		password: password,
119
+	}
120
+}
121
+
122
+func (self *AuthDecorator) ChangeRequest(req *http.Request) (*http.Request, error) {
123
+	if req == nil {
124
+		return req, ErrNilRequest
125
+	}
126
+	req.SetBasicAuth(self.login, self.password)
127
+	return req, nil
128
+}
129
+
130
+// RequestFactory creates an HTTP request
131
+// and applies a list of decorators on the request.
132
+type RequestFactory struct {
133
+	decorators []Decorator
134
+}
135
+
136
+func NewRequestFactory(d ...Decorator) *RequestFactory {
137
+	return &RequestFactory{
138
+		decorators: d,
139
+	}
140
+}
141
+
142
+func (f *RequestFactory) AddDecorator(d ...Decorator) {
143
+	f.decorators = append(f.decorators, d...)
144
+}
145
+
146
+func (f *RequestFactory) GetDecorators() []Decorator {
147
+	return f.decorators
148
+}
149
+
150
+// NewRequest() creates a new *http.Request,
151
+// applies all decorators in the Factory on the request,
152
+// then applies decorators provided by d on the request.
153
+func (h *RequestFactory) NewRequest(method, urlStr string, body io.Reader, d ...Decorator) (*http.Request, error) {
154
+	req, err := http.NewRequest(method, urlStr, body)
155
+	if err != nil {
156
+		return nil, err
157
+	}
158
+
159
+	// By default, a nil factory should work.
160
+	if h == nil {
161
+		return req, nil
162
+	}
163
+	for _, dec := range h.decorators {
164
+		req, _ = dec.ChangeRequest(req)
165
+	}
166
+	for _, dec := range d {
167
+		req, _ = dec.ChangeRequest(req)
168
+	}
169
+	logrus.Debugf("%v -- HEADERS: %v", req.URL, req.Header)
170
+	return req, err
171
+}
0 172
new file mode 100644
... ...
@@ -0,0 +1,222 @@
0
+package requestdecorator
1
+
2
+import (
3
+	"net/http"
4
+	"strings"
5
+	"testing"
6
+)
7
+
8
+func TestUAVersionInfo(t *testing.T) {
9
+	uavi := NewUAVersionInfo("foo", "bar")
10
+	if !uavi.isValid() {
11
+		t.Fatalf("UAVersionInfo should be valid")
12
+	}
13
+	uavi = NewUAVersionInfo("", "bar")
14
+	if uavi.isValid() {
15
+		t.Fatalf("Expected UAVersionInfo to be invalid")
16
+	}
17
+	uavi = NewUAVersionInfo("foo", "")
18
+	if uavi.isValid() {
19
+		t.Fatalf("Expected UAVersionInfo to be invalid")
20
+	}
21
+}
22
+
23
+func TestUserAgentDecorator(t *testing.T) {
24
+	httpVersion := make([]UAVersionInfo, 2)
25
+	httpVersion = append(httpVersion, NewUAVersionInfo("testname", "testversion"))
26
+	httpVersion = append(httpVersion, NewUAVersionInfo("name", "version"))
27
+	uad := &UserAgentDecorator{
28
+		Versions: httpVersion,
29
+	}
30
+
31
+	req, err := http.NewRequest("GET", "/something", strings.NewReader("test"))
32
+	if err != nil {
33
+		t.Fatal(err)
34
+	}
35
+	reqDecorated, err := uad.ChangeRequest(req)
36
+	if err != nil {
37
+		t.Fatal(err)
38
+	}
39
+
40
+	if reqDecorated.Header.Get("User-Agent") != "testname/testversion name/version" {
41
+		t.Fatalf("Request should have User-Agent 'testname/testversion name/version'")
42
+	}
43
+}
44
+
45
+func TestUserAgentDecoratorErr(t *testing.T) {
46
+	httpVersion := make([]UAVersionInfo, 0)
47
+	uad := &UserAgentDecorator{
48
+		Versions: httpVersion,
49
+	}
50
+
51
+	var req *http.Request
52
+	_, err := uad.ChangeRequest(req)
53
+	if err == nil {
54
+		t.Fatalf("Expected to get ErrNilRequest instead no error was returned")
55
+	}
56
+}
57
+
58
+func TestMetaHeadersDecorator(t *testing.T) {
59
+	var headers = map[string][]string{
60
+		"key1": {"value1"},
61
+		"key2": {"value2"},
62
+	}
63
+	mhd := &MetaHeadersDecorator{
64
+		Headers: headers,
65
+	}
66
+
67
+	req, err := http.NewRequest("GET", "/something", strings.NewReader("test"))
68
+	if err != nil {
69
+		t.Fatal(err)
70
+	}
71
+	reqDecorated, err := mhd.ChangeRequest(req)
72
+	if err != nil {
73
+		t.Fatal(err)
74
+	}
75
+
76
+	v, ok := reqDecorated.Header["key1"]
77
+	if !ok {
78
+		t.Fatalf("Expected to have header key1")
79
+	}
80
+	if v[0] != "value1" {
81
+		t.Fatalf("Expected value for key1 isn't value1")
82
+	}
83
+
84
+	v, ok = reqDecorated.Header["key2"]
85
+	if !ok {
86
+		t.Fatalf("Expected to have header key2")
87
+	}
88
+	if v[0] != "value2" {
89
+		t.Fatalf("Expected value for key2 isn't value2")
90
+	}
91
+}
92
+
93
+func TestMetaHeadersDecoratorErr(t *testing.T) {
94
+	mhd := &MetaHeadersDecorator{}
95
+
96
+	var req *http.Request
97
+	_, err := mhd.ChangeRequest(req)
98
+	if err == nil {
99
+		t.Fatalf("Expected to get ErrNilRequest instead no error was returned")
100
+	}
101
+}
102
+
103
+func TestAuthDecorator(t *testing.T) {
104
+	ad := NewAuthDecorator("test", "password")
105
+
106
+	req, err := http.NewRequest("GET", "/something", strings.NewReader("test"))
107
+	if err != nil {
108
+		t.Fatal(err)
109
+	}
110
+	reqDecorated, err := ad.ChangeRequest(req)
111
+	if err != nil {
112
+		t.Fatal(err)
113
+	}
114
+
115
+	username, password, ok := reqDecorated.BasicAuth()
116
+	if !ok {
117
+		t.Fatalf("Cannot retrieve basic auth info from request")
118
+	}
119
+	if username != "test" {
120
+		t.Fatalf("Expected username to be test, got %s", username)
121
+	}
122
+	if password != "password" {
123
+		t.Fatalf("Expected password to be password, got %s", password)
124
+	}
125
+}
126
+
127
+func TestAuthDecoratorErr(t *testing.T) {
128
+	ad := &AuthDecorator{}
129
+
130
+	var req *http.Request
131
+	_, err := ad.ChangeRequest(req)
132
+	if err == nil {
133
+		t.Fatalf("Expected to get ErrNilRequest instead no error was returned")
134
+	}
135
+}
136
+
137
+func TestRequestFactory(t *testing.T) {
138
+	ad := NewAuthDecorator("test", "password")
139
+	httpVersion := make([]UAVersionInfo, 2)
140
+	httpVersion = append(httpVersion, NewUAVersionInfo("testname", "testversion"))
141
+	httpVersion = append(httpVersion, NewUAVersionInfo("name", "version"))
142
+	uad := &UserAgentDecorator{
143
+		Versions: httpVersion,
144
+	}
145
+
146
+	requestFactory := NewRequestFactory(ad, uad)
147
+
148
+	if dlen := requestFactory.GetDecorators(); len(dlen) != 2 {
149
+		t.Fatalf("Expected to have two decorators, got %d", dlen)
150
+	}
151
+
152
+	req, err := requestFactory.NewRequest("GET", "/test", strings.NewReader("test"))
153
+	if err != nil {
154
+		t.Fatal(err)
155
+	}
156
+
157
+	username, password, ok := req.BasicAuth()
158
+	if !ok {
159
+		t.Fatalf("Cannot retrieve basic auth info from request")
160
+	}
161
+	if username != "test" {
162
+		t.Fatalf("Expected username to be test, got %s", username)
163
+	}
164
+	if password != "password" {
165
+		t.Fatalf("Expected password to be password, got %s", password)
166
+	}
167
+	if req.Header.Get("User-Agent") != "testname/testversion name/version" {
168
+		t.Fatalf("Request should have User-Agent 'testname/testversion name/version'")
169
+	}
170
+}
171
+
172
+func TestRequestFactoryNewRequestWithDecorators(t *testing.T) {
173
+	ad := NewAuthDecorator("test", "password")
174
+
175
+	requestFactory := NewRequestFactory(ad)
176
+
177
+	if dlen := requestFactory.GetDecorators(); len(dlen) != 1 {
178
+		t.Fatalf("Expected to have one decorators, got %d", dlen)
179
+	}
180
+
181
+	ad2 := NewAuthDecorator("test2", "password2")
182
+
183
+	req, err := requestFactory.NewRequest("GET", "/test", strings.NewReader("test"), ad2)
184
+	if err != nil {
185
+		t.Fatal(err)
186
+	}
187
+
188
+	username, password, ok := req.BasicAuth()
189
+	if !ok {
190
+		t.Fatalf("Cannot retrieve basic auth info from request")
191
+	}
192
+	if username != "test2" {
193
+		t.Fatalf("Expected username to be test, got %s", username)
194
+	}
195
+	if password != "password2" {
196
+		t.Fatalf("Expected password to be password, got %s", password)
197
+	}
198
+}
199
+
200
+func TestRequestFactoryAddDecorator(t *testing.T) {
201
+	requestFactory := NewRequestFactory()
202
+
203
+	if dlen := requestFactory.GetDecorators(); len(dlen) != 0 {
204
+		t.Fatalf("Expected to have zero decorators, got %d", dlen)
205
+	}
206
+
207
+	ad := NewAuthDecorator("test", "password")
208
+	requestFactory.AddDecorator(ad)
209
+
210
+	if dlen := requestFactory.GetDecorators(); len(dlen) != 1 {
211
+		t.Fatalf("Expected to have one decorators, got %d", dlen)
212
+	}
213
+}
214
+
215
+func TestRequestFactoryNil(t *testing.T) {
216
+	var requestFactory RequestFactory
217
+	_, err := requestFactory.NewRequest("GET", "/test", strings.NewReader("test"))
218
+	if err != nil {
219
+		t.Fatalf("Expected not to get and error, got %s", err)
220
+	}
221
+}
... ...
@@ -14,7 +14,7 @@ import (
14 14
 	"time"
15 15
 
16 16
 	"github.com/Sirupsen/logrus"
17
-	"github.com/docker/docker/utils"
17
+	"github.com/docker/docker/pkg/requestdecorator"
18 18
 )
19 19
 
20 20
 const (
... ...
@@ -225,7 +225,7 @@ func SaveConfig(configFile *ConfigFile) error {
225 225
 }
226 226
 
227 227
 // Login tries to register/login to the registry server.
228
-func Login(authConfig *AuthConfig, registryEndpoint *Endpoint, factory *utils.HTTPRequestFactory) (string, error) {
228
+func Login(authConfig *AuthConfig, registryEndpoint *Endpoint, factory *requestdecorator.RequestFactory) (string, error) {
229 229
 	// Separates the v2 registry login logic from the v1 logic.
230 230
 	if registryEndpoint.Version == APIVersion2 {
231 231
 		return loginV2(authConfig, registryEndpoint, factory)
... ...
@@ -235,7 +235,7 @@ func Login(authConfig *AuthConfig, registryEndpoint *Endpoint, factory *utils.HT
235 235
 }
236 236
 
237 237
 // loginV1 tries to register/login to the v1 registry server.
238
-func loginV1(authConfig *AuthConfig, registryEndpoint *Endpoint, factory *utils.HTTPRequestFactory) (string, error) {
238
+func loginV1(authConfig *AuthConfig, registryEndpoint *Endpoint, factory *requestdecorator.RequestFactory) (string, error) {
239 239
 	var (
240 240
 		status        string
241 241
 		reqBody       []byte
... ...
@@ -348,7 +348,7 @@ func loginV1(authConfig *AuthConfig, registryEndpoint *Endpoint, factory *utils.
348 348
 // now, users should create their account through other means like directly from a web page
349 349
 // served by the v2 registry service provider. Whether this will be supported in the future
350 350
 // is to be determined.
351
-func loginV2(authConfig *AuthConfig, registryEndpoint *Endpoint, factory *utils.HTTPRequestFactory) (string, error) {
351
+func loginV2(authConfig *AuthConfig, registryEndpoint *Endpoint, factory *requestdecorator.RequestFactory) (string, error) {
352 352
 	logrus.Debugf("attempting v2 login to registry endpoint %s", registryEndpoint)
353 353
 	var (
354 354
 		err       error
... ...
@@ -381,7 +381,7 @@ func loginV2(authConfig *AuthConfig, registryEndpoint *Endpoint, factory *utils.
381 381
 	return "", fmt.Errorf("no successful auth challenge for %s - errors: %s", registryEndpoint, allErrors)
382 382
 }
383 383
 
384
-func tryV2BasicAuthLogin(authConfig *AuthConfig, params map[string]string, registryEndpoint *Endpoint, client *http.Client, factory *utils.HTTPRequestFactory) error {
384
+func tryV2BasicAuthLogin(authConfig *AuthConfig, params map[string]string, registryEndpoint *Endpoint, client *http.Client, factory *requestdecorator.RequestFactory) error {
385 385
 	req, err := factory.NewRequest("GET", registryEndpoint.Path(""), nil)
386 386
 	if err != nil {
387 387
 		return err
... ...
@@ -402,7 +402,7 @@ func tryV2BasicAuthLogin(authConfig *AuthConfig, params map[string]string, regis
402 402
 	return nil
403 403
 }
404 404
 
405
-func tryV2TokenAuthLogin(authConfig *AuthConfig, params map[string]string, registryEndpoint *Endpoint, client *http.Client, factory *utils.HTTPRequestFactory) error {
405
+func tryV2TokenAuthLogin(authConfig *AuthConfig, params map[string]string, registryEndpoint *Endpoint, client *http.Client, factory *requestdecorator.RequestFactory) error {
406 406
 	token, err := getToken(authConfig.Username, authConfig.Password, params, registryEndpoint, client, factory)
407 407
 	if err != nil {
408 408
 		return err
... ...
@@ -11,8 +11,8 @@ import (
11 11
 	"strings"
12 12
 
13 13
 	"github.com/Sirupsen/logrus"
14
+	"github.com/docker/docker/pkg/requestdecorator"
14 15
 	"github.com/docker/docker/registry/v2"
15
-	"github.com/docker/docker/utils"
16 16
 )
17 17
 
18 18
 // for mocking in unit tests
... ...
@@ -162,7 +162,7 @@ func (e *Endpoint) Ping() (RegistryInfo, error) {
162 162
 	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)
163 163
 }
164 164
 
165
-func (e *Endpoint) pingV1(factory *utils.HTTPRequestFactory) (RegistryInfo, error) {
165
+func (e *Endpoint) pingV1(factory *requestdecorator.RequestFactory) (RegistryInfo, error) {
166 166
 	logrus.Debugf("attempting v1 ping for registry endpoint %s", e)
167 167
 
168 168
 	if e.String() == IndexServerAddress() {
... ...
@@ -216,7 +216,7 @@ func (e *Endpoint) pingV1(factory *utils.HTTPRequestFactory) (RegistryInfo, erro
216 216
 	return info, nil
217 217
 }
218 218
 
219
-func (e *Endpoint) pingV2(factory *utils.HTTPRequestFactory) (RegistryInfo, error) {
219
+func (e *Endpoint) pingV2(factory *requestdecorator.RequestFactory) (RegistryInfo, error) {
220 220
 	logrus.Debugf("attempting v2 ping for registry endpoint %s", e)
221 221
 
222 222
 	req, err := factory.NewRequest("GET", e.Path(""), nil)
... ...
@@ -5,42 +5,26 @@ import (
5 5
 
6 6
 	"github.com/docker/docker/autogen/dockerversion"
7 7
 	"github.com/docker/docker/pkg/parsers/kernel"
8
-	"github.com/docker/docker/utils"
8
+	"github.com/docker/docker/pkg/requestdecorator"
9 9
 )
10 10
 
11
-func HTTPRequestFactory(metaHeaders map[string][]string) *utils.HTTPRequestFactory {
11
+func HTTPRequestFactory(metaHeaders map[string][]string) *requestdecorator.RequestFactory {
12 12
 	// FIXME: this replicates the 'info' job.
13
-	httpVersion := make([]utils.VersionInfo, 0, 4)
14
-	httpVersion = append(httpVersion, &simpleVersionInfo{"docker", dockerversion.VERSION})
15
-	httpVersion = append(httpVersion, &simpleVersionInfo{"go", runtime.Version()})
16
-	httpVersion = append(httpVersion, &simpleVersionInfo{"git-commit", dockerversion.GITCOMMIT})
13
+	httpVersion := make([]requestdecorator.UAVersionInfo, 0, 4)
14
+	httpVersion = append(httpVersion, requestdecorator.NewUAVersionInfo("docker", dockerversion.VERSION))
15
+	httpVersion = append(httpVersion, requestdecorator.NewUAVersionInfo("go", runtime.Version()))
16
+	httpVersion = append(httpVersion, requestdecorator.NewUAVersionInfo("git-commit", dockerversion.GITCOMMIT))
17 17
 	if kernelVersion, err := kernel.GetKernelVersion(); err == nil {
18
-		httpVersion = append(httpVersion, &simpleVersionInfo{"kernel", kernelVersion.String()})
18
+		httpVersion = append(httpVersion, requestdecorator.NewUAVersionInfo("kernel", kernelVersion.String()))
19 19
 	}
20
-	httpVersion = append(httpVersion, &simpleVersionInfo{"os", runtime.GOOS})
21
-	httpVersion = append(httpVersion, &simpleVersionInfo{"arch", runtime.GOARCH})
22
-	ud := utils.NewHTTPUserAgentDecorator(httpVersion...)
23
-	md := &utils.HTTPMetaHeadersDecorator{
20
+	httpVersion = append(httpVersion, requestdecorator.NewUAVersionInfo("os", runtime.GOOS))
21
+	httpVersion = append(httpVersion, requestdecorator.NewUAVersionInfo("arch", runtime.GOARCH))
22
+	uad := &requestdecorator.UserAgentDecorator{
23
+		Versions: httpVersion,
24
+	}
25
+	mhd := &requestdecorator.MetaHeadersDecorator{
24 26
 		Headers: metaHeaders,
25 27
 	}
26
-	factory := utils.NewHTTPRequestFactory(ud, md)
28
+	factory := requestdecorator.NewRequestFactory(uad, mhd)
27 29
 	return factory
28 30
 }
29
-
30
-// simpleVersionInfo is a simple implementation of
31
-// the interface VersionInfo, which is used
32
-// to provide version information for some product,
33
-// component, etc. It stores the product name and the version
34
-// in string and returns them on calls to Name() and Version().
35
-type simpleVersionInfo struct {
36
-	name    string
37
-	version string
38
-}
39
-
40
-func (v *simpleVersionInfo) Name() string {
41
-	return v.name
42
-}
43
-
44
-func (v *simpleVersionInfo) Version() string {
45
-	return v.version
46
-}
... ...
@@ -7,7 +7,7 @@ import (
7 7
 	"strings"
8 8
 	"testing"
9 9
 
10
-	"github.com/docker/docker/utils"
10
+	"github.com/docker/docker/pkg/requestdecorator"
11 11
 )
12 12
 
13 13
 var (
... ...
@@ -25,7 +25,7 @@ func spawnTestRegistrySession(t *testing.T) *Session {
25 25
 	if err != nil {
26 26
 		t.Fatal(err)
27 27
 	}
28
-	r, err := NewSession(authConfig, utils.NewHTTPRequestFactory(), endpoint, true)
28
+	r, err := NewSession(authConfig, requestdecorator.NewRequestFactory(), endpoint, true)
29 29
 	if err != nil {
30 30
 		t.Fatal(err)
31 31
 	}
... ...
@@ -40,7 +40,7 @@ func TestPublicSession(t *testing.T) {
40 40
 		if err != nil {
41 41
 			t.Fatal(err)
42 42
 		}
43
-		r, err := NewSession(authConfig, utils.NewHTTPRequestFactory(), endpoint, true)
43
+		r, err := NewSession(authConfig, requestdecorator.NewRequestFactory(), endpoint, true)
44 44
 		if err != nil {
45 45
 			t.Fatal(err)
46 46
 		}
... ...
@@ -19,19 +19,20 @@ import (
19 19
 
20 20
 	"github.com/Sirupsen/logrus"
21 21
 	"github.com/docker/docker/pkg/httputils"
22
+	"github.com/docker/docker/pkg/requestdecorator"
22 23
 	"github.com/docker/docker/pkg/tarsum"
23 24
 	"github.com/docker/docker/utils"
24 25
 )
25 26
 
26 27
 type Session struct {
27 28
 	authConfig    *AuthConfig
28
-	reqFactory    *utils.HTTPRequestFactory
29
+	reqFactory    *requestdecorator.RequestFactory
29 30
 	indexEndpoint *Endpoint
30 31
 	jar           *cookiejar.Jar
31 32
 	timeout       TimeoutType
32 33
 }
33 34
 
34
-func NewSession(authConfig *AuthConfig, factory *utils.HTTPRequestFactory, endpoint *Endpoint, timeout bool) (r *Session, err error) {
35
+func NewSession(authConfig *AuthConfig, factory *requestdecorator.RequestFactory, endpoint *Endpoint, timeout bool) (r *Session, err error) {
35 36
 	r = &Session{
36 37
 		authConfig:    authConfig,
37 38
 		indexEndpoint: endpoint,
... ...
@@ -55,7 +56,7 @@ func NewSession(authConfig *AuthConfig, factory *utils.HTTPRequestFactory, endpo
55 55
 		}
56 56
 		if info.Standalone {
57 57
 			logrus.Debugf("Endpoint %s is eligible for private registry. Enabling decorator.", r.indexEndpoint.String())
58
-			dec := utils.NewHTTPAuthDecorator(authConfig.Username, authConfig.Password)
58
+			dec := requestdecorator.NewAuthDecorator(authConfig.Username, authConfig.Password)
59 59
 			factory.AddDecorator(dec)
60 60
 		}
61 61
 	}
... ...
@@ -8,14 +8,14 @@ import (
8 8
 	"net/url"
9 9
 	"strings"
10 10
 
11
-	"github.com/docker/docker/utils"
11
+	"github.com/docker/docker/pkg/requestdecorator"
12 12
 )
13 13
 
14 14
 type tokenResponse struct {
15 15
 	Token string `json:"token"`
16 16
 }
17 17
 
18
-func getToken(username, password string, params map[string]string, registryEndpoint *Endpoint, client *http.Client, factory *utils.HTTPRequestFactory) (token string, err error) {
18
+func getToken(username, password string, params map[string]string, registryEndpoint *Endpoint, client *http.Client, factory *requestdecorator.RequestFactory) (token string, err error) {
19 19
 	realm, ok := params["realm"]
20 20
 	if !ok {
21 21
 		return "", errors.New("no realm specified for token auth challenge")
22 22
deleted file mode 100644
... ...
@@ -1,168 +0,0 @@
1
-package utils
2
-
3
-import (
4
-	"io"
5
-	"net/http"
6
-	"strings"
7
-
8
-	"github.com/Sirupsen/logrus"
9
-)
10
-
11
-// VersionInfo is used to model entities which has a version.
12
-// It is basically a tupple with name and version.
13
-type VersionInfo interface {
14
-	Name() string
15
-	Version() string
16
-}
17
-
18
-func validVersion(version VersionInfo) bool {
19
-	const stopChars = " \t\r\n/"
20
-	name := version.Name()
21
-	vers := version.Version()
22
-	if len(name) == 0 || strings.ContainsAny(name, stopChars) {
23
-		return false
24
-	}
25
-	if len(vers) == 0 || strings.ContainsAny(vers, stopChars) {
26
-		return false
27
-	}
28
-	return true
29
-}
30
-
31
-// Convert versions to a string and append the string to the string base.
32
-//
33
-// Each VersionInfo will be converted to a string in the format of
34
-// "product/version", where the "product" is get from the Name() method, while
35
-// version is get from the Version() method. Several pieces of verson information
36
-// will be concatinated and separated by space.
37
-func appendVersions(base string, versions ...VersionInfo) string {
38
-	if len(versions) == 0 {
39
-		return base
40
-	}
41
-
42
-	verstrs := make([]string, 0, 1+len(versions))
43
-	if len(base) > 0 {
44
-		verstrs = append(verstrs, base)
45
-	}
46
-
47
-	for _, v := range versions {
48
-		if !validVersion(v) {
49
-			continue
50
-		}
51
-		verstrs = append(verstrs, v.Name()+"/"+v.Version())
52
-	}
53
-	return strings.Join(verstrs, " ")
54
-}
55
-
56
-// HTTPRequestDecorator is used to change an instance of
57
-// http.Request. It could be used to add more header fields,
58
-// change body, etc.
59
-type HTTPRequestDecorator interface {
60
-	// ChangeRequest() changes the request accordingly.
61
-	// The changed request will be returned or err will be non-nil
62
-	// if an error occur.
63
-	ChangeRequest(req *http.Request) (newReq *http.Request, err error)
64
-}
65
-
66
-// HTTPUserAgentDecorator appends the product/version to the user agent field
67
-// of a request.
68
-type HTTPUserAgentDecorator struct {
69
-	versions []VersionInfo
70
-}
71
-
72
-func NewHTTPUserAgentDecorator(versions ...VersionInfo) HTTPRequestDecorator {
73
-	return &HTTPUserAgentDecorator{
74
-		versions: versions,
75
-	}
76
-}
77
-
78
-func (h *HTTPUserAgentDecorator) ChangeRequest(req *http.Request) (newReq *http.Request, err error) {
79
-	if req == nil {
80
-		return req, nil
81
-	}
82
-
83
-	userAgent := appendVersions(req.UserAgent(), h.versions...)
84
-	if len(userAgent) > 0 {
85
-		req.Header.Set("User-Agent", userAgent)
86
-	}
87
-	return req, nil
88
-}
89
-
90
-type HTTPMetaHeadersDecorator struct {
91
-	Headers map[string][]string
92
-}
93
-
94
-func (h *HTTPMetaHeadersDecorator) ChangeRequest(req *http.Request) (newReq *http.Request, err error) {
95
-	if h.Headers == nil {
96
-		return req, nil
97
-	}
98
-	for k, v := range h.Headers {
99
-		req.Header[k] = v
100
-	}
101
-	return req, nil
102
-}
103
-
104
-type HTTPAuthDecorator struct {
105
-	login    string
106
-	password string
107
-}
108
-
109
-func NewHTTPAuthDecorator(login, password string) HTTPRequestDecorator {
110
-	return &HTTPAuthDecorator{
111
-		login:    login,
112
-		password: password,
113
-	}
114
-}
115
-
116
-func (self *HTTPAuthDecorator) ChangeRequest(req *http.Request) (*http.Request, error) {
117
-	req.SetBasicAuth(self.login, self.password)
118
-	return req, nil
119
-}
120
-
121
-// HTTPRequestFactory creates an HTTP request
122
-// and applies a list of decorators on the request.
123
-type HTTPRequestFactory struct {
124
-	decorators []HTTPRequestDecorator
125
-}
126
-
127
-func NewHTTPRequestFactory(d ...HTTPRequestDecorator) *HTTPRequestFactory {
128
-	return &HTTPRequestFactory{
129
-		decorators: d,
130
-	}
131
-}
132
-
133
-func (self *HTTPRequestFactory) AddDecorator(d ...HTTPRequestDecorator) {
134
-	self.decorators = append(self.decorators, d...)
135
-}
136
-
137
-func (self *HTTPRequestFactory) GetDecorators() []HTTPRequestDecorator {
138
-	return self.decorators
139
-}
140
-
141
-// NewRequest() creates a new *http.Request,
142
-// applies all decorators in the HTTPRequestFactory on the request,
143
-// then applies decorators provided by d on the request.
144
-func (h *HTTPRequestFactory) NewRequest(method, urlStr string, body io.Reader, d ...HTTPRequestDecorator) (*http.Request, error) {
145
-	req, err := http.NewRequest(method, urlStr, body)
146
-	if err != nil {
147
-		return nil, err
148
-	}
149
-
150
-	// By default, a nil factory should work.
151
-	if h == nil {
152
-		return req, nil
153
-	}
154
-	for _, dec := range h.decorators {
155
-		req, err = dec.ChangeRequest(req)
156
-		if err != nil {
157
-			return nil, err
158
-		}
159
-	}
160
-	for _, dec := range d {
161
-		req, err = dec.ChangeRequest(req)
162
-		if err != nil {
163
-			return nil, err
164
-		}
165
-	}
166
-	logrus.Debugf("%v -- HEADERS: %v", req.URL, req.Header)
167
-	return req, err
168
-}