Skip to content

Commit feda3db

Browse files
author
Victor Vieux
committed
Merge pull request moby#1382 from monnand/650-http-utils
650 http utils and user agent field
2 parents a37b42b + 7bade49 commit feda3db

File tree

6 files changed

+172
-97
lines changed

6 files changed

+172
-97
lines changed

api.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ func postAuth(srv *Server, version float64, w http.ResponseWriter, r *http.Reque
8787
if err != nil {
8888
return err
8989
}
90-
status, err := auth.Login(authConfig)
90+
status, err := auth.Login(authConfig, srv.HTTPRequestFactory())
9191
if err != nil {
9292
return err
9393
}

auth/auth.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"encoding/json"
66
"errors"
77
"fmt"
8+
"github.com/dotcloud/docker/utils"
89
"io/ioutil"
910
"net/http"
1011
"os"
@@ -140,7 +141,7 @@ func SaveConfig(configFile *ConfigFile) error {
140141
}
141142

142143
// try to register/login to the registry server
143-
func Login(authConfig *AuthConfig) (string, error) {
144+
func Login(authConfig *AuthConfig, factory *utils.HTTPRequestFactory) (string, error) {
144145
client := &http.Client{}
145146
reqStatusCode := 0
146147
var status string
@@ -171,7 +172,7 @@ func Login(authConfig *AuthConfig) (string, error) {
171172
"Please check your e-mail for a confirmation link.")
172173
} else if reqStatusCode == 400 {
173174
if string(reqBody) == "\"Username or email already exists\"" {
174-
req, err := http.NewRequest("GET", IndexServerAddress()+"users/", nil)
175+
req, err := factory.NewRequest("GET", IndexServerAddress()+"users/", nil)
175176
req.SetBasicAuth(authConfig.Username, authConfig.Password)
176177
resp, err := client.Do(req)
177178
if err != nil {

auth/auth_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ func TestLogin(t *testing.T) {
3333
os.Setenv("DOCKER_INDEX_URL", "https://indexstaging-docker.dotcloud.com")
3434
defer os.Setenv("DOCKER_INDEX_URL", "")
3535
authConfig := &AuthConfig{Username: "unittester", Password: "surlautrerivejetattendrai", Email: "noise+unittester@dotcloud.com"}
36-
status, err := Login(authConfig)
36+
status, err := Login(authConfig, nil)
3737
if err != nil {
3838
t.Fatal(err)
3939
}
@@ -53,7 +53,7 @@ func TestCreateAccount(t *testing.T) {
5353
token := hex.EncodeToString(tokenBuffer)[:12]
5454
username := "ut" + token
5555
authConfig := &AuthConfig{Username: username, Password: "test42", Email: "docker-ut+" + token + "@example.com"}
56-
status, err := Login(authConfig)
56+
status, err := Login(authConfig, nil)
5757
if err != nil {
5858
t.Fatal(err)
5959
}
@@ -63,7 +63,7 @@ func TestCreateAccount(t *testing.T) {
6363
t.Fatalf("Expected status: \"%s\", found \"%s\" instead.", expectedStatus, status)
6464
}
6565

66-
status, err = Login(authConfig)
66+
status, err = Login(authConfig, nil)
6767
if err == nil {
6868
t.Fatalf("Expected error but found nil instead")
6969
}

registry/registry.go

Lines changed: 15 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -100,13 +100,6 @@ func ResolveRepositoryName(reposName string) (string, string, error) {
100100
return endpoint, reposName, err
101101
}
102102

103-
// VersionInfo is used to model entities which has a version.
104-
// It is basically a tupple with name and version.
105-
type VersionInfo interface {
106-
Name() string
107-
Version() string
108-
}
109-
110103
func doWithCookies(c *http.Client, req *http.Request) (*http.Response, error) {
111104
for _, cookie := range c.Jar.Cookies(req.URL) {
112105
req.AddCookie(cookie)
@@ -121,29 +114,14 @@ func doWithCookies(c *http.Client, req *http.Request) (*http.Response, error) {
121114
return res, err
122115
}
123116

124-
// Set the user agent field in the header based on the versions provided
125-
// in NewRegistry() and extra.
126-
func (r *Registry) setUserAgent(req *http.Request, extra ...VersionInfo) {
127-
if len(r.baseVersions)+len(extra) == 0 {
128-
return
129-
}
130-
if len(extra) == 0 {
131-
req.Header.Set("User-Agent", r.baseVersionsStr)
132-
} else {
133-
req.Header.Set("User-Agent", appendVersions(r.baseVersionsStr, extra...))
134-
}
135-
return
136-
}
137-
138117
// Retrieve the history of a given image from the Registry.
139118
// Return a list of the parent's json (requested image included)
140119
func (r *Registry) GetRemoteHistory(imgID, registry string, token []string) ([]string, error) {
141-
req, err := http.NewRequest("GET", registry+"images/"+imgID+"/ancestry", nil)
120+
req, err := r.reqFactory.NewRequest("GET", registry+"images/"+imgID+"/ancestry", nil)
142121
if err != nil {
143122
return nil, err
144123
}
145124
req.Header.Set("Authorization", "Token "+strings.Join(token, ", "))
146-
r.setUserAgent(req)
147125
res, err := doWithCookies(r.client, req)
148126
if err != nil || res.StatusCode != 200 {
149127
if res != nil {
@@ -170,7 +148,7 @@ func (r *Registry) GetRemoteHistory(imgID, registry string, token []string) ([]s
170148
func (r *Registry) LookupRemoteImage(imgID, registry string, token []string) bool {
171149
rt := &http.Transport{Proxy: http.ProxyFromEnvironment}
172150

173-
req, err := http.NewRequest("GET", registry+"images/"+imgID+"/json", nil)
151+
req, err := r.reqFactory.NewRequest("GET", registry+"images/"+imgID+"/json", nil)
174152
if err != nil {
175153
return false
176154
}
@@ -185,12 +163,11 @@ func (r *Registry) LookupRemoteImage(imgID, registry string, token []string) boo
185163
// Retrieve an image from the Registry.
186164
func (r *Registry) GetRemoteImageJSON(imgID, registry string, token []string) ([]byte, int, error) {
187165
// Get the JSON
188-
req, err := http.NewRequest("GET", registry+"images/"+imgID+"/json", nil)
166+
req, err := r.reqFactory.NewRequest("GET", registry+"images/"+imgID+"/json", nil)
189167
if err != nil {
190168
return nil, -1, fmt.Errorf("Failed to download json: %s", err)
191169
}
192170
req.Header.Set("Authorization", "Token "+strings.Join(token, ", "))
193-
r.setUserAgent(req)
194171
res, err := doWithCookies(r.client, req)
195172
if err != nil {
196173
return nil, -1, fmt.Errorf("Failed to download json: %s", err)
@@ -213,12 +190,11 @@ func (r *Registry) GetRemoteImageJSON(imgID, registry string, token []string) ([
213190
}
214191

215192
func (r *Registry) GetRemoteImageLayer(imgID, registry string, token []string) (io.ReadCloser, error) {
216-
req, err := http.NewRequest("GET", registry+"images/"+imgID+"/layer", nil)
193+
req, err := r.reqFactory.NewRequest("GET", registry+"images/"+imgID+"/layer", nil)
217194
if err != nil {
218195
return nil, fmt.Errorf("Error while getting from the server: %s\n", err)
219196
}
220197
req.Header.Set("Authorization", "Token "+strings.Join(token, ", "))
221-
r.setUserAgent(req)
222198
res, err := doWithCookies(r.client, req)
223199
if err != nil {
224200
return nil, err
@@ -239,7 +215,6 @@ func (r *Registry) GetRemoteTags(registries []string, repository string, token [
239215
return nil, err
240216
}
241217
req.Header.Set("Authorization", "Token "+strings.Join(token, ", "))
242-
r.setUserAgent(req)
243218
res, err := doWithCookies(r.client, req)
244219
if err != nil {
245220
return nil, err
@@ -281,7 +256,6 @@ func (r *Registry) GetRepositoryData(indexEp, remote string) (*RepositoryData, e
281256
req.SetBasicAuth(r.authConfig.Username, r.authConfig.Password)
282257
}
283258
req.Header.Set("X-Docker-Token", "true")
284-
r.setUserAgent(req)
285259

286260
res, err := r.client.Do(req)
287261
if err != nil {
@@ -339,7 +313,7 @@ func (r *Registry) PushImageChecksumRegistry(imgData *ImgData, registry string,
339313

340314
utils.Debugf("[registry] Calling PUT %s", registry+"images/"+imgData.ID+"/checksum")
341315

342-
req, err := http.NewRequest("PUT", registry+"images/"+imgData.ID+"/checksum", nil)
316+
req, err := r.reqFactory.NewRequest("PUT", registry+"images/"+imgData.ID+"/checksum", nil)
343317
if err != nil {
344318
return err
345319
}
@@ -375,13 +349,12 @@ func (r *Registry) PushImageJSONRegistry(imgData *ImgData, jsonRaw []byte, regis
375349

376350
utils.Debugf("[registry] Calling PUT %s", registry+"images/"+imgData.ID+"/json")
377351

378-
req, err := http.NewRequest("PUT", registry+"images/"+imgData.ID+"/json", bytes.NewReader(jsonRaw))
352+
req, err := r.reqFactory.NewRequest("PUT", registry+"images/"+imgData.ID+"/json", bytes.NewReader(jsonRaw))
379353
if err != nil {
380354
return err
381355
}
382356
req.Header.Add("Content-type", "application/json")
383357
req.Header.Set("Authorization", "Token "+strings.Join(token, ","))
384-
r.setUserAgent(req)
385358

386359
res, err := doWithCookies(r.client, req)
387360
if err != nil {
@@ -410,14 +383,13 @@ func (r *Registry) PushImageLayerRegistry(imgID string, layer io.Reader, registr
410383

411384
tarsumLayer := &utils.TarSum{Reader: layer}
412385

413-
req, err := http.NewRequest("PUT", registry+"images/"+imgID+"/layer", tarsumLayer)
386+
req, err := r.reqFactory.NewRequest("PUT", registry+"images/"+imgID+"/layer", tarsumLayer)
414387
if err != nil {
415388
return "", err
416389
}
417390
req.ContentLength = -1
418391
req.TransferEncoding = []string{"chunked"}
419392
req.Header.Set("Authorization", "Token "+strings.Join(token, ","))
420-
r.setUserAgent(req)
421393
res, err := doWithCookies(r.client, req)
422394
if err != nil {
423395
return "", fmt.Errorf("Failed to upload layer: %s", err)
@@ -435,7 +407,7 @@ func (r *Registry) PushImageLayerRegistry(imgID string, layer io.Reader, registr
435407
}
436408

437409
func (r *Registry) opaqueRequest(method, urlStr string, body io.Reader) (*http.Request, error) {
438-
req, err := http.NewRequest(method, urlStr, body)
410+
req, err := r.reqFactory.NewRequest(method, urlStr, body)
439411
if err != nil {
440412
return nil, err
441413
}
@@ -455,7 +427,6 @@ func (r *Registry) PushRegistryTag(remote, revision, tag, registry string, token
455427
}
456428
req.Header.Add("Content-type", "application/json")
457429
req.Header.Set("Authorization", "Token "+strings.Join(token, ","))
458-
r.setUserAgent(req)
459430
req.ContentLength = int64(len(revision))
460431
res, err := doWithCookies(r.client, req)
461432
if err != nil {
@@ -500,7 +471,6 @@ func (r *Registry) PushImageJSONIndex(indexEp, remote string, imgList []*ImgData
500471
req.SetBasicAuth(r.authConfig.Username, r.authConfig.Password)
501472
req.ContentLength = int64(len(imgListJSON))
502473
req.Header.Set("X-Docker-Token", "true")
503-
r.setUserAgent(req)
504474
if validate {
505475
req.Header["X-Docker-Endpoints"] = regs
506476
}
@@ -521,7 +491,6 @@ func (r *Registry) PushImageJSONIndex(indexEp, remote string, imgList []*ImgData
521491
req.SetBasicAuth(r.authConfig.Username, r.authConfig.Password)
522492
req.ContentLength = int64(len(imgListJSON))
523493
req.Header.Set("X-Docker-Token", "true")
524-
r.setUserAgent(req)
525494
if validate {
526495
req.Header["X-Docker-Endpoints"] = regs
527496
}
@@ -576,7 +545,7 @@ func (r *Registry) PushImageJSONIndex(indexEp, remote string, imgList []*ImgData
576545

577546
func (r *Registry) SearchRepositories(term string) (*SearchResults, error) {
578547
u := auth.IndexServerAddress() + "search?q=" + url.QueryEscape(term)
579-
req, err := http.NewRequest("GET", u, nil)
548+
req, err := r.reqFactory.NewRequest("GET", u, nil)
580549
if err != nil {
581550
return nil, err
582551
}
@@ -628,52 +597,12 @@ type ImgData struct {
628597
}
629598

630599
type Registry struct {
631-
client *http.Client
632-
authConfig *auth.AuthConfig
633-
baseVersions []VersionInfo
634-
baseVersionsStr string
600+
client *http.Client
601+
authConfig *auth.AuthConfig
602+
reqFactory *utils.HTTPRequestFactory
635603
}
636604

637-
func validVersion(version VersionInfo) bool {
638-
stopChars := " \t\r\n/"
639-
if strings.ContainsAny(version.Name(), stopChars) {
640-
return false
641-
}
642-
if strings.ContainsAny(version.Version(), stopChars) {
643-
return false
644-
}
645-
return true
646-
}
647-
648-
// Convert versions to a string and append the string to the string base.
649-
//
650-
// Each VersionInfo will be converted to a string in the format of
651-
// "product/version", where the "product" is get from the Name() method, while
652-
// version is get from the Version() method. Several pieces of verson information
653-
// will be concatinated and separated by space.
654-
func appendVersions(base string, versions ...VersionInfo) string {
655-
if len(versions) == 0 {
656-
return base
657-
}
658-
659-
var buf bytes.Buffer
660-
if len(base) > 0 {
661-
buf.Write([]byte(base))
662-
}
663-
664-
for _, v := range versions {
665-
if !validVersion(v) {
666-
continue
667-
}
668-
buf.Write([]byte(v.Name()))
669-
buf.Write([]byte("/"))
670-
buf.Write([]byte(v.Version()))
671-
buf.Write([]byte(" "))
672-
}
673-
return buf.String()
674-
}
675-
676-
func NewRegistry(root string, authConfig *auth.AuthConfig, baseVersions ...VersionInfo) (r *Registry, err error) {
605+
func NewRegistry(root string, authConfig *auth.AuthConfig, factory *utils.HTTPRequestFactory) (r *Registry, err error) {
677606
httpTransport := &http.Transport{
678607
DisableKeepAlives: true,
679608
Proxy: http.ProxyFromEnvironment,
@@ -689,7 +618,7 @@ func NewRegistry(root string, authConfig *auth.AuthConfig, baseVersions ...Versi
689618
if err != nil {
690619
return nil, err
691620
}
692-
r.baseVersions = baseVersions
693-
r.baseVersionsStr = appendVersions("", baseVersions...)
621+
622+
r.reqFactory = factory
694623
return r, nil
695624
}

server.go

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,9 @@ func (v *simpleVersionInfo) Version() string {
5252
// docker, go, git-commit (of the docker) and the host's kernel.
5353
//
5454
// Such information will be used on call to NewRegistry().
55-
func (srv *Server) versionInfos() []registry.VersionInfo {
55+
func (srv *Server) versionInfos() []utils.VersionInfo {
5656
v := srv.DockerVersion()
57-
ret := make([]registry.VersionInfo, 0, 4)
57+
ret := make([]utils.VersionInfo, 0, 4)
5858
ret = append(ret, &simpleVersionInfo{"docker", v.Version})
5959

6060
if len(v.GoVersion) > 0 {
@@ -102,7 +102,7 @@ func (srv *Server) ContainerExport(name string, out io.Writer) error {
102102
}
103103

104104
func (srv *Server) ImagesSearch(term string) ([]APISearch, error) {
105-
r, err := registry.NewRegistry(srv.runtime.root, nil, srv.versionInfos()...)
105+
r, err := registry.NewRegistry(srv.runtime.root, nil, srv.HTTPRequestFactory())
106106
if err != nil {
107107
return nil, err
108108
}
@@ -559,7 +559,7 @@ func (srv *Server) poolRemove(kind, key string) error {
559559
}
560560

561561
func (srv *Server) ImagePull(localName string, tag string, out io.Writer, sf *utils.StreamFormatter, authConfig *auth.AuthConfig) error {
562-
r, err := registry.NewRegistry(srv.runtime.root, authConfig, srv.versionInfos()...)
562+
r, err := registry.NewRegistry(srv.runtime.root, authConfig, srv.HTTPRequestFactory())
563563
if err != nil {
564564
return err
565565
}
@@ -720,7 +720,7 @@ func (srv *Server) ImagePush(localName string, out io.Writer, sf *utils.StreamFo
720720

721721
out = utils.NewWriteFlusher(out)
722722
img, err := srv.runtime.graph.Get(localName)
723-
r, err2 := registry.NewRegistry(srv.runtime.root, authConfig, srv.versionInfos()...)
723+
r, err2 := registry.NewRegistry(srv.runtime.root, authConfig, srv.HTTPRequestFactory())
724724
if err2 != nil {
725725
return err2
726726
}
@@ -1164,11 +1164,21 @@ func NewServer(flGraphPath string, autoRestart, enableCors bool, dns ListOpts) (
11641164
pushingPool: make(map[string]struct{}),
11651165
events: make([]utils.JSONMessage, 0, 64), //only keeps the 64 last events
11661166
listeners: make(map[string]chan utils.JSONMessage),
1167+
reqFactory: nil,
11671168
}
11681169
runtime.srv = srv
11691170
return srv, nil
11701171
}
11711172

1173+
func (srv *Server) HTTPRequestFactory() *utils.HTTPRequestFactory {
1174+
if srv.reqFactory == nil {
1175+
ud := utils.NewHTTPUserAgentDecorator(srv.versionInfos()...)
1176+
factory := utils.NewHTTPRequestFactory(ud)
1177+
srv.reqFactory = factory
1178+
}
1179+
return srv.reqFactory
1180+
}
1181+
11721182
func (srv *Server) LogEvent(action, id string) {
11731183
now := time.Now().Unix()
11741184
jm := utils.JSONMessage{Status: action, ID: id, Time: now}
@@ -1189,4 +1199,5 @@ type Server struct {
11891199
pushingPool map[string]struct{}
11901200
events []utils.JSONMessage
11911201
listeners map[string]chan utils.JSONMessage
1202+
reqFactory *utils.HTTPRequestFactory
11921203
}

0 commit comments

Comments
 (0)