1/* 2Copyright 2017 The Kubernetes Authors. 3 4Licensed under the Apache License, Version 2.0 (the "License"); 5you may not use this file except in compliance with the License. 6You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10Unless required by applicable law or agreed to in writing, software 11distributed under the License is distributed on an "AS IS" BASIS, 12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13See the License for the specific language governing permissions and 14limitations under the License. 15*/ 16 17package aggregator 18 19import ( 20 "strings" 21 22 "github.com/go-openapi/spec" 23) 24 25const ( 26 definitionPrefix = "#/definitions/" 27) 28 29// Run a readonlyReferenceWalker method on all references of an OpenAPI spec 30type readonlyReferenceWalker struct { 31 // walkRefCallback will be called on each reference. The input will never be nil. 32 walkRefCallback func(ref *spec.Ref) 33 34 // The spec to walk through. 35 root *spec.Swagger 36} 37 38// walkOnAllReferences recursively walks on all references, while following references into definitions. 39// it calls walkRef on each found reference. 40func walkOnAllReferences(walkRef func(ref *spec.Ref), root *spec.Swagger) { 41 alreadyVisited := map[string]bool{} 42 43 walker := &readonlyReferenceWalker{ 44 root: root, 45 } 46 walker.walkRefCallback = func(ref *spec.Ref) { 47 walkRef(ref) 48 49 refStr := ref.String() 50 if refStr == "" || !strings.HasPrefix(refStr, definitionPrefix) { 51 return 52 } 53 defName := refStr[len(definitionPrefix):] 54 55 if _, found := root.Definitions[defName]; found && !alreadyVisited[refStr] { 56 alreadyVisited[refStr] = true 57 def := root.Definitions[defName] 58 walker.walkSchema(&def) 59 } 60 } 61 walker.Start() 62} 63 64func (s *readonlyReferenceWalker) walkSchema(schema *spec.Schema) { 65 if schema == nil { 66 return 67 } 68 s.walkRefCallback(&schema.Ref) 69 var v *spec.Schema 70 if len(schema.Definitions)+len(schema.Properties)+len(schema.PatternProperties) > 0 { 71 v = &spec.Schema{} 72 } 73 for k := range schema.Definitions { 74 *v = schema.Definitions[k] 75 s.walkSchema(v) 76 } 77 for k := range schema.Properties { 78 *v = schema.Properties[k] 79 s.walkSchema(v) 80 } 81 for k := range schema.PatternProperties { 82 *v = schema.PatternProperties[k] 83 s.walkSchema(v) 84 } 85 for i := range schema.AllOf { 86 s.walkSchema(&schema.AllOf[i]) 87 } 88 for i := range schema.AnyOf { 89 s.walkSchema(&schema.AnyOf[i]) 90 } 91 for i := range schema.OneOf { 92 s.walkSchema(&schema.OneOf[i]) 93 } 94 if schema.Not != nil { 95 s.walkSchema(schema.Not) 96 } 97 if schema.AdditionalProperties != nil && schema.AdditionalProperties.Schema != nil { 98 s.walkSchema(schema.AdditionalProperties.Schema) 99 } 100 if schema.AdditionalItems != nil && schema.AdditionalItems.Schema != nil { 101 s.walkSchema(schema.AdditionalItems.Schema) 102 } 103 if schema.Items != nil { 104 if schema.Items.Schema != nil { 105 s.walkSchema(schema.Items.Schema) 106 } 107 for i := range schema.Items.Schemas { 108 s.walkSchema(&schema.Items.Schemas[i]) 109 } 110 } 111} 112 113func (s *readonlyReferenceWalker) walkParams(params []spec.Parameter) { 114 if params == nil { 115 return 116 } 117 for _, param := range params { 118 s.walkRefCallback(¶m.Ref) 119 s.walkSchema(param.Schema) 120 if param.Items != nil { 121 s.walkRefCallback(¶m.Items.Ref) 122 } 123 } 124} 125 126func (s *readonlyReferenceWalker) walkResponse(resp *spec.Response) { 127 if resp == nil { 128 return 129 } 130 s.walkRefCallback(&resp.Ref) 131 s.walkSchema(resp.Schema) 132} 133 134func (s *readonlyReferenceWalker) walkOperation(op *spec.Operation) { 135 if op == nil { 136 return 137 } 138 s.walkParams(op.Parameters) 139 if op.Responses == nil { 140 return 141 } 142 s.walkResponse(op.Responses.Default) 143 for _, r := range op.Responses.StatusCodeResponses { 144 s.walkResponse(&r) 145 } 146} 147 148func (s *readonlyReferenceWalker) Start() { 149 if s.root.Paths == nil { 150 return 151 } 152 for _, pathItem := range s.root.Paths.Paths { 153 s.walkParams(pathItem.Parameters) 154 s.walkOperation(pathItem.Delete) 155 s.walkOperation(pathItem.Get) 156 s.walkOperation(pathItem.Head) 157 s.walkOperation(pathItem.Options) 158 s.walkOperation(pathItem.Patch) 159 s.walkOperation(pathItem.Post) 160 s.walkOperation(pathItem.Put) 161 } 162} 163