From f033ce3ee9ee055612acacde537687e41865e14f Mon Sep 17 00:00:00 2001 From: unclejack Date: Fri, 27 Jun 2014 15:04:28 +0300 Subject: [PATCH 1/2] resumablerequestreader: allow initial response Make it possible to inspect an initial response and pass it to ResumableRequestReader. This makes it possible to inspect an initial response and passing it to ResumableRequestReader to avoid making an extra request. Docker-DCO-1.1-Signed-off-by: Cristian Staretu (github: unclejack) --- utils/resumablerequestreader.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/utils/resumablerequestreader.go b/utils/resumablerequestreader.go index e01f4e6d71..bed202ec0c 100644 --- a/utils/resumablerequestreader.go +++ b/utils/resumablerequestreader.go @@ -24,6 +24,10 @@ func ResumableRequestReader(c *http.Client, r *http.Request, maxfail uint32, tot return &resumableRequestReader{client: c, request: r, maxFailures: maxfail, totalSize: totalsize} } +func ResumableRequestReaderWithInitialResponse(c *http.Client, r *http.Request, maxfail uint32, totalsize int64, initialResponse *http.Response) io.ReadCloser { + return &resumableRequestReader{client: c, request: r, maxFailures: maxfail, totalSize: totalsize, currentResponse: initialResponse} +} + func (r *resumableRequestReader) Read(p []byte) (n int, err error) { if r.client == nil || r.request == nil { return 0, fmt.Errorf("client and request can't be nil\n") From c47ebe7a351bc639028cd48aed9d2fa2310a2a65 Mon Sep 17 00:00:00 2001 From: unclejack Date: Fri, 27 Jun 2014 15:10:30 +0300 Subject: [PATCH 2/2] get layer: remove HEAD req & pass down response Docker-DCO-1.1-Signed-off-by: Cristian Staretu (github: unclejack) --- registry/registry.go | 56 ++++++++++++++++++-------------------------- 1 file changed, 23 insertions(+), 33 deletions(-) diff --git a/registry/registry.go b/registry/registry.go index 748636dca8..57795f1c34 100644 --- a/registry/registry.go +++ b/registry/registry.go @@ -390,52 +390,42 @@ func (r *Registry) GetRemoteImageJSON(imgID, registry string, token []string) ([ func (r *Registry) GetRemoteImageLayer(imgID, registry string, token []string, imgSize int64) (io.ReadCloser, error) { var ( - retries = 5 - headRes *http.Response - client *http.Client - hasResume bool = false - imageURL = fmt.Sprintf("%simages/%s/layer", registry, imgID) + retries = 5 + client *http.Client + res *http.Response + imageURL = fmt.Sprintf("%simages/%s/layer", registry, imgID) ) - headReq, err := r.reqFactory.NewRequest("HEAD", imageURL, nil) - if err != nil { - return nil, fmt.Errorf("Error while getting from the server: %s\n", err) - } - - setTokenAuth(headReq, token) - for i := 1; i <= retries; i++ { - headRes, client, err = r.doRequest(headReq) - if err != nil && i == retries { - return nil, fmt.Errorf("Eror while making head request: %s\n", err) - } else if err != nil { - time.Sleep(time.Duration(i) * 5 * time.Second) - continue - } - break - } - - if headRes.Header.Get("Accept-Ranges") == "bytes" && imgSize > 0 { - hasResume = true - } req, err := r.reqFactory.NewRequest("GET", imageURL, nil) if err != nil { return nil, fmt.Errorf("Error while getting from the server: %s\n", err) } setTokenAuth(req, token) - if hasResume { - utils.Debugf("server supports resume") - return utils.ResumableRequestReader(client, req, 5, imgSize), nil - } - utils.Debugf("server doesn't support resume") - res, _, err := r.doRequest(req) - if err != nil { - return nil, err + for i := 1; i <= retries; i++ { + res, client, err = r.doRequest(req) + if err != nil { + res.Body.Close() + if i == retries { + return nil, fmt.Errorf("Server error: Status %d while fetching image layer (%s)", + res.StatusCode, imgID) + } + time.Sleep(time.Duration(i) * 5 * time.Second) + continue + } + break } + if res.StatusCode != 200 { res.Body.Close() return nil, fmt.Errorf("Server error: Status %d while fetching image layer (%s)", res.StatusCode, imgID) } + + if res.Header.Get("Accept-Ranges") == "bytes" && imgSize > 0 { + utils.Debugf("server supports resume") + return utils.ResumableRequestReaderWithInitialResponse(client, req, 5, imgSize, res), nil + } + utils.Debugf("server doesn't support resume") return res.Body, nil }