From e128a821db4f008d2b1744fd652be037ab46faa5 Mon Sep 17 00:00:00 2001
From: Kenny Leung <kleung@google.com>
Date: Tue, 8 Dec 2015 14:24:03 -0800
Subject: [PATCH 1/2] Print error for failed HTTP auth request.

Signed-off-by: Kenny Leung <kleung@google.com>
---
 registry/client/auth/session.go |  3 ++-
 registry/client/blob_writer.go  |  2 +-
 registry/client/errors.go       |  6 +++++-
 registry/client/repository.go   | 20 ++++++++++----------
 4 files changed, 18 insertions(+), 13 deletions(-)

diff --git a/registry/client/auth/session.go b/registry/client/auth/session.go
index 6c92fc34..8594b66f 100644
--- a/registry/client/auth/session.go
+++ b/registry/client/auth/session.go
@@ -240,7 +240,8 @@ func (th *tokenHandler) fetchToken(params map[string]string) (token *tokenRespon
 	defer resp.Body.Close()
 
 	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, fmt.Errorf("token auth attempt for registry: %s request failed with status: %d %s: %q", req.URL, resp.StatusCode, http.StatusText(resp.StatusCode), err)
 	}
 
 	decoder := json.NewDecoder(resp.Body)
diff --git a/registry/client/blob_writer.go b/registry/client/blob_writer.go
index c7eee4e8..21a018dc 100644
--- a/registry/client/blob_writer.go
+++ b/registry/client/blob_writer.go
@@ -33,7 +33,7 @@ func (hbu *httpBlobUpload) handleErrorResponse(resp *http.Response) error {
 	if resp.StatusCode == http.StatusNotFound {
 		return distribution.ErrBlobUploadUnknown
 	}
-	return handleErrorResponse(resp)
+	return HandleErrorResponse(resp)
 }
 
 func (hbu *httpBlobUpload) ReadFrom(r io.Reader) (n int64, err error) {
diff --git a/registry/client/errors.go b/registry/client/errors.go
index 7305c021..8e3cb108 100644
--- a/registry/client/errors.go
+++ b/registry/client/errors.go
@@ -47,7 +47,11 @@ func parseHTTPErrorResponse(r io.Reader) error {
 	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 {
 		err := parseHTTPErrorResponse(resp.Body)
 		if uErr, ok := err.(*UnexpectedHTTPResponseError); ok {
diff --git a/registry/client/repository.go b/registry/client/repository.go
index bb10ece7..421584ad 100644
--- a/registry/client/repository.go
+++ b/registry/client/repository.go
@@ -91,7 +91,7 @@ func (r *registry) Repositories(ctx context.Context, entries []string, last stri
 			returnErr = io.EOF
 		}
 	} else {
-		return 0, handleErrorResponse(resp)
+		return 0, HandleErrorResponse(resp)
 	}
 
 	return numFilled, returnErr
@@ -213,7 +213,7 @@ func (ms *manifests) Tags() ([]string, error) {
 
 		return tagsResponse.Tags, nil
 	}
-	return nil, handleErrorResponse(resp)
+	return nil, HandleErrorResponse(resp)
 }
 
 func (ms *manifests) Exists(dgst digest.Digest) (bool, error) {
@@ -238,7 +238,7 @@ func (ms *manifests) ExistsByTag(tag string) (bool, error) {
 	} else if resp.StatusCode == http.StatusNotFound {
 		return false, nil
 	}
-	return false, handleErrorResponse(resp)
+	return false, HandleErrorResponse(resp)
 }
 
 func (ms *manifests) Get(dgst digest.Digest) (*schema1.SignedManifest, error) {
@@ -297,7 +297,7 @@ func (ms *manifests) GetByTag(tag string, options ...distribution.ManifestServic
 		}
 		return &sm, nil
 	}
-	return nil, handleErrorResponse(resp)
+	return nil, HandleErrorResponse(resp)
 }
 
 func (ms *manifests) Put(m *schema1.SignedManifest) error {
@@ -323,7 +323,7 @@ func (ms *manifests) Put(m *schema1.SignedManifest) error {
 		// TODO(dmcgowan): make use of digest header
 		return nil
 	}
-	return handleErrorResponse(resp)
+	return HandleErrorResponse(resp)
 }
 
 func (ms *manifests) Delete(dgst digest.Digest) error {
@@ -345,7 +345,7 @@ func (ms *manifests) Delete(dgst digest.Digest) error {
 	if SuccessStatus(resp.StatusCode) {
 		return nil
 	}
-	return handleErrorResponse(resp)
+	return HandleErrorResponse(resp)
 }
 
 type blobs struct {
@@ -401,7 +401,7 @@ func (bs *blobs) Open(ctx context.Context, dgst digest.Digest) (distribution.Rea
 			if resp.StatusCode == http.StatusNotFound {
 				return distribution.ErrBlobUnknown
 			}
-			return handleErrorResponse(resp)
+			return HandleErrorResponse(resp)
 		}), nil
 }
 
@@ -457,7 +457,7 @@ func (bs *blobs) Create(ctx context.Context) (distribution.BlobWriter, error) {
 			location:  location,
 		}, nil
 	}
