forked from TrueCloudLab/distribution
Merge pull request #1249 from k4leung4/print-error-msg
Print error for failed HTTP auth request.
This commit is contained in:
commit
5529baa918
5 changed files with 108 additions and 14 deletions
|
@ -240,7 +240,8 @@ func (th *tokenHandler) fetchToken(params map[string]string) (token *tokenRespon
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
if !client.SuccessStatus(resp.StatusCode) {
|
if !client.SuccessStatus(resp.StatusCode) {
|
||||||
return nil, fmt.Errorf("token auth attempt for registry: %s request failed with status: %d %s", req.URL, resp.StatusCode, http.StatusText(resp.StatusCode))
|
err := client.HandleErrorResponse(resp)
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
decoder := json.NewDecoder(resp.Body)
|
decoder := json.NewDecoder(resp.Body)
|
||||||
|
|
|
@ -33,7 +33,7 @@ func (hbu *httpBlobUpload) handleErrorResponse(resp *http.Response) error {
|
||||||
if resp.StatusCode == http.StatusNotFound {
|
if resp.StatusCode == http.StatusNotFound {
|
||||||
return distribution.ErrBlobUploadUnknown
|
return distribution.ErrBlobUploadUnknown
|
||||||
}
|
}
|
||||||
return handleErrorResponse(resp)
|
return HandleErrorResponse(resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hbu *httpBlobUpload) ReadFrom(r io.Reader) (n int64, err error) {
|
func (hbu *httpBlobUpload) ReadFrom(r io.Reader) (n int64, err error) {
|
||||||
|
|
|
@ -47,7 +47,11 @@ func parseHTTPErrorResponse(r io.Reader) error {
|
||||||
return errors
|
return errors
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleErrorResponse(resp *http.Response) error {
|
// HandleErrorResponse returns error parsed from HTTP response for an
|
||||||
|
// unsuccessful HTTP response code (in the range 400 - 499 inclusive). An
|
||||||
|
// UnexpectedHTTPStatusError returned for response code outside of expected
|
||||||
|
// range.
|
||||||
|
func HandleErrorResponse(resp *http.Response) error {
|
||||||
if resp.StatusCode == 401 {
|
if resp.StatusCode == 401 {
|
||||||
err := parseHTTPErrorResponse(resp.Body)
|
err := parseHTTPErrorResponse(resp.Body)
|
||||||
if uErr, ok := err.(*UnexpectedHTTPResponseError); ok {
|
if uErr, ok := err.(*UnexpectedHTTPResponseError); ok {
|
||||||
|
|
89
docs/client/errors_test.go
Normal file
89
docs/client/errors_test.go
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
type nopCloser struct {
|
||||||
|
io.Reader
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nopCloser) Close() error { return nil }
|
||||||
|
|
||||||
|
func TestHandleErrorResponse401ValidBody(t *testing.T) {
|
||||||
|
json := "{\"errors\":[{\"code\":\"UNAUTHORIZED\",\"message\":\"action requires authentication\"}]}"
|
||||||
|
response := &http.Response{
|
||||||
|
Status: "401 Unauthorized",
|
||||||
|
StatusCode: 401,
|
||||||
|
Body: nopCloser{bytes.NewBufferString(json)},
|
||||||
|
}
|
||||||
|
err := HandleErrorResponse(response)
|
||||||
|
|
||||||
|
expectedMsg := "unauthorized: action requires authentication"
|
||||||
|
if !strings.Contains(err.Error(), expectedMsg) {
|
||||||
|
t.Errorf("Expected \"%s\", got: \"%s\"", expectedMsg, err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleErrorResponse401WithInvalidBody(t *testing.T) {
|
||||||
|
json := "{invalid json}"
|
||||||
|
response := &http.Response{
|
||||||
|
Status: "401 Unauthorized",
|
||||||
|
StatusCode: 401,
|
||||||
|
Body: nopCloser{bytes.NewBufferString(json)},
|
||||||
|
}
|
||||||
|
err := HandleErrorResponse(response)
|
||||||
|
|
||||||
|
expectedMsg := "unauthorized: authentication required"
|
||||||
|
if !strings.Contains(err.Error(), expectedMsg) {
|
||||||
|
t.Errorf("Expected \"%s\", got: \"%s\"", expectedMsg, err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleErrorResponseExpectedStatusCode400ValidBody(t *testing.T) {
|
||||||
|
json := "{\"errors\":[{\"code\":\"DIGEST_INVALID\",\"message\":\"provided digest does not match\"}]}"
|
||||||
|
response := &http.Response{
|
||||||
|
Status: "400 Bad Request",
|
||||||
|
StatusCode: 400,
|
||||||
|
Body: nopCloser{bytes.NewBufferString(json)},
|
||||||
|
}
|
||||||
|
err := HandleErrorResponse(response)
|
||||||
|
|
||||||
|
expectedMsg := "digest invalid: provided digest does not match"
|
||||||
|
if !strings.Contains(err.Error(), expectedMsg) {
|
||||||
|
t.Errorf("Expected \"%s\", got: \"%s\"", expectedMsg, err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleErrorResponseExpectedStatusCode404InvalidBody(t *testing.T) {
|
||||||
|
json := "{invalid json}"
|
||||||
|
response := &http.Response{
|
||||||
|
Status: "404 Not Found",
|
||||||
|
StatusCode: 404,
|
||||||
|
Body: nopCloser{bytes.NewBufferString(json)},
|
||||||
|
}
|
||||||
|
err := HandleErrorResponse(response)
|
||||||
|
|
||||||
|
expectedMsg := "Error parsing HTTP response: invalid character 'i' looking for beginning of object key string: \"{invalid json}\""
|
||||||
|
if !strings.Contains(err.Error(), expectedMsg) {
|
||||||
|
t.Errorf("Expected \"%s\", got: \"%s\"", expectedMsg, err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleErrorResponseUnexpectedStatusCode501(t *testing.T) {
|
||||||
|
response := &http.Response{
|
||||||
|
Status: "501 Not Implemented",
|
||||||
|
StatusCode: 501,
|
||||||
|
Body: nopCloser{bytes.NewBufferString("{\"Error Encountered\" : \"Function not implemented.\"}")},
|
||||||
|
}
|
||||||
|
err := HandleErrorResponse(response)
|
||||||
|
|
||||||
|
expectedMsg := "Received unexpected HTTP status: 501 Not Implemented"
|
||||||
|
if !strings.Contains(err.Error(), expectedMsg) {
|
||||||
|
t.Errorf("Expected \"%s\", got: \"%s\"", expectedMsg, err.Error())
|
||||||
|
}
|
||||||
|
}
|
|
@ -91,7 +91,7 @@ func (r *registry) Repositories(ctx context.Context, entries []string, last stri
|
||||||
returnErr = io.EOF
|
returnErr = io.EOF
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return 0, handleErrorResponse(resp)
|
return 0, HandleErrorResponse(resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
return numFilled, returnErr
|
return numFilled, returnErr
|
||||||
|
@ -203,7 +203,7 @@ func (t *tags) All(ctx context.Context) ([]string, error) {
|
||||||
tags = tagsResponse.Tags
|
tags = tagsResponse.Tags
|
||||||
return tags, nil
|
return tags, nil
|
||||||
}
|
}
|
||||||
return tags, handleErrorResponse(resp)
|
return tags, HandleErrorResponse(resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
func descriptorFromResponse(response *http.Response) (distribution.Descriptor, error) {
|
func descriptorFromResponse(response *http.Response) (distribution.Descriptor, error) {
|
||||||
|
@ -276,7 +276,7 @@ check:
|
||||||
}
|
}
|
||||||
goto check
|
goto check
|
||||||
default:
|
default:
|
||||||
return distribution.Descriptor{}, handleErrorResponse(resp)
|
return distribution.Descriptor{}, HandleErrorResponse(resp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -315,7 +315,7 @@ func (ms *manifests) Exists(ctx context.Context, dgst digest.Digest) (bool, erro
|
||||||
} else if resp.StatusCode == http.StatusNotFound {
|
} else if resp.StatusCode == http.StatusNotFound {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
return false, handleErrorResponse(resp)
|
return false, HandleErrorResponse(resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddEtagToTag allows a client to supply an eTag to Get which will be
|
// AddEtagToTag allows a client to supply an eTag to Get which will be
|
||||||
|
@ -395,7 +395,7 @@ func (ms *manifests) Get(ctx context.Context, dgst digest.Digest, options ...dis
|
||||||
}
|
}
|
||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
return nil, handleErrorResponse(resp)
|
return nil, HandleErrorResponse(resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithTag allows a tag to be passed into Put which enables the client
|
// WithTag allows a tag to be passed into Put which enables the client
|
||||||
|
@ -462,7 +462,7 @@ func (ms *manifests) Put(ctx context.Context, m distribution.Manifest, options .
|
||||||
return dgst, nil
|
return dgst, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return "", handleErrorResponse(resp)
|
return "", HandleErrorResponse(resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms *manifests) Delete(ctx context.Context, dgst digest.Digest) error {
|
func (ms *manifests) Delete(ctx context.Context, dgst digest.Digest) error {
|
||||||
|
@ -484,7 +484,7 @@ func (ms *manifests) Delete(ctx context.Context, dgst digest.Digest) error {
|
||||||
if SuccessStatus(resp.StatusCode) {
|
if SuccessStatus(resp.StatusCode) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return handleErrorResponse(resp)
|
return HandleErrorResponse(resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo(richardscothern): Restore interface and implementation with merge of #1050
|
// todo(richardscothern): Restore interface and implementation with merge of #1050
|
||||||
|
@ -541,7 +541,7 @@ func (bs *blobs) Open(ctx context.Context, dgst digest.Digest) (distribution.Rea
|
||||||
if resp.StatusCode == http.StatusNotFound {
|
if resp.StatusCode == http.StatusNotFound {
|
||||||
return distribution.ErrBlobUnknown
|
return distribution.ErrBlobUnknown
|
||||||
}
|
}
|
||||||
return handleErrorResponse(resp)
|
return HandleErrorResponse(resp)
|
||||||
}), nil
|
}), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -597,7 +597,7 @@ func (bs *blobs) Create(ctx context.Context) (distribution.BlobWriter, error) {
|
||||||
location: location,
|
location: location,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
return nil, handleErrorResponse(resp)
|
return nil, HandleErrorResponse(resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bs *blobs) Resume(ctx context.Context, id string) (distribution.BlobWriter, error) {
|
func (bs *blobs) Resume(ctx context.Context, id string) (distribution.BlobWriter, error) {
|
||||||
|
@ -645,7 +645,7 @@ func (bs *blobStatter) Stat(ctx context.Context, dgst digest.Digest) (distributi
|
||||||
} else if resp.StatusCode == http.StatusNotFound {
|
} else if resp.StatusCode == http.StatusNotFound {
|
||||||
return distribution.Descriptor{}, distribution.ErrBlobUnknown
|
return distribution.Descriptor{}, distribution.ErrBlobUnknown
|
||||||
}
|
}
|
||||||
return distribution.Descriptor{}, handleErrorResponse(resp)
|
return distribution.Descriptor{}, HandleErrorResponse(resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildCatalogValues(maxEntries int, last string) url.Values {
|
func buildCatalogValues(maxEntries int, last string) url.Values {
|
||||||
|
@ -682,7 +682,7 @@ func (bs *blobStatter) Clear(ctx context.Context, dgst digest.Digest) error {
|
||||||
if SuccessStatus(resp.StatusCode) {
|
if SuccessStatus(resp.StatusCode) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return handleErrorResponse(resp)
|
return HandleErrorResponse(resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bs *blobStatter) SetDescriptor(ctx context.Context, dgst digest.Digest, desc distribution.Descriptor) error {
|
func (bs *blobStatter) SetDescriptor(ctx context.Context, dgst digest.Digest, desc distribution.Descriptor) error {
|
||||||
|
|
Loading…
Reference in a new issue