mirror of
https://github.com/distribution/distribution.git
synced 2025-06-26 23:39:39 +00:00
Merge 49c4d26b24
into 97495e5397
This commit is contained in:
commit
22a55d9387
@ -44,7 +44,6 @@ func parseHTTPErrorResponse(resp *http.Response) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
statusCode := resp.StatusCode
|
||||
|
||||
// A HEAD request for example validly does not contain any body, while
|
||||
@ -53,6 +52,10 @@ func parseHTTPErrorResponse(resp *http.Response) error {
|
||||
return makeError(statusCode, "")
|
||||
}
|
||||
|
||||
if statusCode == 401 {
|
||||
return makeError(statusCode, string(body))
|
||||
}
|
||||
|
||||
ctHeader := resp.Header.Get("Content-Type")
|
||||
if ctHeader == "" {
|
||||
return makeError(statusCode, string(body))
|
||||
@ -101,13 +104,13 @@ func parseHTTPErrorResponse(resp *http.Response) error {
|
||||
func makeError(statusCode int, details string) error {
|
||||
switch statusCode {
|
||||
case http.StatusUnauthorized:
|
||||
return errcode.ErrorCodeUnauthorized.WithMessage(details)
|
||||
return errcode.ErrorCodeUnauthorized.WithMessageStatusCode(details, statusCode)
|
||||
case http.StatusForbidden:
|
||||
return errcode.ErrorCodeDenied.WithMessage(details)
|
||||
return errcode.ErrorCodeDenied.WithMessageStatusCode(details, statusCode)
|
||||
case http.StatusTooManyRequests:
|
||||
return errcode.ErrorCodeTooManyRequests.WithMessage(details)
|
||||
return errcode.ErrorCodeTooManyRequests.WithMessageStatusCode(details, statusCode)
|
||||
default:
|
||||
return errcode.ErrorCodeUnknown.WithMessage(details)
|
||||
return errcode.ErrorCodeUnknown.WithMessageStatusCode(details, statusCode)
|
||||
}
|
||||
}
|
||||
|
||||
@ -138,6 +141,7 @@ func HandleHTTPResponseError(resp *http.Response) error {
|
||||
for _, c := range challenge.ResponseChallenges(resp) {
|
||||
if c.Scheme == "bearer" {
|
||||
var err errcode.Error
|
||||
err.StatusCode = resp.StatusCode
|
||||
// codes defined at https://tools.ietf.org/html/rfc6750#section-3.1
|
||||
switch c.Parameters["error"] {
|
||||
case "invalid_token":
|
||||
|
@ -78,6 +78,16 @@ func (ec ErrorCode) WithMessage(message string) Error {
|
||||
}
|
||||
}
|
||||
|
||||
// WithMessage creates a new Error struct based on the passed-in info and
|
||||
// overrides the Message property.
|
||||
func (ec ErrorCode) WithMessageStatusCode(message string, statusCode int) Error {
|
||||
return Error{
|
||||
Code: ec,
|
||||
Message: message,
|
||||
StatusCode: statusCode,
|
||||
}
|
||||
}
|
||||
|
||||
// WithDetail creates a new Error struct based on the passed-in info and
|
||||
// set the Detail property appropriately
|
||||
func (ec ErrorCode) WithDetail(detail interface{}) Error {
|
||||
@ -100,7 +110,7 @@ type Error struct {
|
||||
Code ErrorCode `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Detail interface{} `json:"detail,omitempty"`
|
||||
|
||||
StatusCode int `json:"statusCode"`
|
||||
// TODO(duglin): See if we need an "args" property so we can do the
|
||||
// variable substitution right before showing the message to the user
|
||||
}
|
||||
@ -122,6 +132,7 @@ func (e Error) Error() string {
|
||||
func (e Error) WithDetail(detail interface{}) Error {
|
||||
return Error{
|
||||
Code: e.Code,
|
||||
StatusCode: e.StatusCode,
|
||||
Message: e.Message,
|
||||
Detail: detail,
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package handlers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"mime"
|
||||
"net/http"
|
||||
@ -142,6 +143,8 @@ func (imh *manifestHandler) GetManifest(w http.ResponseWriter, r *http.Request)
|
||||
if err != nil {
|
||||
if _, ok := err.(distribution.ErrManifestUnknownRevision); ok {
|
||||
imh.Errors = append(imh.Errors, errcode.ErrorCodeManifestUnknown.WithDetail(err))
|
||||
} else if checkAllErrorsStatusCode(err, 401) {
|
||||
imh.Errors = append(imh.Errors, errcode.ErrorCodeUnauthorized.WithDetail(err))
|
||||
} else {
|
||||
imh.Errors = append(imh.Errors, errcode.ErrorCodeUnknown.WithDetail(err))
|
||||
}
|
||||
@ -225,6 +228,21 @@ func (imh *manifestHandler) GetManifest(w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
}
|
||||
|
||||
func checkAllErrorsStatusCode(err error, statusCode int) bool {
|
||||
var errs errcode.Errors
|
||||
if !errors.As(err, &errs) {
|
||||
return false
|
||||
}
|
||||
for _, e := range errs {
|
||||
var specificErr errcode.Error
|
||||
ok := errors.As(e, &specificErr)
|
||||
if !ok || specificErr.StatusCode != statusCode {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func etagMatch(r *http.Request, etag string) bool {
|
||||
for _, headerVal := range r.Header["If-None-Match"] {
|
||||
if headerVal == etag || headerVal == fmt.Sprintf(`"%s"`, etag) { // allow quoted or unquoted
|
||||
|
Loading…
Reference in New Issue
Block a user