podman

Форк
0
1064 строки · 29.3 Кб
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 analysis
16

17
import (
18
	"fmt"
19
	slashpath "path"
20
	"strconv"
21
	"strings"
22

23
	"github.com/go-openapi/jsonpointer"
24
	"github.com/go-openapi/spec"
25
	"github.com/go-openapi/swag"
26
)
27

28
type referenceAnalysis struct {
29
	schemas        map[string]spec.Ref
30
	responses      map[string]spec.Ref
31
	parameters     map[string]spec.Ref
32
	items          map[string]spec.Ref
33
	headerItems    map[string]spec.Ref
34
	parameterItems map[string]spec.Ref
35
	allRefs        map[string]spec.Ref
36
	pathItems      map[string]spec.Ref
37
}
38

39
func (r *referenceAnalysis) addRef(key string, ref spec.Ref) {
40
	r.allRefs["#"+key] = ref
41
}
42

43
func (r *referenceAnalysis) addItemsRef(key string, items *spec.Items, location string) {
44
	r.items["#"+key] = items.Ref
45
	r.addRef(key, items.Ref)
46
	if location == "header" {
47
		// NOTE: in swagger 2.0, headers and parameters (but not body param schemas) are simple schemas
48
		// and $ref are not supported here. However it is possible to analyze this.
49
		r.headerItems["#"+key] = items.Ref
50
	} else {
51
		r.parameterItems["#"+key] = items.Ref
52
	}
53
}
54

55
func (r *referenceAnalysis) addSchemaRef(key string, ref SchemaRef) {
56
	r.schemas["#"+key] = ref.Schema.Ref
57
	r.addRef(key, ref.Schema.Ref)
58
}
59

60
func (r *referenceAnalysis) addResponseRef(key string, resp *spec.Response) {
61
	r.responses["#"+key] = resp.Ref
62
	r.addRef(key, resp.Ref)
63
}
64

65
func (r *referenceAnalysis) addParamRef(key string, param *spec.Parameter) {
66
	r.parameters["#"+key] = param.Ref
67
	r.addRef(key, param.Ref)
68
}
69

70
func (r *referenceAnalysis) addPathItemRef(key string, pathItem *spec.PathItem) {
71
	r.pathItems["#"+key] = pathItem.Ref
72
	r.addRef(key, pathItem.Ref)
73
}
74

75
type patternAnalysis struct {
76
	parameters  map[string]string
77
	headers     map[string]string
78
	items       map[string]string
79
	schemas     map[string]string
80
	allPatterns map[string]string
81
}
82

83
func (p *patternAnalysis) addPattern(key, pattern string) {
84
	p.allPatterns["#"+key] = pattern
85
}
86

87
func (p *patternAnalysis) addParameterPattern(key, pattern string) {
88
	p.parameters["#"+key] = pattern
89
	p.addPattern(key, pattern)
90
}
91

92
func (p *patternAnalysis) addHeaderPattern(key, pattern string) {
93
	p.headers["#"+key] = pattern
94
	p.addPattern(key, pattern)
95
}
96

97
func (p *patternAnalysis) addItemsPattern(key, pattern string) {
98
	p.items["#"+key] = pattern
99
	p.addPattern(key, pattern)
100
}
101

102
func (p *patternAnalysis) addSchemaPattern(key, pattern string) {
103
	p.schemas["#"+key] = pattern
104
	p.addPattern(key, pattern)
105
}
106

107
type enumAnalysis struct {
108
	parameters map[string][]interface{}
109
	headers    map[string][]interface{}
110
	items      map[string][]interface{}
111
	schemas    map[string][]interface{}
112
	allEnums   map[string][]interface{}
113
}
114

115
func (p *enumAnalysis) addEnum(key string, enum []interface{}) {
116
	p.allEnums["#"+key] = enum
117
}
118

119
func (p *enumAnalysis) addParameterEnum(key string, enum []interface{}) {
120
	p.parameters["#"+key] = enum
121
	p.addEnum(key, enum)
122
}
123

124
func (p *enumAnalysis) addHeaderEnum(key string, enum []interface{}) {
125
	p.headers["#"+key] = enum
126
	p.addEnum(key, enum)
127
}
128

129
func (p *enumAnalysis) addItemsEnum(key string, enum []interface{}) {
130
	p.items["#"+key] = enum
131
	p.addEnum(key, enum)
132
}
133

134
func (p *enumAnalysis) addSchemaEnum(key string, enum []interface{}) {
135
	p.schemas["#"+key] = enum
136
	p.addEnum(key, enum)
137
}
138

