github.com/opcr-io/oras-go/v2@v2.0.0-20231122155130-eb4260d8a0ae/registry/remote/errcode/errors.go (about)

     1  /*
     2  Copyright The ORAS Authors.
     3  Licensed under the Apache License, Version 2.0 (the "License");
     4  you may not use this file except in compliance with the License.
     5  You may obtain a copy of the License at
     6  
     7  http://www.apache.org/licenses/LICENSE-2.0
     8  
     9  Unless required by applicable law or agreed to in writing, software
    10  distributed under the License is distributed on an "AS IS" BASIS,
    11  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  See the License for the specific language governing permissions and
    13  limitations under the License.
    14  */
    15  
    16  package errcode
    17  
    18  import (
    19  	"fmt"
    20  	"net/http"
    21  	"net/url"
    22  	"strings"
    23  	"unicode"
    24  )
    25  
    26  // References:
    27  //   - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc1/spec.md#error-codes
    28  //   - https://docs.docker.com/registry/spec/api/#errors-2
    29  const (
    30  	ErrorCodeBlobUnknown         = "BLOB_UNKNOWN"
    31  	ErrorCodeBlobUploadInvalid   = "BLOB_UPLOAD_INVALID"
    32  	ErrorCodeBlobUploadUnknown   = "BLOB_UPLOAD_UNKNOWN"
    33  	ErrorCodeDigestInvalid       = "DIGEST_INVALID"
    34  	ErrorCodeManifestBlobUnknown = "MANIFEST_BLOB_UNKNOWN"
    35  	ErrorCodeManifestInvalid     = "MANIFEST_INVALID"
    36  	ErrorCodeManifestUnknown     = "MANIFEST_UNKNOWN"
    37  	ErrorCodeNameInvalid         = "NAME_INVALID"
    38  	ErrorCodeNameUnknown         = "NAME_UNKNOWN"
    39  	ErrorCodeSizeInvalid         = "SIZE_INVALID"
    40  	ErrorCodeUnauthorized        = "UNAUTHORIZED"
    41  	ErrorCodeDenied              = "DENIED"
    42  	ErrorCodeUnsupported         = "UNSUPPORTED"
    43  )
    44  
    45  // Error represents a response inner error returned by the remote
    46  // registry.
    47  // References:
    48  //   - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc1/spec.md#error-codes
    49  //   - https://docs.docker.com/registry/spec/api/#errors-2
    50  type Error struct {
    51  	Code    string `json:"code"`
    52  	Message string `json:"message"`
    53  	Detail  any    `json:"detail,omitempty"`
    54  }
    55  
    56  // Error returns a error string describing the error.
    57  func (e Error) Error() string {
    58  	code := strings.Map(func(r rune) rune {
    59  		if r == '_' {
    60  			return ' '
    61  		}
    62  		return unicode.ToLower(r)
    63  	}, e.Code)
    64  	if e.Message == "" {
    65  		return code
    66  	}
    67  	if e.Detail == nil {
    68  		return fmt.Sprintf("%s: %s", code, e.Message)
    69  	}
    70  	return fmt.Sprintf("%s: %s: %v", code, e.Message, e.Detail)
    71  }
    72  
    73  // Errors represents a list of response inner errors returned by the remote
    74  // server.
    75  // References:
    76  //   - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc1/spec.md#error-codes
    77  //   - https://docs.docker.com/registry/spec/api/#errors-2
    78  type Errors []Error
    79  
    80  // Error returns a error string describing the error.
    81  func (errs Errors) Error() string {
    82  	switch len(errs) {
    83  	case 0:
    84  		return "<nil>"
    85  	case 1:
    86  		return errs[0].Error()
    87  	}
    88  	var errmsgs []string
    89  	for _, err := range errs {
    90  		errmsgs = append(errmsgs, err.Error())
    91  	}
    92  	return strings.Join(errmsgs, "; ")
    93  }
    94  
    95  // Unwrap returns the inner error only when there is exactly one error.
    96  func (errs Errors) Unwrap() error {
    97  	if len(errs) == 1 {
    98  		return errs[0]
    99  	}
   100  	return nil
   101  }
   102  
   103  // ErrorResponse represents an error response.
   104  type ErrorResponse struct {
   105  	Method     string
   106  	URL        *url.URL
   107  	StatusCode int
   108  	Errors     Errors
   109  }
   110  
   111  // Error returns a error string describing the error.
   112  func (err *ErrorResponse) Error() string {
   113  	var errmsg string
   114  	if len(err.Errors) > 0 {
   115  		errmsg = err.Errors.Error()
   116  	} else {
   117  		errmsg = http.StatusText(err.StatusCode)
   118  	}
   119  	return fmt.Sprintf("%s %q: response status code %d: %s", err.Method, err.URL, err.StatusCode, errmsg)
   120  }
   121  
   122  // Unwrap returns the internal errors of err if any.
   123  func (err *ErrorResponse) Unwrap() error {
   124  	if len(err.Errors) == 0 {
   125  		return nil
   126  	}
   127  	return err.Errors
   128  }