podman

Форк
0
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

15
package errors
16

17
import (
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.
26
var DefaultHTTPCode = http.StatusUnprocessableEntity
27

28
// Error represents a error interface all swagger framework errors implement
29
type Error interface {
30
	error
31
	Code() int32
32
}
33

34
type apiError struct {
35
	code    int32
36
	message string
37
}
38

39
func (a *apiError) Error() string {
40
	return a.message
41
}
42

43
func (a *apiError) Code() int32 {
44
	return a.code
45
}
46

47
// MarshalJSON implements the JSON encoding interface
48
func (a apiError) MarshalJSON() ([]byte, error) {
49
	return 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
56
func New(code int32, message string, args ...interface{}) Error {
57
	if len(args) > 0 {
58
		return &apiError{code, fmt.Sprintf(message, args...)}
59
	}
60
	return &apiError{code, message}
61
}
62

63
// NotFound creates a new not found error
64
func NotFound(message string, args ...interface{}) Error {
65
	if message == "" {
66
		message = "Not found"
67
	}
68
	return New(http.StatusNotFound, fmt.Sprintf(message, args...))
69
}
70

71
// NotImplemented creates a new not implemented error
72
func NotImplemented(message string) Error {
73
	return New(http.StatusNotImplemented, message)
74
}
75

76
// MethodNotAllowedError represents an error for when the path matches but the method doesn't
77
type MethodNotAllowedError struct {
78
	code    int32
79
	Allowed []string
80
	message string
81
}
82

83
func (m *MethodNotAllowedError) Error() string {
84
	return m.message
85
}
86

87
// Code the error code
88
func (m *MethodNotAllowedError) Code() int32 {
89
	return m.code
90
}
91

92
// MarshalJSON implements the JSON encoding interface
93
func (m MethodNotAllowedError) MarshalJSON() ([]byte, error) {
94
	return json.Marshal(map[string]interface{}{
95
		"code":    m.code,
96
		"message": m.message,
97
		"allowed": m.Allowed,
98
	})
99
}
100

101
func errorAsJSON(err Error) []byte {
102
	//nolint:errchkjson
103
	b, _ := json.Marshal(struct {
104
		Code    int32  `json:"code"`
105
		Message string `json:"message"`
106
	}{err.Code(), err.Error()})
107
	return b
108
}
109

110
func flattenComposite(errs *CompositeError) *CompositeError {
111
	var res []error
112
	for _, er := range errs.Errors {
113
		switch e := er.(type) {
114
		case *CompositeError:
115
			if e != nil && len(e.Errors) > 0 {
116
				flat := flattenComposite(e)
117
				if len(flat.Errors) > 0 {
118
					res = append(res, flat.Errors...)
119
				}
120
			}
121
		default:
122
			if e != nil {
123
				res = append(res, e)
124
			}
125
		}
126
	}
127
	return CompositeValidationError(res...)
128
}
129

130
// MethodNotAllowed creates a new method not allowed error
131
func MethodNotAllowed(requested string, allow []string) Error {
132
	msg := fmt.Sprintf("method %s is not allowed, but [%s] are", requested, strings.Join(allow, ","))
133
	return &MethodNotAllowedError{code: http.StatusMethodNotAllowed, Allowed: allow, message: msg}
134
}
135

136
// ServeError the error handler interface implementation
137
func ServeError(rw http.ResponseWriter, r *http.Request, err error) {
138
	rw.Header().Set("Content-Type", "application/json")
139
	switch e := err.(type) {
140
	case *CompositeError:
141
		er := flattenComposite(e)
142
		// strips composite errors to first element only
143
		if len(er.Errors) > 0 {
144
			ServeError(rw, r, er.Errors[0])
145
		} else {
146
			// guard against empty CompositeError (invalid construct)
147
			ServeError(rw, r, nil)
148
		}
149
	case *MethodNotAllowedError:
150
		rw.Header().Add("Allow", strings.Join(e.Allowed, ","))
151
		rw.WriteHeader(asHTTPCode(int(e.Code())))
152
		if r == nil || r.Method != http.MethodHead {
153
			_, _ = rw.Write(errorAsJSON(e))
154
		}
155
	case Error:
156
		value := reflect.ValueOf(e)
157
		if value.Kind() == reflect.Ptr && value.IsNil() {
158
			rw.WriteHeader(http.StatusInternalServerError)
159
			_, _ = rw.Write(errorAsJSON(New(http.StatusInternalServerError, "Unknown error")))
160
			return
161
		}
162
		rw.WriteHeader(asHTTPCode(int(e.Code())))
163
		if r == nil || r.Method != http.MethodHead {
164
			_, _ = rw.Write(errorAsJSON(e))
165
		}
166
	case nil:
167
		rw.WriteHeader(http.StatusInternalServerError)
168
		_, _ = rw.Write(errorAsJSON(New(http.StatusInternalServerError, "Unknown error")))
169
	default:
170
		rw.WriteHeader(http.StatusInternalServerError)
171
		if r == nil || r.Method != http.MethodHead {
172
			_, _ = rw.Write(errorAsJSON(New(http.StatusInternalServerError, err.Error())))
173
		}
174
	}
175
}
176

177
func asHTTPCode(input int) int {
178
	if input >= 600 {
179
		return DefaultHTTPCode
180
	}
181
	return input
182
}
183

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.