139
// New takes a swagger spec object and returns an analyzed spec document.
140
// The analyzed document contains a number of indices that make it easier to
141
// reason about semantics of a swagger specification for use in code generation
142
// or validation etc.
143
func New(doc *spec.Swagger) *Spec {
144
	a := &Spec{
145
		spec:       doc,
146
		references: referenceAnalysis{},
147
		patterns:   patternAnalysis{},
148
		enums:      enumAnalysis{},
149
	}
150
	a.reset()
151
	a.initialize()
152

153
	return a
154
}
155

156
// Spec is an analyzed specification object. It takes a swagger spec object and turns it into a registry
157
// with a bunch of utility methods to act on the information in the spec.
158
type Spec struct {
159
	spec        *spec.Swagger
160
	consumes    map[string]struct{}
161
	produces    map[string]struct{}
162
	authSchemes map[string]struct{}
163
	operations  map[string]map[string]*spec.Operation
164
	references  referenceAnalysis
165
	patterns    patternAnalysis
166
	enums       enumAnalysis
167
	allSchemas  map[string]SchemaRef
168
	allOfs      map[string]SchemaRef
169
}
170

171
func (s *Spec) reset() {
172
	s.consumes = make(map[string]struct{}, 150)
173
	s.produces = make(map[string]struct{}, 150)
174
	s.authSchemes = make(map[string]struct{}, 150)
175
	s.operations = make(map[string]map[string]*spec.Operation, 150)
176
	s.allSchemas = make(map[string]SchemaRef, 150)
177
	s.allOfs = make(map[string]SchemaRef, 150)
178
	s.references.schemas = make(map[string]spec.Ref, 150)
179
	s.references.pathItems = make(map[string]spec.Ref, 150)
180
	s.references.responses = make(map[string]spec.Ref, 150)
181
	s.references.parameters = make(map[string]spec.Ref, 150)
182
	s.references.items = make(map[string]spec.Ref, 150)
183
	s.references.headerItems = make(map[string]spec.Ref, 150)
184
	s.references.parameterItems = make(map[string]spec.Ref, 150)
185
	s.references.allRefs = make(map[string]spec.Ref, 150)
186
	s.patterns.parameters = make(map[string]string, 150)
187
	s.patterns.headers = make(map[string]string, 150)
188
	s.patterns.items = make(map[string]string, 150)
189
	s.patterns.schemas = make(map[string]string, 150)
190
	s.patterns.allPatterns = make(map[string]string, 150)
191
	s.enums.parameters = make(map[string][]interface{}, 150)
192
	s.enums.headers = make(map[string][]interface{}, 150)
193
	s.enums.items = make(map[string][]interface{}, 150)
194
	s.enums.schemas = make(map[string][]interface{}, 150)
195
	s.enums.allEnums = make(map[string][]interface{}, 150)
196
}
197

198
func (s *Spec) reload() {
199
	s.reset()
200
	s.initialize()
201
}
202

203
func (s *Spec) initialize() {
204
	for _, c := range s.spec.Consumes {
205
		s.consumes[c] = struct{}{}
206
	}
207
	for _, c := range s.spec.Produces {
208
		s.produces[c] = struct{}{}
209
	}
210
	for _, ss := range s.spec.Security {
211
		for k := range ss {
212
			s.authSchemes[k] = struct{}{}
213
		}
214
	}
215
	for path, pathItem := range s.AllPaths() {
216
		s.analyzeOperations(path, &pathItem) //#nosec
217
	}
218

219
	for name, parameter := range s.spec.Parameters {
220
		refPref := slashpath.Join("/parameters", jsonpointer.Escape(name))
221
		if parameter.Items != nil {
222
			s.analyzeItems("items", parameter.Items, refPref, "parameter")
223
		}
224
		if parameter.In == "body" && parameter.Schema != nil {
225
			s.analyzeSchema("schema", parameter.Schema, refPref)
226
		}
227
		if parameter.Pattern != "" {
228
			s.patterns.addParameterPattern(refPref, parameter.Pattern)
229
		}
230
		if len(parameter.Enum) > 0 {
231
			s.enums.addParameterEnum(refPref, parameter.Enum)
232
		}
233
	}
234

235
	for name, response := range s.spec.Responses {
236
		refPref := slashpath.Join("/responses", jsonpointer.Escape(name))
237
		for k, v := range response.Headers {
238
			hRefPref := slashpath.Join(refPref, "headers", k)
239
			if v.Items != nil {
240
				s.analyzeItems("items", v.Items, hRefPref, "header")
241
			}
242
			if v.Pattern != "" {
243
				s.patterns.addHeaderPattern(hRefPref, v.Pattern)
244
			}
245
			if len(v.Enum) > 0 {
246
				s.enums.addHeaderEnum(hRefPref, v.Enum)
247
			}
248
		}
249
		if response.Schema != nil {
250
			s.analyzeSchema("schema", response.Schema, refPref)
251
		}
252
	}
253

254
	for name := range s.spec.Definitions {
255
		schema := s.spec.Definitions[name]
256
		s.analyzeSchema(name, &schema, "/definitions")
257
	}
258
	// TODO: after analyzing all things and flattening schemas etc
259
	// resolve all the collected references to their final representations
260
	// best put in a separate method because this could get expensive
261
}
262