-	return nil, handleErrorResponse(resp)
+	return nil, HandleErrorResponse(resp)
 }
 
 func (bs *blobs) Resume(ctx context.Context, id string) (distribution.BlobWriter, error) {
@@ -505,7 +505,7 @@ func (bs *blobStatter) Stat(ctx context.Context, dgst digest.Digest) (distributi
 	} else if resp.StatusCode == http.StatusNotFound {
 		return distribution.Descriptor{}, distribution.ErrBlobUnknown
 	}
-	return distribution.Descriptor{}, handleErrorResponse(resp)
+	return distribution.Descriptor{}, HandleErrorResponse(resp)
 }
 
 func buildCatalogValues(maxEntries int, last string) url.Values {
@@ -542,7 +542,7 @@ func (bs *blobStatter) Clear(ctx context.Context, dgst digest.Digest) error {
 	if SuccessStatus(resp.StatusCode) {
 		return nil
 	}
-	return handleErrorResponse(resp)
+	return HandleErrorResponse(resp)
 }
 
 func (bs *blobStatter) SetDescriptor(ctx context.Context, dgst digest.Digest, desc distribution.Descriptor) error {

From c28278f7a2adfc98553284b052f2848a3df495b9 Mon Sep 17 00:00:00 2001
From: Kenny Leung <kleung@google.com>
Date: Tue, 8 Dec 2015 14:24:03 -0800
Subject: [PATCH 2/2] Print error for failed HTTP auth request.

Signed-off-by: Kenny Leung <kleung@google.com>
---
 registry/client/auth/session.go |  3 ++-
 registry/client/blob_writer.go  |  2 +-
 registry/client/errors.go       |  6 +++++-
 registry/client/repository.go   | 22 +++++++++++-----------
 4 files changed, 19 insertions(+), 14 deletions(-)

diff --git a/registry/client/auth/session.go b/registry/client/auth/session.go
index 6c92fc34..8594b66f 100644
--- a/registry/client/auth/session.go
+++ b/registry/client/auth/session.go
@@ -240,7 +240,8 @@ func (th *tokenHandler) fetchToken(params map[string]string) (token *tokenRespon
 	defer resp.Body.Close()
 
 	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, fmt.Errorf("token auth attempt for registry: %s request failed with status: %d %s: %q", req.URL, resp.StatusCode, http.StatusText(resp.StatusCode), err)
 	}
 
 	decoder := json.NewDecoder(resp.Body)
diff --git a/registry/client/blob_writer.go b/registry/client/blob_writer.go
index c7eee4e8..21a018dc 100644
--- a/registry/client/blob_writer.go
+++ b/registry/client/blob_writer.go
@@ -33,7 +33,7 @@ func (hbu *httpBlobUpload) handleErrorResponse(resp *http.Response) error {
 	if resp.StatusCode == http.StatusNotFound {
 		return distribution.ErrBlobUploadUnknown
 	}
-	return handleErrorResponse(resp)
+	return HandleErrorResponse(resp)
 }
 
 func (hbu *httpBlobUpload) ReadFrom(r io.Reader) (n int64, err error) {
diff --git a/registry/client/errors.go b/registry/client/errors.go
index 7305c021..8e3cb108 100644
--- a/registry/client/errors.go
+++ b/registry/client/errors.go
@@ -47,7 +47,11 @@ func parseHTTPErrorResponse(r io.Reader) error {
 	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 {
 		err := parseHTTPErrorResponse(resp.Body)
 		if uErr, ok := err.(*UnexpectedHTTPResponseError); ok {
diff --git a/registry/client/repository.go b/registry/client/repository.go
index 9d489dd5..758c6e5e 100644
--- a/registry/client/repository.go
+++ b/registry/client/repository.go
@@ -91,7 +91,7 @@ func (r *registry) Repositories(ctx context.Context, entries []string, last stri
 			returnErr = io.EOF
 		}
 	} else {
-		return 0, handleErrorResponse(resp)
+		return 0, HandleErrorResponse(resp)
 	}
 
 	return numFilled, returnErr
@@ -203,7 +203,7 @@ func (t *tags) All(ctx context.Context) ([]string, error) {
 		tags = tagsResponse.Tags
 		return tags, nil
 	}
-	return tags, handleErrorResponse(resp)
+	return tags, HandleErrorResponse(resp)
 }
 
 func descriptorFromResponse(response *http.Response) (distribution.Descriptor, error) {
@@ -276,7 +276,7 @@ check:
 		}
 		goto check
 	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 {
 		return false, nil
 	}
-	return false, handleErrorResponse(resp)
+	return false, HandleErrorResponse(resp)
 }
 
 // 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 nil, handleErrorResponse(resp)
+	return nil, HandleErrorResponse(resp)
 }
 
 // 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 "", handleErrorResponse(resp)
+	return "", HandleErrorResponse(resp)
 }
 
 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) {
 		return nil
 	}
-	return handleErrorResponse(resp)
+	return HandleErrorResponse(resp)
 }
 
 // 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 {
 				return distribution.ErrBlobUnknown
 			}
-			return handleErrorResponse(resp)
+			return HandleErrorResponse(resp)
 		}), nil
 }
 
@@ -597,7 +597,7 @@ func (bs *blobs) Create(ctx context.Context) (distribution.BlobWriter, error) {
 			location:  location,
 		}, nil
 	}
-	return nil, handleErrorResponse(resp)
+	return nil, HandleErrorResponse(resp)
 }
 
 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 {
 		return distribution.Descriptor{}, distribution.ErrBlobUnknown
 	}
-	return distribution.Descriptor{}, handleErrorResponse(resp)
+	return distribution.Descriptor{}, HandleErrorResponse(resp)
 }
 
 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) {
 		return nil
 	}
-	return handleErrorResponse(resp)
+	return HandleErrorResponse(resp)
 }
 
 func (bs *blobStatter) SetDescriptor(ctx context.Context, dgst digest.Digest, desc distribution.Descriptor) error {