podman

Форк
0
324 строки · 10.2 Кб
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 validate
16

17
// TODO: define this as package validate/internal
18
// This must be done while keeping CI intact with all tests and test coverage
19

20
import (
21
	"reflect"
22
	"strconv"
23
	"strings"
24

25
	"github.com/go-openapi/errors"
26
	"github.com/go-openapi/spec"
27
)
28

29
const (
30
	swaggerBody     = "body"
31
	swaggerExample  = "example"
32
	swaggerExamples = "examples"
33
)
34

35
const (
36
	objectType  = "object"
37
	arrayType   = "array"
38
	stringType  = "string"
39
	integerType = "integer"
40
	numberType  = "number"
41
	booleanType = "boolean"
42
	fileType    = "file"
43
	nullType    = "null"
44
)
45

46
const (
47
	jsonProperties = "properties"
48
	jsonItems      = "items"
49
	jsonType       = "type"
50
	// jsonSchema     = "schema"
51
	jsonDefault = "default"
52
)
53

54
const (
55
	stringFormatDate     = "date"
56
	stringFormatDateTime = "date-time"
57
	stringFormatPassword = "password"
58
	stringFormatByte     = "byte"
59
	// stringFormatBinary       = "binary"
60
	stringFormatCreditCard   = "creditcard"
61
	stringFormatDuration     = "duration"
62
	stringFormatEmail        = "email"
63
	stringFormatHexColor     = "hexcolor"
64
	stringFormatHostname     = "hostname"
65
	stringFormatIPv4         = "ipv4"
66
	stringFormatIPv6         = "ipv6"
67
	stringFormatISBN         = "isbn"
68
	stringFormatISBN10       = "isbn10"
69
	stringFormatISBN13       = "isbn13"
70
	stringFormatMAC          = "mac"
71
	stringFormatBSONObjectID = "bsonobjectid"
72
	stringFormatRGBColor     = "rgbcolor"
73
	stringFormatSSN          = "ssn"
74
	stringFormatURI          = "uri"
75
	stringFormatUUID         = "uuid"
76
	stringFormatUUID3        = "uuid3"
77
	stringFormatUUID4        = "uuid4"
78
	stringFormatUUID5        = "uuid5"
79

80
	integerFormatInt32  = "int32"
81
	integerFormatInt64  = "int64"
82
	integerFormatUInt32 = "uint32"
83
	integerFormatUInt64 = "uint64"
84

85
	numberFormatFloat32 = "float32"
86
	numberFormatFloat64 = "float64"
87
	numberFormatFloat   = "float"
88
	numberFormatDouble  = "double"
89
)
90

91
// Helpers available at the package level
92
var (
93
	pathHelp     *pathHelper
94
	valueHelp    *valueHelper
95
	errorHelp    *errorHelper
96
	paramHelp    *paramHelper
97
	responseHelp *responseHelper
98
)
99

100
type errorHelper struct {
101
	// A collection of unexported helpers for error construction
102
}
103

104
func (h *errorHelper) sErr(err errors.Error) *Result {
105
	// Builds a Result from standard errors.Error
106
	return &Result{Errors: []error{err}}
107
}
108

109
func (h *errorHelper) addPointerError(res *Result, err error, ref string, fromPath string) *Result {
110
	// Provides more context on error messages
111
	// reported by the jsoinpointer package by altering the passed Result
112
	if err != nil {
113
		res.AddErrors(cannotResolveRefMsg(fromPath, ref, err))
114
	}
115
	return res
116
}
117

118
type pathHelper struct {
119
	// A collection of unexported helpers for path validation
120
}
121