263
func (s *Spec) analyzeOperations(path string, pi *spec.PathItem) {
264
	// TODO: resolve refs here?
265
	// Currently, operations declared via pathItem $ref are known only after expansion
266
	op := pi
267
	if pi.Ref.String() != "" {
268
		key := slashpath.Join("/paths", jsonpointer.Escape(path))
269
		s.references.addPathItemRef(key, pi)
270
	}
271
	s.analyzeOperation("GET", path, op.Get)
272
	s.analyzeOperation("PUT", path, op.Put)
273
	s.analyzeOperation("POST", path, op.Post)
274
	s.analyzeOperation("PATCH", path, op.Patch)
275
	s.analyzeOperation("DELETE", path, op.Delete)
276
	s.analyzeOperation("HEAD", path, op.Head)
277
	s.analyzeOperation("OPTIONS", path, op.Options)
278
	for i, param := range op.Parameters {
279
		refPref := slashpath.Join("/paths", jsonpointer.Escape(path), "parameters", strconv.Itoa(i))
280
		if param.Ref.String() != "" {
281
			s.references.addParamRef(refPref, &param) //#nosec
282
		}
283
		if param.Pattern != "" {
284
			s.patterns.addParameterPattern(refPref, param.Pattern)
285
		}
286
		if len(param.Enum) > 0 {
287
			s.enums.addParameterEnum(refPref, param.Enum)
288
		}
289
		if param.Items != nil {
290
			s.analyzeItems("items", param.Items, refPref, "parameter")
291
		}
292
		if param.Schema != nil {
293
			s.analyzeSchema("schema", param.Schema, refPref)
294
		}
295
	}
296
}
297

298
func (s *Spec) analyzeItems(name string, items *spec.Items, prefix, location string) {
299
	if items == nil {
300
		return
301
	}
302
	refPref := slashpath.Join(prefix, name)
303
	s.analyzeItems(name, items.Items, refPref, location)
304
	if items.Ref.String() != "" {
305
		s.references.addItemsRef(refPref, items, location)
306
	}
307
	if items.Pattern != "" {
308
		s.patterns.addItemsPattern(refPref, items.Pattern)
309
	}
310
	if len(items.Enum) > 0 {
311
		s.enums.addItemsEnum(refPref, items.Enum)
312
	}
313
}
314

315
func (s *Spec) analyzeParameter(prefix string, i int, param spec.Parameter) {
316
	refPref := slashpath.Join(prefix, "parameters", strconv.Itoa(i))
317
	if param.Ref.String() != "" {
318
		s.references.addParamRef(refPref, &param) //#nosec
319
	}
320

321
	if param.Pattern != "" {
322
		s.patterns.addParameterPattern(refPref, param.Pattern)
323
	}
324

325
	if len(param.Enum) > 0 {
326
		s.enums.addParameterEnum(refPref, param.Enum)
327
	}
328

329
	s.analyzeItems("items", param.Items, refPref, "parameter")
330
	if param.In == "body" && param.Schema != nil {
331
		s.analyzeSchema("schema", param.Schema, refPref)
332
	}
333
}
334

335
func (s *Spec) analyzeOperation(method, path string, op *spec.Operation) {
336
	if op == nil {
337
		return
338
	}
339

340
	for _, c := range op.Consumes {
341
		s.consumes[c] = struct{}{}
342
	}
343

344
	for _, c := range op.Produces {
345
		s.produces[c] = struct{}{}
346
	}
347

348
	for _, ss := range op.Security {
349
		for k := range ss {
350
			s.authSchemes[k] = struct{}{}
351
		}
352
	}
353

354
	if _, ok := s.operations[method]; !ok {
355
		s.operations[method] = make(map[string]*spec.Operation)
356
	}
357

358
	s.operations[method][path] = op
359
	prefix := slashpath.Join("/paths", jsonpointer.Escape(path), strings.ToLower(method))
360
	for i, param := range op.Parameters {
361
		s.analyzeParameter(prefix, i, param)
362
	}
363

364
	if op.Responses == nil {
365
		return
366
	}
367

368
	if op.Responses.Default != nil {
369
		s.analyzeDefaultResponse(prefix, op.Responses.Default)
370
	}
371

372
	for k, res := range op.Responses.StatusCodeResponses {
373
		s.analyzeResponse(prefix, k, res)
374
	}
375
}
376

