mirror of https://github.com/docker/docs.git
Merge pull request #21283 from runcom/update-test
vendor docker/distribution d06d6d3b09
This commit is contained in:
commit
a05fdd6806
|
@ -93,7 +93,8 @@ func retryOnError(err error) error {
|
||||||
return xfer.DoNotRetry{Err: err}
|
return xfer.DoNotRetry{Err: err}
|
||||||
}
|
}
|
||||||
case *url.Error:
|
case *url.Error:
|
||||||
if v.Err == auth.ErrNoBasicAuthCredentials {
|
switch v.Err {
|
||||||
|
case auth.ErrNoBasicAuthCredentials, auth.ErrNoToken:
|
||||||
return xfer.DoNotRetry{Err: v.Err}
|
return xfer.DoNotRetry{Err: v.Err}
|
||||||
}
|
}
|
||||||
return retryOnError(v.Err)
|
return retryOnError(v.Err)
|
||||||
|
|
|
@ -48,7 +48,7 @@ clone git github.com/boltdb/bolt v1.1.0
|
||||||
clone git github.com/miekg/dns 75e6e86cc601825c5dbcd4e0c209eab180997cd7
|
clone git github.com/miekg/dns 75e6e86cc601825c5dbcd4e0c209eab180997cd7
|
||||||
|
|
||||||
# get graph and distribution packages
|
# get graph and distribution packages
|
||||||
clone git github.com/docker/distribution db17a23b961978730892e12a0c6051d43a31aab3
|
clone git github.com/docker/distribution d06d6d3b093302c02a93153ac7b06ebc0ffd1793
|
||||||
clone git github.com/vbatts/tar-split v0.9.11
|
clone git github.com/vbatts/tar-split v0.9.11
|
||||||
|
|
||||||
# get desired notary commit, might also need to be updated in Dockerfile
|
# get desired notary commit, might also need to be updated in Dockerfile
|
||||||
|
|
|
@ -546,35 +546,78 @@ func (s *DockerSuite) TestPushToCentralRegistryUnauthorized(c *check.C) {
|
||||||
dockerCmd(c, "tag", "busybox", repoName)
|
dockerCmd(c, "tag", "busybox", repoName)
|
||||||
out, _, err := dockerCmdWithError("push", repoName)
|
out, _, err := dockerCmdWithError("push", repoName)
|
||||||
c.Assert(err, check.NotNil, check.Commentf(out))
|
c.Assert(err, check.NotNil, check.Commentf(out))
|
||||||
|
c.Assert(out, check.Not(checker.Contains), "Retrying")
|
||||||
c.Assert(out, checker.Contains, "unauthorized: access to the requested resource is not authorized")
|
c.Assert(out, checker.Contains, "unauthorized: access to the requested resource is not authorized")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DockerRegistryAuthTokenSuite) TestPushTokenServiceUnauthResponse(c *check.C) {
|
func getTestTokenService(status int, body string) *httptest.Server {
|
||||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
w.WriteHeader(http.StatusUnauthorized)
|
w.WriteHeader(status)
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.Write([]byte(`{"errors": [{"Code":"UNAUTHORIZED", "message": "a message", "detail": null}]}`))
|
w.Write([]byte(body))
|
||||||
}))
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DockerRegistryAuthTokenSuite) TestPushTokenServiceUnauthResponse(c *check.C) {
|
||||||
|
ts := getTestTokenService(http.StatusUnauthorized, `{"errors": [{"Code":"UNAUTHORIZED", "message": "a message", "detail": null}]}`)
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
s.setupRegistryWithTokenService(c, ts.URL)
|
s.setupRegistryWithTokenService(c, ts.URL)
|
||||||
repoName := fmt.Sprintf("%s/busybox", privateRegistryURL)
|
repoName := fmt.Sprintf("%s/busybox", privateRegistryURL)
|
||||||
dockerCmd(c, "tag", "busybox", repoName)
|
dockerCmd(c, "tag", "busybox", repoName)
|
||||||
out, _, err := dockerCmdWithError("push", repoName)
|
out, _, err := dockerCmdWithError("push", repoName)
|
||||||
c.Assert(err, check.NotNil, check.Commentf(out))
|
c.Assert(err, check.NotNil, check.Commentf(out))
|
||||||
|
c.Assert(out, checker.Not(checker.Contains), "Retrying")
|
||||||
c.Assert(out, checker.Contains, "unauthorized: a message")
|
c.Assert(out, checker.Contains, "unauthorized: a message")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DockerRegistryAuthTokenSuite) TestPushMisconfiguredTokenServiceResponse(c *check.C) {
|
func (s *DockerRegistryAuthTokenSuite) TestPushMisconfiguredTokenServiceResponseUnauthorized(c *check.C) {
|
||||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
ts := getTestTokenService(http.StatusUnauthorized, `{"error": "unauthorized"}`)
|
||||||
w.WriteHeader(http.StatusUnauthorized)
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
// this will make the daemon panics if no check is performed in retryOnError
|
|
||||||
w.Write([]byte(`{"error": "unauthorized"}`))
|
|
||||||
}))
|
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
s.setupRegistryWithTokenService(c, ts.URL)
|
s.setupRegistryWithTokenService(c, ts.URL)
|
||||||
repoName := fmt.Sprintf("%s/busybox", privateRegistryURL)
|
repoName := fmt.Sprintf("%s/busybox", privateRegistryURL)
|
||||||
dockerCmd(c, "tag", "busybox", repoName)
|
dockerCmd(c, "tag", "busybox", repoName)
|
||||||
out, _, err := dockerCmdWithError("push", repoName)
|
out, _, err := dockerCmdWithError("push", repoName)
|
||||||
c.Assert(err, check.NotNil, check.Commentf(out))
|
c.Assert(err, check.NotNil, check.Commentf(out))
|
||||||
|
c.Assert(out, checker.Not(checker.Contains), "Retrying")
|
||||||
|
split := strings.Split(out, "\n")
|
||||||
|
c.Assert(split[len(split)-2], check.Equals, "unauthorized: authentication required")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DockerRegistryAuthTokenSuite) TestPushMisconfiguredTokenServiceResponseError(c *check.C) {
|
||||||
|
ts := getTestTokenService(http.StatusInternalServerError, `{"error": "unexpected"}`)
|
||||||
|
defer ts.Close()
|
||||||
|
s.setupRegistryWithTokenService(c, ts.URL)
|
||||||
|
repoName := fmt.Sprintf("%s/busybox", privateRegistryURL)
|
||||||
|
dockerCmd(c, "tag", "busybox", repoName)
|
||||||
|
out, _, err := dockerCmdWithError("push", repoName)
|
||||||
|
c.Assert(err, check.NotNil, check.Commentf(out))
|
||||||
|
c.Assert(out, checker.Contains, "Retrying")
|
||||||
|
split := strings.Split(out, "\n")
|
||||||
|
c.Assert(split[len(split)-2], check.Equals, "received unexpected HTTP status: 500 Internal Server Error")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DockerRegistryAuthTokenSuite) TestPushMisconfiguredTokenServiceResponseUnparsable(c *check.C) {
|
||||||
|
ts := getTestTokenService(http.StatusForbidden, `no way`)
|
||||||
|
defer ts.Close()
|
||||||
|
s.setupRegistryWithTokenService(c, ts.URL)
|
||||||
|
repoName := fmt.Sprintf("%s/busybox", privateRegistryURL)
|
||||||
|
dockerCmd(c, "tag", "busybox", repoName)
|
||||||
|
out, _, err := dockerCmdWithError("push", repoName)
|
||||||
|
c.Assert(err, check.NotNil, check.Commentf(out))
|
||||||
|
c.Assert(out, checker.Not(checker.Contains), "Retrying")
|
||||||
|
split := strings.Split(out, "\n")
|
||||||
|
c.Assert(split[len(split)-2], checker.Contains, "error parsing HTTP 403 response body: ")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DockerRegistryAuthTokenSuite) TestPushMisconfiguredTokenServiceResponseNoToken(c *check.C) {
|
||||||
|
ts := getTestTokenService(http.StatusOK, `{"something": "wrong"}`)
|
||||||
|
defer ts.Close()
|
||||||
|
s.setupRegistryWithTokenService(c, ts.URL)
|
||||||
|
repoName := fmt.Sprintf("%s/busybox", privateRegistryURL)
|
||||||
|
dockerCmd(c, "tag", "busybox", repoName)
|
||||||
|
out, _, err := dockerCmdWithError("push", repoName)
|
||||||
|
c.Assert(err, check.NotNil, check.Commentf(out))
|
||||||
|
c.Assert(out, checker.Not(checker.Contains), "Retrying")
|
||||||
|
split := strings.Split(out, "\n")
|
||||||
|
c.Assert(split[len(split)-2], check.Equals, "authorization server did not include a token in the response")
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,7 +90,7 @@ It's mandatory to:
|
||||||
|
|
||||||
Complying to these simple rules will greatly accelerate the review process, and will ensure you have a pleasant experience in contributing code to the Registry.
|
Complying to these simple rules will greatly accelerate the review process, and will ensure you have a pleasant experience in contributing code to the Registry.
|
||||||
|
|
||||||
Have a look at a great, successful contribution: the [Ceph driver PR](https://github.com/docker/distribution/pull/443)
|
Have a look at a great, successful contribution: the [Swift driver PR](https://github.com/docker/distribution/pull/493)
|
||||||
|
|
||||||
## Coding Style
|
## Coding Style
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
FROM golang:1.5.3
|
FROM golang:1.5.3
|
||||||
|
|
||||||
RUN apt-get update && \
|
RUN apt-get update && \
|
||||||
apt-get install -y librados-dev apache2-utils && \
|
apt-get install -y apache2-utils && \
|
||||||
rm -rf /var/lib/apt/lists/*
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
ENV DISTRIBUTION_DIR /go/src/github.com/docker/distribution
|
ENV DISTRIBUTION_DIR /go/src/github.com/docker/distribution
|
||||||
ENV GOPATH $DISTRIBUTION_DIR/Godeps/_workspace:$GOPATH
|
ENV GOPATH $DISTRIBUTION_DIR/Godeps/_workspace:$GOPATH
|
||||||
ENV DOCKER_BUILDTAGS include_rados include_oss include_gcs
|
ENV DOCKER_BUILDTAGS include_oss include_gcs
|
||||||
|
|
||||||
WORKDIR $DISTRIBUTION_DIR
|
WORKDIR $DISTRIBUTION_DIR
|
||||||
COPY . $DISTRIBUTION_DIR
|
COPY . $DISTRIBUTION_DIR
|
||||||
|
|
|
@ -189,9 +189,11 @@ type BlobCreateOption interface {
|
||||||
// BlobWriteService.Resume. If supported by the store, a writer can be
|
// BlobWriteService.Resume. If supported by the store, a writer can be
|
||||||
// recovered with the id.
|
// recovered with the id.
|
||||||
type BlobWriter interface {
|
type BlobWriter interface {
|
||||||
io.WriteSeeker
|
io.WriteCloser
|
||||||
io.ReaderFrom
|
io.ReaderFrom
|
||||||
io.Closer
|
|
||||||
|
// Size returns the number of bytes written to this blob.
|
||||||
|
Size() int64
|
||||||
|
|
||||||
// ID returns the identifier for this writer. The ID can be used with the
|
// ID returns the identifier for this writer. The ID can be used with the
|
||||||
// Blob service to later resume the write.
|
// Blob service to later resume the write.
|
||||||
|
@ -216,9 +218,6 @@ type BlobWriter interface {
|
||||||
// result in a no-op. This allows use of Cancel in a defer statement,
|
// result in a no-op. This allows use of Cancel in a defer statement,
|
||||||
// increasing the assurance that it is correctly called.
|
// increasing the assurance that it is correctly called.
|
||||||
Cancel(ctx context.Context) error
|
Cancel(ctx context.Context) error
|
||||||
|
|
||||||
// Get a reader to the blob being written by this BlobWriter
|
|
||||||
Reader() (io.ReadCloser, error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// BlobService combines the operations to access, read and write blobs. This
|
// BlobService combines the operations to access, read and write blobs. This
|
||||||
|
|
|
@ -3,9 +3,6 @@ machine:
|
||||||
pre:
|
pre:
|
||||||
# Install gvm
|
# Install gvm
|
||||||
- bash < <(curl -s -S -L https://raw.githubusercontent.com/moovweb/gvm/1.0.22/binscripts/gvm-installer)
|
- bash < <(curl -s -S -L https://raw.githubusercontent.com/moovweb/gvm/1.0.22/binscripts/gvm-installer)
|
||||||
# Install ceph to test rados driver & create pool
|
|
||||||
- sudo -i ~/distribution/contrib/ceph/ci-setup.sh
|
|
||||||
- ceph osd pool create docker-distribution 1
|
|
||||||
# Install codecov for coverage
|
# Install codecov for coverage
|
||||||
- pip install --user codecov
|
- pip install --user codecov
|
||||||
|
|
||||||
|
@ -19,11 +16,9 @@ machine:
|
||||||
BASE_DIR: src/github.com/$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME
|
BASE_DIR: src/github.com/$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME
|
||||||
# Trick circle brainflat "no absolute path" behavior
|
# Trick circle brainflat "no absolute path" behavior
|
||||||
BASE_STABLE: ../../../$HOME/.gvm/pkgsets/stable/global/$BASE_DIR
|
BASE_STABLE: ../../../$HOME/.gvm/pkgsets/stable/global/$BASE_DIR
|
||||||
DOCKER_BUILDTAGS: "include_rados include_oss include_gcs"
|
DOCKER_BUILDTAGS: "include_oss include_gcs"
|
||||||
# Workaround Circle parsing dumb bugs and/or YAML wonkyness
|
# Workaround Circle parsing dumb bugs and/or YAML wonkyness
|
||||||
CIRCLE_PAIN: "mode: set"
|
CIRCLE_PAIN: "mode: set"
|
||||||
# Ceph config
|
|
||||||
RADOS_POOL: "docker-distribution"
|
|
||||||
|
|
||||||
hosts:
|
hosts:
|
||||||
# Not used yet
|
# Not used yet
|
||||||
|
|
|
@ -25,7 +25,7 @@ type Challenge struct {
|
||||||
type ChallengeManager interface {
|
type ChallengeManager interface {
|
||||||
// GetChallenges returns the challenges for the given
|
// GetChallenges returns the challenges for the given
|
||||||
// endpoint URL.
|
// endpoint URL.
|
||||||
GetChallenges(endpoint string) ([]Challenge, error)
|
GetChallenges(endpoint url.URL) ([]Challenge, error)
|
||||||
|
|
||||||
// AddResponse adds the response to the challenge
|
// AddResponse adds the response to the challenge
|
||||||
// manager. The challenges will be parsed out of
|
// manager. The challenges will be parsed out of
|
||||||
|
@ -48,8 +48,10 @@ func NewSimpleChallengeManager() ChallengeManager {
|
||||||
|
|
||||||
type simpleChallengeManager map[string][]Challenge
|
type simpleChallengeManager map[string][]Challenge
|
||||||
|
|
||||||
func (m simpleChallengeManager) GetChallenges(endpoint string) ([]Challenge, error) {
|
func (m simpleChallengeManager) GetChallenges(endpoint url.URL) ([]Challenge, error) {
|
||||||
challenges := m[endpoint]
|
endpoint.Host = strings.ToLower(endpoint.Host)
|
||||||
|
|
||||||
|
challenges := m[endpoint.String()]
|
||||||
return challenges, nil
|
return challenges, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,11 +62,10 @@ func (m simpleChallengeManager) AddResponse(resp *http.Response) error {
|
||||||
}
|
}
|
||||||
urlCopy := url.URL{
|
urlCopy := url.URL{
|
||||||
Path: resp.Request.URL.Path,
|
Path: resp.Request.URL.Path,
|
||||||
Host: resp.Request.URL.Host,
|
Host: strings.ToLower(resp.Request.URL.Host),
|
||||||
Scheme: resp.Request.URL.Scheme,
|
Scheme: resp.Request.URL.Scheme,
|
||||||
}
|
}
|
||||||
m[urlCopy.String()] = challenges
|
m[urlCopy.String()] = challenges
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,9 +15,15 @@ import (
|
||||||
"github.com/docker/distribution/registry/client/transport"
|
"github.com/docker/distribution/registry/client/transport"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrNoBasicAuthCredentials is returned if a request can't be authorized with
|
var (
|
||||||
// basic auth due to lack of credentials.
|
// ErrNoBasicAuthCredentials is returned if a request can't be authorized with
|
||||||
var ErrNoBasicAuthCredentials = errors.New("no basic auth credentials")
|
// basic auth due to lack of credentials.
|
||||||
|
ErrNoBasicAuthCredentials = errors.New("no basic auth credentials")
|
||||||
|
|
||||||
|
// ErrNoToken is returned if a request is successful but the body does not
|
||||||
|
// contain an authorization token.
|
||||||
|
ErrNoToken = errors.New("authorization server did not include a token in the response")
|
||||||
|
)
|
||||||
|
|
||||||
const defaultClientID = "registry-client"
|
const defaultClientID = "registry-client"
|
||||||
|
|
||||||
|
@ -77,9 +83,7 @@ func (ea *endpointAuthorizer) ModifyRequest(req *http.Request) error {
|
||||||
Path: req.URL.Path[:v2Root+4],
|
Path: req.URL.Path[:v2Root+4],
|
||||||
}
|
}
|
||||||
|
|
||||||
pingEndpoint := ping.String()
|
challenges, err := ea.challenges.GetChallenges(ping)
|
||||||
|
|
||||||
challenges, err := ea.challenges.GetChallenges(pingEndpoint)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -404,7 +408,7 @@ func (th *tokenHandler) fetchTokenWithBasicAuth(realm *url.URL, service string,
|
||||||
}
|
}
|
||||||
|
|
||||||
if tr.Token == "" {
|
if tr.Token == "" {
|
||||||
return "", time.Time{}, errors.New("authorization server did not include a token in the response")
|
return "", time.Time{}, ErrNoToken
|
||||||
}
|
}
|
||||||
|
|
||||||
if tr.ExpiresIn < minimumTokenLifetimeSeconds {
|
if tr.ExpiresIn < minimumTokenLifetimeSeconds {
|
||||||
|
|
|
@ -6,7 +6,6 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/docker/distribution"
|
"github.com/docker/distribution"
|
||||||
|
@ -104,21 +103,8 @@ func (hbu *httpBlobUpload) Write(p []byte) (n int, err error) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hbu *httpBlobUpload) Seek(offset int64, whence int) (int64, error) {
|
func (hbu *httpBlobUpload) Size() int64 {
|
||||||
newOffset := hbu.offset
|
return hbu.offset
|
||||||
|
|
||||||
switch whence {
|
|
||||||
case os.SEEK_CUR:
|
|
||||||
newOffset += int64(offset)
|
|
||||||
case os.SEEK_END:
|
|
||||||
newOffset += int64(offset)
|
|
||||||
case os.SEEK_SET:
|
|
||||||
newOffset = int64(offset)
|
|
||||||
}
|
|
||||||
|
|
||||||
hbu.offset = newOffset
|
|
||||||
|
|
||||||
return hbu.offset, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hbu *httpBlobUpload) ID() string {
|
func (hbu *httpBlobUpload) ID() string {
|
||||||
|
|
|
@ -2,6 +2,7 @@ package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
@ -10,6 +11,10 @@ import (
|
||||||
"github.com/docker/distribution/registry/api/errcode"
|
"github.com/docker/distribution/registry/api/errcode"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ErrNoErrorsInBody is returned when a HTTP response body parses to an empty
|
||||||
|
// errcode.Errors slice.
|
||||||
|
var ErrNoErrorsInBody = errors.New("no error details found in HTTP response body")
|
||||||
|
|
||||||
// UnexpectedHTTPStatusError is returned when an unexpected HTTP status is
|
// UnexpectedHTTPStatusError is returned when an unexpected HTTP status is
|
||||||
// returned when making a registry api call.
|
// returned when making a registry api call.
|
||||||
type UnexpectedHTTPStatusError struct {
|
type UnexpectedHTTPStatusError struct {
|
||||||
|
@ -17,18 +22,19 @@ type UnexpectedHTTPStatusError struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *UnexpectedHTTPStatusError) Error() string {
|
func (e *UnexpectedHTTPStatusError) Error() string {
|
||||||
return fmt.Sprintf("Received unexpected HTTP status: %s", e.Status)
|
return fmt.Sprintf("received unexpected HTTP status: %s", e.Status)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnexpectedHTTPResponseError is returned when an expected HTTP status code
|
// UnexpectedHTTPResponseError is returned when an expected HTTP status code
|
||||||
// is returned, but the content was unexpected and failed to be parsed.
|
// is returned, but the content was unexpected and failed to be parsed.
|
||||||
type UnexpectedHTTPResponseError struct {
|
type UnexpectedHTTPResponseError struct {
|
||||||
ParseErr error
|
ParseErr error
|
||||||
|
StatusCode int
|
||||||
Response []byte
|
Response []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *UnexpectedHTTPResponseError) Error() string {
|
func (e *UnexpectedHTTPResponseError) Error() string {
|
||||||
return fmt.Sprintf("Error parsing HTTP response: %s: %q", e.ParseErr.Error(), string(e.Response))
|
return fmt.Sprintf("error parsing HTTP %d response body: %s: %q", e.StatusCode, e.ParseErr.Error(), string(e.Response))
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseHTTPErrorResponse(statusCode int, r io.Reader) error {
|
func parseHTTPErrorResponse(statusCode int, r io.Reader) error {
|
||||||
|
@ -54,9 +60,21 @@ func parseHTTPErrorResponse(statusCode int, r io.Reader) error {
|
||||||
if err := json.Unmarshal(body, &errors); err != nil {
|
if err := json.Unmarshal(body, &errors); err != nil {
|
||||||
return &UnexpectedHTTPResponseError{
|
return &UnexpectedHTTPResponseError{
|
||||||
ParseErr: err,
|
ParseErr: err,
|
||||||
|
StatusCode: statusCode,
|
||||||
Response: body,
|
Response: body,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(errors) == 0 {
|
||||||
|
// If there was no error specified in the body, return
|
||||||
|
// UnexpectedHTTPResponseError.
|
||||||
|
return &UnexpectedHTTPResponseError{
|
||||||
|
ParseErr: ErrNoErrorsInBody,
|
||||||
|
StatusCode: statusCode,
|
||||||
|
Response: body,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return errors
|
return errors
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -308,6 +308,7 @@ check:
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return distribution.Descriptor{}, err
|
return distribution.Descriptor{}, err
|
||||||
}
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case resp.StatusCode >= 200 && resp.StatusCode < 400:
|
case resp.StatusCode >= 200 && resp.StatusCode < 400:
|
||||||
|
|
Loading…
Reference in New Issue