122
func (h *pathHelper) stripParametersInPath(path string) string {
123
	// Returns a path stripped from all path parameters, with multiple or trailing slashes removed.
124
	//
125
	// Stripping is performed on a slash-separated basis, e.g '/a{/b}' remains a{/b} and not /a.
126
	//  - Trailing "/" make a difference, e.g. /a/ !~ /a (ex: canary/bitbucket.org/swagger.json)
127
	//  - presence or absence of a parameter makes a difference, e.g. /a/{log} !~ /a/ (ex: canary/kubernetes/swagger.json)
128

129
	// Regexp to extract parameters from path, with surrounding {}.
130
	// NOTE: important non-greedy modifier
131
	rexParsePathParam := mustCompileRegexp(`{[^{}]+?}`)
132
	strippedSegments := []string{}
133

134
	for _, segment := range strings.Split(path, "/") {
135
		strippedSegments = append(strippedSegments, rexParsePathParam.ReplaceAllString(segment, "X"))
136
	}
137
	return strings.Join(strippedSegments, "/")
138
}
139

140
func (h *pathHelper) extractPathParams(path string) (params []string) {
141
	// Extracts all params from a path, with surrounding "{}"
142
	rexParsePathParam := mustCompileRegexp(`{[^{}]+?}`)
143

144
	for _, segment := range strings.Split(path, "/") {
145
		for _, v := range rexParsePathParam.FindAllStringSubmatch(segment, -1) {
146
			params = append(params, v...)
147
		}
148
	}
149
	return
150
}
151

152
type valueHelper struct {
153
	// A collection of unexported helpers for value validation
154
}
155

156
func (h *valueHelper) asInt64(val interface{}) int64 {
157
	// Number conversion function for int64, without error checking
158
	// (implements an implicit type upgrade).
159
	v := reflect.ValueOf(val)
160
	switch v.Kind() {
161
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
162
		return v.Int()
163
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
164
		return int64(v.Uint())
165
	case reflect.Float32, reflect.Float64:
166
		return int64(v.Float())
167
	default:
168
		// panic("Non numeric value in asInt64()")
169
		return 0
170
	}
171
}
172

173
func (h *valueHelper) asUint64(val interface{}) uint64 {
174
	// Number conversion function for uint64, without error checking
175
	// (implements an implicit type upgrade).
176
	v := reflect.ValueOf(val)
177
	switch v.Kind() {
178
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
179
		return uint64(v.Int())
180
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
181
		return v.Uint()
182
	case reflect.Float32, reflect.Float64:
183
		return uint64(v.Float())
184
	default:
185
		// panic("Non numeric value in asUint64()")
186
		return 0
187
	}
188
}
189

190
// Same for unsigned floats
191
func (h *valueHelper) asFloat64(val interface{}) float64 {
192
	// Number conversion function for float64, without error checking
193
	// (implements an implicit type upgrade).
194
	v := reflect.ValueOf(val)
195
	switch v.Kind() {
196
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
197
		return float64(v.Int())
198
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
199
		return float64(v.Uint())
200
	case reflect.Float32, reflect.Float64:
201
		return v.Float()
202
	default:
203
		// panic("Non numeric value in asFloat64()")
204
		return 0
205
	}
206
}
207

208
type paramHelper struct {
209
	// A collection of unexported helpers for parameters resolution
210
}
211

212
func (h *paramHelper) safeExpandedParamsFor(path, method, operationID string, res *Result, s *SpecValidator) (params []spec.Parameter) {
213
	operation, ok := s.expandedAnalyzer().OperationFor(method, path)
214
	if ok {
215
		// expand parameters first if necessary
216
		resolvedParams := []spec.Parameter{}
217
		for _, ppr := range operation.Parameters {
218
			resolvedParam, red := h.resolveParam(path, method, operationID, &ppr, s) //#nosec
219
			res.Merge(red)
220
			if resolvedParam != nil {
221
				resolvedParams = append(resolvedParams, *resolvedParam)
222
			}
223
		}
224
		// remove params with invalid expansion from Slice
225
		operation.Parameters = resolvedParams
226

227
		for _, ppr := range s.expandedAnalyzer().SafeParamsFor(method, path,
228
			func(p spec.Parameter, err error) bool {
229
				// since params have already been expanded, there are few causes for error
230
				res.AddErrors(someParametersBrokenMsg(path, method, operationID))
231
				// original error from analyzer
232
				res.AddErrors(err)
233
				return true
234
			}) {
235
			params = append(params, ppr)
236
		}
237
	}
238
	return
239
}
240