377
func (s *Spec) analyzeDefaultResponse(prefix string, res *spec.Response) {
378
	refPref := slashpath.Join(prefix, "responses", "default")
379
	if res.Ref.String() != "" {
380
		s.references.addResponseRef(refPref, res)
381
	}
382

383
	for k, v := range res.Headers {
384
		hRefPref := slashpath.Join(refPref, "headers", k)
385
		s.analyzeItems("items", v.Items, hRefPref, "header")
386
		if v.Pattern != "" {
387
			s.patterns.addHeaderPattern(hRefPref, v.Pattern)
388
		}
389
	}
390

391
	if res.Schema != nil {
392
		s.analyzeSchema("schema", res.Schema, refPref)
393
	}
394
}
395

396
func (s *Spec) analyzeResponse(prefix string, k int, res spec.Response) {
397
	refPref := slashpath.Join(prefix, "responses", strconv.Itoa(k))
398
	if res.Ref.String() != "" {
399
		s.references.addResponseRef(refPref, &res) //#nosec
400
	}
401

402
	for k, v := range res.Headers {
403
		hRefPref := slashpath.Join(refPref, "headers", k)
404
		s.analyzeItems("items", v.Items, hRefPref, "header")
405
		if v.Pattern != "" {
406
			s.patterns.addHeaderPattern(hRefPref, v.Pattern)
407
		}
408

409
		if len(v.Enum) > 0 {
410
			s.enums.addHeaderEnum(hRefPref, v.Enum)
411
		}
412
	}
413

414
	if res.Schema != nil {
415
		s.analyzeSchema("schema", res.Schema, refPref)
416
	}
417
}
418

419
func (s *Spec) analyzeSchema(name string, schema *spec.Schema, prefix string) {
420
	refURI := slashpath.Join(prefix, jsonpointer.Escape(name))
421
	schRef := SchemaRef{
422
		Name:     name,
423
		Schema:   schema,
424
		Ref:      spec.MustCreateRef("#" + refURI),
425
		TopLevel: prefix == "/definitions",
426
	}
427

428
	s.allSchemas["#"+refURI] = schRef
429

430
	if schema.Ref.String() != "" {
431
		s.references.addSchemaRef(refURI, schRef)
432
	}
433

434
	if schema.Pattern != "" {
435
		s.patterns.addSchemaPattern(refURI, schema.Pattern)
436
	}
437

438
	if len(schema.Enum) > 0 {
439
		s.enums.addSchemaEnum(refURI, schema.Enum)
440
	}
441

442
	for k, v := range schema.Definitions {
443
		v := v
444
		s.analyzeSchema(k, &v, slashpath.Join(refURI, "definitions"))
445
	}
446

447
	for k, v := range schema.Properties {
448
		v := v
449
		s.analyzeSchema(k, &v, slashpath.Join(refURI, "properties"))
450
	}
451

452
	for k, v := range schema.PatternProperties {
453
		v := v
454
		// NOTE: swagger 2.0 does not support PatternProperties.
455
		// However it is possible to analyze this in a schema
456
		s.analyzeSchema(k, &v, slashpath.Join(refURI, "patternProperties"))
457
	}
458

459
	for i := range schema.AllOf {
460
		v := &schema.AllOf[i]
461
		s.analyzeSchema(strconv.Itoa(i), v, slashpath.Join(refURI, "allOf"))
462
	}
463

464
	if len(schema.AllOf) > 0 {
465
		s.allOfs["#"+refURI] = schRef
466
	}
467

468
	for i := range schema.AnyOf {
469
		v := &schema.AnyOf[i]
470
		// NOTE: swagger 2.0 does not support anyOf constructs.
471
		// However it is possible to analyze this in a schema
472
		s.analyzeSchema(strconv.Itoa(i), v, slashpath.Join(refURI, "anyOf"))
473
	}
474

475
	for i := range schema.OneOf {
476
		v := &schema.OneOf[i]
477
		// NOTE: swagger 2.0 does not support oneOf constructs.
478
		// However it is possible to analyze this in a schema
479
		s.analyzeSchema(strconv.Itoa(i), v, slashpath.Join(refURI, "oneOf"))
480
	}
481

482
	if schema.Not != nil {
483
		// NOTE: swagger 2.0 does not support "not" constructs.
484
		// However it is possible to analyze this in a schema
485
		s.analyzeSchema("not", schema.Not, refURI)
486
	}
487

488
	if schema.AdditionalProperties != nil && schema.AdditionalProperties.Schema != nil {
489
		s.analyzeSchema("additionalProperties", schema.AdditionalProperties.Schema, refURI)
490
	}
491

492
	if schema.AdditionalItems != nil && schema.AdditionalItems.Schema != nil {
493
		// NOTE: swagger 2.0 does not support AdditionalItems.
494
		// However it is possible to analyze this in a schema
495
		s.analyzeSchema("additionalItems", schema.AdditionalItems.Schema, refURI)
496
	}
497

498
	if schema.Items != nil {
499
		if schema.Items.Schema != nil {
500
			s.analyzeSchema("items", schema.Items.Schema, refURI)
501
		}
502

503
		for i := range schema.Items.Schemas {
504
			sch := &schema.Items.Schemas[i]
505
			s.analyzeSchema(strconv.Itoa(i), sch, slashpath.Join(refURI, "items"))
506
		}
507
	}
508
}
509

