podman

Форк
0
192 строки · 4.9 Кб
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{
59
			code:    code,
60
			message: fmt.Sprintf(message, args...),
61
		}
62
	}
63
	return &apiError{
64
		code:    code,
65
		message: message,
66
	}
67
}
68

69
// NotFound creates a new not found error
70
func NotFound(message string, args ...interface{}) Error {
71
	if message == "" {
72
		message = "Not found"
73
	}
74
	return New(http.StatusNotFound, fmt.Sprintf(message, args...))
75
}
76

77
// NotImplemented creates a new not implemented error
78
func NotImplemented(message string) Error {
79
	return New(http.StatusNotImplemented, message)
80
}
81

82
// MethodNotAllowedError represents an error for when the path matches but the method doesn't
83
type MethodNotAllowedError struct {
84
	code    int32
85
	Allowed []string
86
	message string
87
}
88

89
func (m *MethodNotAllowedError) Error() string {
90
	return m.message
91
}
92

93
// Code the error code
94
func (m *MethodNotAllowedError) Code() int32 {
95
	return m.code
96
}
97

98
// MarshalJSON implements the JSON encoding interface
99
func (m MethodNotAllowedError) MarshalJSON() ([]byte, error) {
100
	return json.Marshal(map[string]interface{}{
101
		"code":    m.code,
102
		"message": m.message,
103
		"allowed": m.Allowed,
104
	})
105
}
106

107
func errorAsJSON(err Error) []byte {
108
	//nolint:errchkjson
109
	b, _ := json.Marshal(struct {
110
		Code    int32  `json:"code"`
111
		Message string `json:"message"`
112
	}{err.Code(), err.Error()})
113
	return b
114
}
115

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

136
// MethodNotAllowed creates a new method not allowed error
137
func MethodNotAllowed(requested string, allow []string) Error {
138
	msg := fmt.Sprintf("method %s is not allowed, but [%s] are", requested, strings.Join(allow, ","))
139
	return &MethodNotAllowedError{
140
		code:    http.StatusMethodNotAllowed,
141
		Allowed: allow,
142
		message: msg,
143
	}
144
}
145

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

187
func asHTTPCode(input int) int {
188
	if input >= 600 {
189
		return DefaultHTTPCode
190
	}
191
	return input
192
}
193

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

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

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

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