241
func (h *paramHelper) resolveParam(path, method, operationID string, param *spec.Parameter, s *SpecValidator) (*spec.Parameter, *Result) {
242
	// Ensure parameter is expanded
243
	var err error
244
	res := new(Result)
245
	isRef := param.Ref.String() != ""
246
	if s.spec.SpecFilePath() == "" {
247
		err = spec.ExpandParameterWithRoot(param, s.spec.Spec(), nil)
248
	} else {
249
		err = spec.ExpandParameter(param, s.spec.SpecFilePath())
250

251
	}
252
	if err != nil { // Safeguard
253
		// NOTE: we may enter enter here when the whole parameter is an unresolved $ref
254
		refPath := strings.Join([]string{"\"" + path + "\"", method}, ".")
255
		errorHelp.addPointerError(res, err, param.Ref.String(), refPath)
256
		return nil, res
257
	}
258
	res.Merge(h.checkExpandedParam(param, param.Name, param.In, operationID, isRef))
259
	return param, res
260
}
261

262
func (h *paramHelper) checkExpandedParam(pr *spec.Parameter, path, in, operation string, isRef bool) *Result {
263
	// Secure parameter structure after $ref resolution
264
	res := new(Result)
265
	simpleZero := spec.SimpleSchema{}
266
	// Try to explain why... best guess
267
	switch {
268
	case pr.In == swaggerBody && (pr.SimpleSchema != simpleZero && pr.SimpleSchema.Type != objectType):
269
		if isRef {
270
			// Most likely, a $ref with a sibling is an unwanted situation: in itself this is a warning...
271
			// but we detect it because of the following error:
272
			// schema took over Parameter for an unexplained reason
273
			res.AddWarnings(refShouldNotHaveSiblingsMsg(path, operation))
274
		}
275
		res.AddErrors(invalidParameterDefinitionMsg(path, in, operation))
276
	case pr.In != swaggerBody && pr.Schema != nil:
277
		if isRef {
278
			res.AddWarnings(refShouldNotHaveSiblingsMsg(path, operation))
279
		}
280
		res.AddErrors(invalidParameterDefinitionAsSchemaMsg(path, in, operation))
281
	case (pr.In == swaggerBody && pr.Schema == nil) || (pr.In != swaggerBody && pr.SimpleSchema == simpleZero):
282
		// Other unexpected mishaps
283
		res.AddErrors(invalidParameterDefinitionMsg(path, in, operation))
284
	}
285
	return res
286
}
287

288
type responseHelper struct {
289
	// A collection of unexported helpers for response resolution
290
}
291

292
func (r *responseHelper) expandResponseRef(
293
	response *spec.Response,
294
	path string, s *SpecValidator) (*spec.Response, *Result) {
295
	// Ensure response is expanded
296
	var err error
297
	res := new(Result)
298
	if s.spec.SpecFilePath() == "" {
299
		// there is no physical document to resolve $ref in response
300
		err = spec.ExpandResponseWithRoot(response, s.spec.Spec(), nil)
301
	} else {
302
		err = spec.ExpandResponse(response, s.spec.SpecFilePath())
303
	}
304
	if err != nil { // Safeguard
305
		// NOTE: we may enter here when the whole response is an unresolved $ref.
306
		errorHelp.addPointerError(res, err, response.Ref.String(), path)
307
		return nil, res
308
	}
309
	return response, res
310
}
311

312
func (r *responseHelper) responseMsgVariants(
313
	responseType string,
314
	responseCode int) (responseName, responseCodeAsStr string) {
315
	// Path variants for messages
316
	if responseType == jsonDefault {
317
		responseCodeAsStr = jsonDefault
318
		responseName = "default response"
319
	} else {
320
		responseCodeAsStr = strconv.Itoa(responseCode)
321
		responseName = "response " + responseCodeAsStr
322
	}
323
	return
324
}
325

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

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

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

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