510
// SecurityRequirement is a representation of a security requirement for an operation
511
type SecurityRequirement struct {
512
	Name   string
513
	Scopes []string
514
}
515

516
// SecurityRequirementsFor gets the security requirements for the operation
517
func (s *Spec) SecurityRequirementsFor(operation *spec.Operation) [][]SecurityRequirement {
518
	if s.spec.Security == nil && operation.Security == nil {
519
		return nil
520
	}
521

522
	schemes := s.spec.Security
523
	if operation.Security != nil {
524
		schemes = operation.Security
525
	}
526

527
	result := [][]SecurityRequirement{}
528
	for _, scheme := range schemes {
529
		if len(scheme) == 0 {
530
			// append a zero object for anonymous
531
			result = append(result, []SecurityRequirement{{}})
532

533
			continue
534
		}
535

536
		var reqs []SecurityRequirement
537
		for k, v := range scheme {
538
			if v == nil {
539
				v = []string{}
540
			}
541
			reqs = append(reqs, SecurityRequirement{Name: k, Scopes: v})
542
		}
543

544
		result = append(result, reqs)
545
	}
546

547
	return result
548
}
549

550
// SecurityDefinitionsForRequirements gets the matching security definitions for a set of requirements
551
func (s *Spec) SecurityDefinitionsForRequirements(requirements []SecurityRequirement) map[string]spec.SecurityScheme {
552
	result := make(map[string]spec.SecurityScheme)
553

554
	for _, v := range requirements {
555
		if definition, ok := s.spec.SecurityDefinitions[v.Name]; ok {
556
			if definition != nil {
557
				result[v.Name] = *definition
558
			}
559
		}
560
	}
561

562
	return result
563
}
564

565
// SecurityDefinitionsFor gets the matching security definitions for a set of requirements
566
func (s *Spec) SecurityDefinitionsFor(operation *spec.Operation) map[string]spec.SecurityScheme {
567
	requirements := s.SecurityRequirementsFor(operation)
568
	if len(requirements) == 0 {
569
		return nil
570
	}
571

572
	result := make(map[string]spec.SecurityScheme)
573
	for _, reqs := range requirements {
574
		for _, v := range reqs {
575
			if v.Name == "" {
576
				// optional requirement
577
				continue
578
			}
579

580
			if _, ok := result[v.Name]; ok {
581
				// duplicate requirement
582
				continue
583
			}
584

585
			if definition, ok := s.spec.SecurityDefinitions[v.Name]; ok {
586
				if definition != nil {
587
					result[v.Name] = *definition
588
				}
589
			}
590
		}
591
	}
592

593
	return result
594
}
595

596
// ConsumesFor gets the mediatypes for the operation
597
func (s *Spec) ConsumesFor(operation *spec.Operation) []string {
598
	if len(operation.Consumes) == 0 {
599
		cons := make(map[string]struct{}, len(s.spec.Consumes))
600
		for _, k := range s.spec.Consumes {
601
			cons[k] = struct{}{}
602
		}
603

604
		return s.structMapKeys(cons)
605
	}
606

607
	cons := make(map[string]struct{}, len(operation.Consumes))
608
	for _, c := range operation.Consumes {
609
		cons[c] = struct{}{}
610
	}
611

612
	return s.structMapKeys(cons)
613
}
614

615
// ProducesFor gets the mediatypes for the operation
616
func (s *Spec) ProducesFor(operation *spec.Operation) []string {
617
	if len(operation.Produces) == 0 {
618
		prod := make(map[string]struct{}, len(s.spec.Produces))
619
		for _, k := range s.spec.Produces {
620
			prod[k] = struct{}{}
621
		}
622

623
		return s.structMapKeys(prod)
624
	}
625

626
	prod := make(map[string]struct{}, len(operation.Produces))
627
	for _, c := range operation.Produces {
628
		prod[c] = struct{}{}
629
	}
630

631
	return s.structMapKeys(prod)
632
}
633

634
func mapKeyFromParam(param *spec.Parameter) string {
635
	return fmt.Sprintf("%s#%s", param.In, fieldNameFromParam(param))
636
}
637

638
func fieldNameFromParam(param *spec.Parameter) string {
639
	// TODO: this should be x-go-name
640
	if nm, ok := param.Extensions.GetString("go-name"); ok {
641
		return nm
642
	}
643

644
	return swag.ToGoName(param.Name)
645
}
646

