Handle nonstandard token endpoint errors
https://github.com/docker/distribution/pull/1249 changed token fetching to parse HTTP error response bodies as serialized errcodes. However, Docker Hub's authentication endpoint does not return error bodies in this format. To work around this, convert its format into ErrCodeUnauthorized or ErrCodeUnknown. Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
This commit is contained in:
parent
05b8317291
commit
59254013be
2 changed files with 25 additions and 3 deletions
|
@ -69,6 +69,15 @@ func (ec *ErrorCode) UnmarshalText(text []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithMessage creates a new Error struct based on the passed-in info and
|
||||||
|
// overrides the Message property.
|
||||||
|
func (ec ErrorCode) WithMessage(message string) Error {
|
||||||
|
return Error{
|
||||||
|
Code: ec,
|
||||||
|
Message: message,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// WithDetail creates a new Error struct based on the passed-in info and
|
// WithDetail creates a new Error struct based on the passed-in info and
|
||||||
// set the Detail property appropriately
|
// set the Detail property appropriately
|
||||||
func (ec ErrorCode) WithDetail(detail interface{}) Error {
|
func (ec ErrorCode) WithDetail(detail interface{}) Error {
|
||||||
|
|
|
@ -31,13 +31,26 @@ 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 response: %s: %q", e.ParseErr.Error(), string(e.Response))
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseHTTPErrorResponse(r io.Reader) error {
|
func parseHTTPErrorResponse(statusCode int, r io.Reader) error {
|
||||||
var errors errcode.Errors
|
var errors errcode.Errors
|
||||||
body, err := ioutil.ReadAll(r)
|
body, err := ioutil.ReadAll(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For backward compatibility, handle irregularly formatted
|
||||||
|
// messages that contain a "details" field.
|
||||||
|
var detailsErr struct {
|
||||||
|
Details string `json:"details"`
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(body, &detailsErr)
|
||||||
|
if err == nil && detailsErr.Details != "" {
|
||||||
|
if statusCode == http.StatusUnauthorized {
|
||||||
|
return errcode.ErrorCodeUnauthorized.WithMessage(detailsErr.Details)
|
||||||
|
}
|
||||||
|
return errcode.ErrorCodeUnknown.WithMessage(detailsErr.Details)
|
||||||
|
}
|
||||||
|
|
||||||
if err := json.Unmarshal(body, &errors); err != nil {
|
if err := json.Unmarshal(body, &errors); err != nil {
|
||||||
return &UnexpectedHTTPResponseError{
|
return &UnexpectedHTTPResponseError{
|
||||||
ParseErr: err,
|
ParseErr: err,
|
||||||
|
@ -53,14 +66,14 @@ func parseHTTPErrorResponse(r io.Reader) error {
|
||||||
// range.
|
// range.
|
||||||
func HandleErrorResponse(resp *http.Response) error {
|
func HandleErrorResponse(resp *http.Response) error {
|
||||||
if resp.StatusCode == 401 {
|
if resp.StatusCode == 401 {
|
||||||
err := parseHTTPErrorResponse(resp.Body)
|
err := parseHTTPErrorResponse(resp.StatusCode, resp.Body)
|
||||||
if uErr, ok := err.(*UnexpectedHTTPResponseError); ok {
|
if uErr, ok := err.(*UnexpectedHTTPResponseError); ok {
|
||||||
return errcode.ErrorCodeUnauthorized.WithDetail(uErr.Response)
|
return errcode.ErrorCodeUnauthorized.WithDetail(uErr.Response)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if resp.StatusCode >= 400 && resp.StatusCode < 500 {
|
if resp.StatusCode >= 400 && resp.StatusCode < 500 {
|
||||||
return parseHTTPErrorResponse(resp.Body)
|
return parseHTTPErrorResponse(resp.StatusCode, resp.Body)
|
||||||
}
|
}
|
||||||
return &UnexpectedHTTPStatusError{Status: resp.Status}
|
return &UnexpectedHTTPStatusError{Status: resp.Status}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue