podman
182 строки · 4.8 Кб
1// Copyright 2015 go-swagger maintainers
2//
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
15package errors16
17import (18"encoding/json"19"fmt"20"net/http"21"reflect"22"strings"23)
24
25// DefaultHTTPCode is used when the error Code cannot be used as an HTTP code.
26var DefaultHTTPCode = http.StatusUnprocessableEntity27
28// Error represents a error interface all swagger framework errors implement
29type Error interface {30error31Code() int3232}
33
34type apiError struct {35code int3236message string37}
38
39func (a *apiError) Error() string {40return a.message41}
42
43func (a *apiError) Code() int32 {44return a.code45}
46
47// MarshalJSON implements the JSON encoding interface
48func (a apiError) MarshalJSON() ([]byte, error) {49return json.Marshal(map[string]interface{}{50"code": a.code,51"message": a.message,52})53}
54
55// New creates a new API error with a code and a message
56func New(code int32, message string, args ...interface{}) Error {57if len(args) > 0 {58return &apiError{code, fmt.Sprintf(message, args...)}59}60return &apiError{code, message}61}
62
63// NotFound creates a new not found error
64func NotFound(message string, args ...interface{}) Error {65if message == "" {66message = "Not found"67}68return New(http.StatusNotFound, fmt.Sprintf(message, args...))69}
70
71// NotImplemented creates a new not implemented error
72func NotImplemented(message string) Error {73return New(http.StatusNotImplemented, message)74}
75
76// MethodNotAllowedError represents an error for when the path matches but the method doesn't
77type MethodNotAllowedError struct {78code int3279Allowed []string80message string81}
82
83func (m *MethodNotAllowedError) Error() string {84return m.message85}
86
87// Code the error code
88func (m *MethodNotAllowedError) Code() int32 {89return m.code90}
91
92// MarshalJSON implements the JSON encoding interface
93func (m MethodNotAllowedError) MarshalJSON() ([]byte, error) {94return json.Marshal(map[string]interface{}{95"code": m.code,96"message": m.message,97"allowed": m.Allowed,98})99}
100
101func errorAsJSON(err Error) []byte {102//nolint:errchkjson103b, _ := json.Marshal(struct {104Code int32 `json:"code"`105Message string `json:"message"`106}{err.Code(), err.Error()})107return b108}
109
110func flattenComposite(errs *CompositeError) *CompositeError {111var res []error112for _, er := range errs.Errors {113switch e := er.(type) {114case *CompositeError:115if e != nil && len(e.Errors) > 0 {116flat := flattenComposite(e)117if len(flat.Errors) > 0 {118res = append(res, flat.Errors...)119}120}121default:122if e != nil {123res = append(res, e)124}125}126}127return CompositeValidationError(res...)128}
129
130// MethodNotAllowed creates a new method not allowed error
131func MethodNotAllowed(requested string, allow []string) Error {132msg := fmt.Sprintf("method %s is not allowed, but [%s] are", requested, strings.Join(allow, ","))133return &MethodNotAllowedError{code: http.StatusMethodNotAllowed, Allowed: allow, message: msg}134}
135
136// ServeError the error handler interface implementation
137func ServeError(rw http.ResponseWriter, r *http.Request, err error) {138rw.Header().Set("Content-Type", "application/json")139switch e := err.(type) {140case *CompositeError:141er := flattenComposite(e)142// strips composite errors to first element only143if len(er.Errors) > 0 {144ServeError(rw, r, er.Errors[0])145} else {146// guard against empty CompositeError (invalid construct)147ServeError(rw, r, nil)148}149case *MethodNotAllowedError:150rw.Header().Add("Allow", strings.Join(e.Allowed, ","))151rw.WriteHeader(asHTTPCode(int(e.Code())))152if r == nil || r.Method != http.MethodHead {153_, _ = rw.Write(errorAsJSON(e))154}155case Error:156value := reflect.ValueOf(e)157if value.Kind() == reflect.Ptr && value.IsNil() {158rw.WriteHeader(http.StatusInternalServerError)159_, _ = rw.Write(errorAsJSON(New(http.StatusInternalServerError, "Unknown error")))160return161}162rw.WriteHeader(asHTTPCode(int(e.Code())))163if r == nil || r.Method != http.MethodHead {164_, _ = rw.Write(errorAsJSON(e))165}166case nil:167rw.WriteHeader(http.StatusInternalServerError)168_, _ = rw.Write(errorAsJSON(New(http.StatusInternalServerError, "Unknown error")))169default:170rw.WriteHeader(http.StatusInternalServerError)171if r == nil || r.Method != http.MethodHead {172_, _ = rw.Write(errorAsJSON(New(http.StatusInternalServerError, err.Error())))173}174}175}
176
177func asHTTPCode(input int) int {178if input >= 600 {179return DefaultHTTPCode180}181return input182}
183