647
// ErrorOnParamFunc is a callback function to be invoked
648
// whenever an error is encountered while resolving references
649
// on parameters.
650
//
651
// This function takes as input the spec.Parameter which triggered the
652
// error and the error itself.
653
//
654
// If the callback function returns false, the calling function should bail.
655
//
656
// If it returns true, the calling function should continue evaluating parameters.
657
// A nil ErrorOnParamFunc must be evaluated as equivalent to panic().
658
type ErrorOnParamFunc func(spec.Parameter, error) bool
659

660
func (s *Spec) paramsAsMap(parameters []spec.Parameter, res map[string]spec.Parameter, callmeOnError ErrorOnParamFunc) {
661
	for _, param := range parameters {
662
		pr := param
663
		if pr.Ref.String() == "" {
664
			res[mapKeyFromParam(&pr)] = pr
665

666
			continue
667
		}
668

669
		// resolve $ref
670
		if callmeOnError == nil {
671
			callmeOnError = func(_ spec.Parameter, err error) bool {
672
				panic(err)
673
			}
674
		}
675

676
		obj, _, err := pr.Ref.GetPointer().Get(s.spec)
677
		if err != nil {
678
			if callmeOnError(param, fmt.Errorf("invalid reference: %q", pr.Ref.String())) {
679
				continue
680
			}
681

682
			break
683
		}
684

685
		objAsParam, ok := obj.(spec.Parameter)
686
		if !ok {
687
			if callmeOnError(param, fmt.Errorf("resolved reference is not a parameter: %q", pr.Ref.String())) {
688
				continue
689
			}
690

691
			break
692
		}
693

694
		pr = objAsParam
695
		res[mapKeyFromParam(&pr)] = pr
696
	}
697
}
698

699
// ParametersFor the specified operation id.
700
//
701
// Assumes parameters properly resolve references if any and that
702
// such references actually resolve to a parameter object.
703
// Otherwise, panics.
704
func (s *Spec) ParametersFor(operationID string) []spec.Parameter {
705
	return s.SafeParametersFor(operationID, nil)
706
}
707

708
// SafeParametersFor the specified operation id.
709
//
710
// Does not assume parameters properly resolve references or that
711
// such references actually resolve to a parameter object.
712
//
713
// Upon error, invoke a ErrorOnParamFunc callback with the erroneous
714
// parameters. If the callback is set to nil, panics upon errors.
715
func (s *Spec) SafeParametersFor(operationID string, callmeOnError ErrorOnParamFunc) []spec.Parameter {
716
	gatherParams := func(pi *spec.PathItem, op *spec.Operation) []spec.Parameter {
717
		bag := make(map[string]spec.Parameter)
718
		s.paramsAsMap(pi.Parameters, bag, callmeOnError)
719
		s.paramsAsMap(op.Parameters, bag, callmeOnError)
720

721
		var res []spec.Parameter
722
		for _, v := range bag {
723
			res = append(res, v)
724
		}
725

726
		return res
727
	}
728

729
	for _, pi := range s.spec.Paths.Paths {
730
		if pi.Get != nil && pi.Get.ID == operationID {
731
			return gatherParams(&pi, pi.Get) //#nosec
732
		}
733
		if pi.Head != nil && pi.Head.ID == operationID {
734
			return gatherParams(&pi, pi.Head) //#nosec
735
		}
736
		if pi.Options != nil && pi.Options.ID == operationID {
737
			return gatherParams(&pi, pi.Options) //#nosec
738
		}
739
		if pi.Post != nil && pi.Post.ID == operationID {
740
			return gatherParams(&pi, pi.Post) //#nosec
741
		}
742
		if pi.Patch != nil && pi.Patch.ID == operationID {
743
			return gatherParams(&pi, pi.Patch) //#nosec
744
		}
745
		if pi.Put != nil && pi.Put.ID == operationID {
746
			return gatherParams(&pi, pi.Put) //#nosec
747
		}
748
		if pi.Delete != nil && pi.Delete.ID == operationID {
749
			return gatherParams(&pi, pi.Delete) //#nosec
750
		}
751
	}
752

753
	return nil
754
}
755

756
// ParamsFor the specified method and path. Aggregates them with the defaults etc, so it's all the params that
757
// apply for the method and path.
758
//
759
// Assumes parameters properly resolve references if any and that
760
// such references actually resolve to a parameter object.
761
// Otherwise, panics.
762
func (s *Spec) ParamsFor(method, path string) map[string]spec.Parameter {
763
	return s.SafeParamsFor(method, path, nil)
764
}
765

766
// SafeParamsFor the specified method and path. Aggregates them with the defaults etc, so it's all the params that
767
// apply for the method and path.
768
//
769
// Does not assume parameters properly resolve references or that
770
// such references actually resolve to a parameter object.
771
//
772
// Upon error, invoke a ErrorOnParamFunc callback with the erroneous
773
// parameters. If the callback is set to nil, panics upon errors.
774
func (s *Spec) SafeParamsFor(method, path string, callmeOnError ErrorOnParamFunc) map[string]spec.Parameter {
775
	res := make(map[string]spec.Parameter)
776
	if pi, ok := s.spec.Paths.Paths[path]; ok {
777
		s.paramsAsMap(pi.Parameters, res, callmeOnError)
778
		s.paramsAsMap(s.operations[strings.ToUpper(method)][path].Parameters, res, callmeOnError)
779
	}
780

781
	return res
782
}
783

784
// OperationForName gets the operation for the given id
785
func (s *Spec) OperationForName(operationID string) (string, string, *spec.Operation, bool) {
786
	for method, pathItem := range s.operations {
787
		for path, op := range pathItem {
788
			if operationID == op.ID {
789
				return method, path, op, true
790
			}
791
		}
792
	}
793

794
	return "", "", nil, false
795
}
796

797
// OperationFor the given method and path
798
func (s *Spec) OperationFor(method, path string) (*spec.Operation, bool) {
799
	if mp, ok := s.operations[strings.ToUpper(method)]; ok {
800
		op, fn := mp[path]
801

802
		return op, fn
803
	}
804

805
	return nil, false
806
}
807

808
// Operations gathers all the operations specified in the spec document
809
func (s *Spec) Operations() map[string]map[string]*spec.Operation {
810
	return s.operations
811
}
812

813
func (s *Spec) structMapKeys(mp map[string]struct{}) []string {
814
	if len(mp) == 0 {
815
		return nil
816
	}
817

818
	result := make([]string, 0, len(mp))
819
	for k := range mp {
820
		result = append(result, k)
821
	}
822

823
	return result
824
}
825

826
// AllPaths returns all the paths in the swagger spec
827
func (s *Spec) AllPaths() map[string]spec.PathItem {
828
	if s.spec == nil || s.spec.Paths == nil {
829
		return nil
830
	}
831

832
	return s.spec.Paths.Paths
833
}
834

835
// OperationIDs gets all the operation ids based on method an dpath
836
func (s *Spec) OperationIDs() []string {
837
	if len(s.operations) == 0 {
838
		return nil
839
	}
840

841
	result := make([]string, 0, len(s.operations))
842
	for method, v := range s.operations {
843
		for p, o := range v {
844
			if o.ID != "" {
845
				result = append(result, o.ID)
846
			} else {
847
				result = append(result, fmt.Sprintf("%s %s", strings.ToUpper(method), p))
848
			}
849
		}
850
	}
851

852
	return result
853
}
854

855
// OperationMethodPaths gets all the operation ids based on method an dpath
856
func (s *Spec) OperationMethodPaths() []string {
857
	if len(s.operations) == 0 {
858
		return nil
859
	}
860

861
	result := make([]string, 0, len(s.operations))
862
	for method, v := range s.operations {
863
		for p := range v {
864
			result = append(result, fmt.Sprintf("%s %s", strings.ToUpper(method), p))
865
		}
866
	}
867

868
	return result
869
}
870

871
// RequiredConsumes gets all the distinct consumes that are specified in the specification document
872
func (s *Spec) RequiredConsumes() []string {
873
	return s.structMapKeys(s.consumes)
874
}
875

876
// RequiredProduces gets all the distinct produces that are specified in the specification document
877
func (s *Spec) RequiredProduces() []string {
878
	return s.structMapKeys(s.produces)
879
}
880

881
// RequiredSecuritySchemes gets all the distinct security schemes that are specified in the swagger spec
882
func (s *Spec) RequiredSecuritySchemes() []string {
883
	return s.structMapKeys(s.authSchemes)
884
}
885

886
// SchemaRef is a reference to a schema
887
type SchemaRef struct {
888
	Name     string
889
	Ref      spec.Ref
890
	Schema   *spec.Schema
891
	TopLevel bool
892
}
893

894
// SchemasWithAllOf returns schema references to all schemas that are defined
895
// with an allOf key
896
func (s *Spec) SchemasWithAllOf() (result []SchemaRef) {
897
	for _, v := range s.allOfs {
898
		result = append(result, v)
899
	}
900

901
	return
902
}
903

904
// AllDefinitions returns schema references for all the definitions that were discovered
905
func (s *Spec) AllDefinitions() (result []SchemaRef) {
906
	for _, v := range s.allSchemas {
907
		result = append(result, v)
908
	}
909

910
	return
911
}
912

913
// AllDefinitionReferences returns json refs for all the discovered schemas
914
func (s *Spec) AllDefinitionReferences() (result []string) {
915
	for _, v := range s.references.schemas {
916
		result = append(result, v.String())
917
	}
918

919
	return
920
}
921

922
// AllParameterReferences returns json refs for all the discovered parameters
923
func (s *Spec) AllParameterReferences() (result []string) {
924
	for _, v := range s.references.parameters {
925
		result = append(result, v.String())
926
	}
927

928
	return
929
}
930

931
// AllResponseReferences returns json refs for all the discovered responses
932
func (s *Spec) AllResponseReferences() (result []string) {
933
	for _, v := range s.references.responses {
934
		result = append(result, v.String())
935
	}
936

937
	return
938
}
939

940
// AllPathItemReferences returns the references for all the items
941
func (s *Spec) AllPathItemReferences() (result []string) {
942
	for _, v := range s.references.pathItems {
943
		result = append(result, v.String())
944
	}
945

946
	return
947
}
948

949
// AllItemsReferences returns the references for all the items in simple schemas (parameters or headers).
950
//
951
// NOTE: since Swagger 2.0 forbids $ref in simple params, this should always yield an empty slice for a valid
952
// Swagger 2.0 spec.
953
func (s *Spec) AllItemsReferences() (result []string) {
954
	for _, v := range s.references.items {
955
		result = append(result, v.String())
956
	}
957

958
	return
959
}
960

961
// AllReferences returns all the references found in the document, with possible duplicates
962
func (s *Spec) AllReferences() (result []string) {
963
	for _, v := range s.references.allRefs {
964
		result = append(result, v.String())
965
	}
966

967
	return
968
}
969

970
// AllRefs returns all the unique references found in the document
971
func (s *Spec) AllRefs() (result []spec.Ref) {
972
	set := make(map[string]struct{})
973
	for _, v := range s.references.allRefs {
974
		a := v.String()
975
		if a == "" {
976
			continue
977
		}
978

979
		if _, ok := set[a]; !ok {
980
			set[a] = struct{}{}
981
			result = append(result, v)
982
		}
983
	}
984

985
	return
986
}
987

988
func cloneStringMap(source map[string]string) map[string]string {
989
	res := make(map[string]string, len(source))
990
	for k, v := range source {
991
		res[k] = v
992
	}
993

994
	return res
995
}
996

997
func cloneEnumMap(source map[string][]interface{}) map[string][]interface{} {
998
	res := make(map[string][]interface{}, len(source))
999
	for k, v := range source {
1000
		res[k] = v
1001
	}
1002

1003
	return res
1004
}
1005

1006
// ParameterPatterns returns all the patterns found in parameters
1007
// the map is cloned to avoid accidental changes
1008
func (s *Spec) ParameterPatterns() map[string]string {
1009
	return cloneStringMap(s.patterns.parameters)
1010
}
1011

1012
// HeaderPatterns returns all the patterns found in response headers
1013
// the map is cloned to avoid accidental changes
1014
func (s *Spec) HeaderPatterns() map[string]string {
1015
	return cloneStringMap(s.patterns.headers)
1016
}
1017

1018
// ItemsPatterns returns all the patterns found in simple array items
1019
// the map is cloned to avoid accidental changes
1020
func (s *Spec) ItemsPatterns() map[string]string {
1021
	return cloneStringMap(s.patterns.items)
1022
}
1023

1024
// SchemaPatterns returns all the patterns found in schemas
1025
// the map is cloned to avoid accidental changes
1026
func (s *Spec) SchemaPatterns() map[string]string {
1027
	return cloneStringMap(s.patterns.schemas)
1028
}
1029

1030
// AllPatterns returns all the patterns found in the spec
1031
// the map is cloned to avoid accidental changes
1032
func (s *Spec) AllPatterns() map[string]string {
1033
	return cloneStringMap(s.patterns.allPatterns)
1034
}
1035

1036
// ParameterEnums returns all the enums found in parameters
1037
// the map is cloned to avoid accidental changes
1038
func (s *Spec) ParameterEnums() map[string][]interface{} {
1039
	return cloneEnumMap(s.enums.parameters)
1040
}
1041

1042
// HeaderEnums returns all the enums found in response headers
1043
// the map is cloned to avoid accidental changes
1044
func (s *Spec) HeaderEnums() map[string][]interface{} {
1045
	return cloneEnumMap(s.enums.headers)
1046
}
1047

1048
// ItemsEnums returns all the enums found in simple array items
1049
// the map is cloned to avoid accidental changes
1050
func (s *Spec) ItemsEnums() map[string][]interface{} {
1051
	return cloneEnumMap(s.enums.items)
1052
}
1053

1054
// SchemaEnums returns all the enums found in schemas
1055
// the map is cloned to avoid accidental changes
1056
func (s *Spec) SchemaEnums() map[string][]interface{} {
1057
	return cloneEnumMap(s.enums.schemas)
1058
}
1059

1060
// AllEnums returns all the enums found in the spec
1061
// the map is cloned to avoid accidental changes
1062
func (s *Spec) AllEnums() map[string][]interface{} {
1063
	return cloneEnumMap(s.enums.allEnums)
1064
}
1065

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

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

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

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