mutating_walker.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  1. /*
  2. Copyright 2017 The Kubernetes Authors.
  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. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package aggregator
  14. import (
  15. _ "net/http/pprof"
  16. "github.com/go-openapi/spec"
  17. )
  18. // Run a walkRefCallback method on all references of an OpenAPI spec, replacing the values.
  19. type mutatingReferenceWalker struct {
  20. // walkRefCallback will be called on each reference. Do not mutate the input, always create a copy first and return that.
  21. walkRefCallback func(ref *spec.Ref) *spec.Ref
  22. }
  23. // replaceReferences rewrites the references without mutating the input.
  24. // The output might share data with the input.
  25. func replaceReferences(walkRef func(ref *spec.Ref) *spec.Ref, sp *spec.Swagger) *spec.Swagger {
  26. walker := &mutatingReferenceWalker{walkRefCallback: walkRef}
  27. return walker.Start(sp)
  28. }
  29. func (w *mutatingReferenceWalker) walkSchema(schema *spec.Schema) *spec.Schema {
  30. if schema == nil {
  31. return nil
  32. }
  33. orig := schema
  34. clone := func() {
  35. if orig == schema {
  36. schema = &spec.Schema{}
  37. *schema = *orig
  38. }
  39. }
  40. if r := w.walkRefCallback(&schema.Ref); r != &schema.Ref {
  41. clone()
  42. schema.Ref = *r
  43. }
  44. definitionsCloned := false
  45. for k, v := range schema.Definitions {
  46. if s := w.walkSchema(&v); s != &v {
  47. if !definitionsCloned {
  48. definitionsCloned = true
  49. clone()
  50. schema.Definitions = make(spec.Definitions, len(orig.Definitions))
  51. for k2, v2 := range orig.Definitions {
  52. schema.Definitions[k2] = v2
  53. }
  54. }
  55. schema.Definitions[k] = *s
  56. }
  57. }
  58. propertiesCloned := false
  59. for k, v := range schema.Properties {
  60. if s := w.walkSchema(&v); s != &v {
  61. if !propertiesCloned {
  62. propertiesCloned = true
  63. clone()
  64. schema.Properties = make(map[string]spec.Schema, len(orig.Properties))
  65. for k2, v2 := range orig.Properties {
  66. schema.Properties[k2] = v2
  67. }
  68. }
  69. schema.Properties[k] = *s
  70. }
  71. }
  72. patternPropertiesCloned := false
  73. for k, v := range schema.PatternProperties {
  74. if s := w.walkSchema(&v); s != &v {
  75. if !patternPropertiesCloned {
  76. patternPropertiesCloned = true
  77. clone()
  78. schema.PatternProperties = make(map[string]spec.Schema, len(orig.PatternProperties))
  79. for k2, v2 := range orig.PatternProperties {
  80. schema.PatternProperties[k2] = v2
  81. }
  82. }
  83. schema.PatternProperties[k] = *s
  84. }
  85. }
  86. allOfCloned := false
  87. for i := range schema.AllOf {
  88. if s := w.walkSchema(&schema.AllOf[i]); s != &schema.AllOf[i] {
  89. if !allOfCloned {
  90. allOfCloned = true
  91. clone()
  92. schema.AllOf = make([]spec.Schema, len(orig.AllOf))
  93. copy(schema.AllOf, orig.AllOf)
  94. }
  95. schema.AllOf[i] = *s
  96. }
  97. }
  98. anyOfCloned := false
  99. for i := range schema.AnyOf {
  100. if s := w.walkSchema(&schema.AnyOf[i]); s != &schema.AnyOf[i] {
  101. if !anyOfCloned {
  102. anyOfCloned = true
  103. clone()
  104. schema.AnyOf = make([]spec.Schema, len(orig.AnyOf))
  105. copy(schema.AnyOf, orig.AnyOf)
  106. }
  107. schema.AnyOf[i] = *s
  108. }
  109. }
  110. oneOfCloned := false
  111. for i := range schema.OneOf {
  112. if s := w.walkSchema(&schema.OneOf[i]); s != &schema.OneOf[i] {
  113. if !oneOfCloned {
  114. oneOfCloned = true
  115. clone()
  116. schema.OneOf = make([]spec.Schema, len(orig.OneOf))
  117. copy(schema.OneOf, orig.OneOf)
  118. }
  119. schema.OneOf[i] = *s
  120. }
  121. }
  122. if schema.Not != nil {
  123. if s := w.walkSchema(schema.Not); s != schema.Not {
  124. clone()
  125. schema.Not = s
  126. }
  127. }
  128. if schema.AdditionalProperties != nil && schema.AdditionalProperties.Schema != nil {
  129. if s := w.walkSchema(schema.AdditionalProperties.Schema); s != schema.AdditionalProperties.Schema {
  130. clone()
  131. schema.AdditionalProperties = &spec.SchemaOrBool{Schema: s, Allows: schema.AdditionalProperties.Allows}
  132. }
  133. }
  134. if schema.AdditionalItems != nil && schema.AdditionalItems.Schema != nil {
  135. if s := w.walkSchema(schema.AdditionalItems.Schema); s != schema.AdditionalItems.Schema {
  136. clone()
  137. schema.AdditionalItems = &spec.SchemaOrBool{Schema: s, Allows: schema.AdditionalItems.Allows}
  138. }
  139. }
  140. if schema.Items != nil {
  141. if schema.Items.Schema != nil {
  142. if s := w.walkSchema(schema.Items.Schema); s != schema.Items.Schema {
  143. clone()
  144. schema.Items = &spec.SchemaOrArray{Schema: s}
  145. }
  146. } else {
  147. itemsCloned := false
  148. for i := range schema.Items.Schemas {
  149. if s := w.walkSchema(&schema.Items.Schemas[i]); s != &schema.Items.Schemas[i] {
  150. if !itemsCloned {
  151. clone()
  152. schema.Items = &spec.SchemaOrArray{
  153. Schemas: make([]spec.Schema, len(orig.Items.Schemas)),
  154. }
  155. itemsCloned = true
  156. copy(schema.Items.Schemas, orig.Items.Schemas)
  157. }
  158. schema.Items.Schemas[i] = *s
  159. }
  160. }
  161. }
  162. }
  163. return schema
  164. }
  165. func (w *mutatingReferenceWalker) walkParameter(param *spec.Parameter) *spec.Parameter {
  166. if param == nil {
  167. return nil
  168. }
  169. orig := param
  170. cloned := false
  171. clone := func() {
  172. if !cloned {
  173. cloned = true
  174. param = &spec.Parameter{}
  175. *param = *orig
  176. }
  177. }
  178. if r := w.walkRefCallback(&param.Ref); r != &param.Ref {
  179. clone()
  180. param.Ref = *r
  181. }
  182. if s := w.walkSchema(param.Schema); s != param.Schema {
  183. clone()
  184. param.Schema = s
  185. }
  186. if param.Items != nil {
  187. if r := w.walkRefCallback(&param.Items.Ref); r != &param.Items.Ref {
  188. param.Items.Ref = *r
  189. }
  190. }
  191. return param
  192. }
  193. func (w *mutatingReferenceWalker) walkParameters(params []spec.Parameter) ([]spec.Parameter, bool) {
  194. if params == nil {
  195. return nil, false
  196. }
  197. orig := params
  198. cloned := false
  199. clone := func() {
  200. if !cloned {
  201. cloned = true
  202. params = make([]spec.Parameter, len(params))
  203. copy(params, orig)
  204. }
  205. }
  206. for i := range params {
  207. if s := w.walkParameter(&params[i]); s != &params[i] {
  208. clone()
  209. params[i] = *s
  210. }
  211. }
  212. return params, cloned
  213. }
  214. func (w *mutatingReferenceWalker) walkResponse(resp *spec.Response) *spec.Response {
  215. if resp == nil {
  216. return nil
  217. }
  218. orig := resp
  219. cloned := false
  220. clone := func() {
  221. if !cloned {
  222. cloned = true
  223. resp = &spec.Response{}
  224. *resp = *orig
  225. }
  226. }
  227. if r := w.walkRefCallback(&resp.Ref); r != &resp.Ref {
  228. clone()
  229. resp.Ref = *r
  230. }
  231. if s := w.walkSchema(resp.Schema); s != resp.Schema {
  232. clone()
  233. resp.Schema = s
  234. }
  235. return resp
  236. }
  237. func (w *mutatingReferenceWalker) walkResponses(resps *spec.Responses) *spec.Responses {
  238. if resps == nil {
  239. return nil
  240. }
  241. orig := resps
  242. cloned := false
  243. clone := func() {
  244. if !cloned {
  245. cloned = true
  246. resps = &spec.Responses{}
  247. *resps = *orig
  248. }
  249. }
  250. if r := w.walkResponse(resps.ResponsesProps.Default); r != resps.ResponsesProps.Default {
  251. clone()
  252. resps.Default = r
  253. }
  254. responsesCloned := false
  255. for k, v := range resps.ResponsesProps.StatusCodeResponses {
  256. if r := w.walkResponse(&v); r != &v {
  257. if !responsesCloned {
  258. responsesCloned = true
  259. clone()
  260. resps.ResponsesProps.StatusCodeResponses = make(map[int]spec.Response, len(orig.StatusCodeResponses))
  261. for k2, v2 := range orig.StatusCodeResponses {
  262. resps.ResponsesProps.StatusCodeResponses[k2] = v2
  263. }
  264. }
  265. resps.ResponsesProps.StatusCodeResponses[k] = *r
  266. }
  267. }
  268. return resps
  269. }
  270. func (w *mutatingReferenceWalker) walkOperation(op *spec.Operation) *spec.Operation {
  271. if op == nil {
  272. return nil
  273. }
  274. orig := op
  275. cloned := false
  276. clone := func() {
  277. if !cloned {
  278. cloned = true
  279. op = &spec.Operation{}
  280. *op = *orig
  281. }
  282. }
  283. parametersCloned := false
  284. for i := range op.Parameters {
  285. if s := w.walkParameter(&op.Parameters[i]); s != &op.Parameters[i] {
  286. if !parametersCloned {
  287. parametersCloned = true
  288. clone()
  289. op.Parameters = make([]spec.Parameter, len(orig.Parameters))
  290. copy(op.Parameters, orig.Parameters)
  291. }
  292. op.Parameters[i] = *s
  293. }
  294. }
  295. if r := w.walkResponses(op.Responses); r != op.Responses {
  296. clone()
  297. op.Responses = r
  298. }
  299. return op
  300. }
  301. func (w *mutatingReferenceWalker) walkPathItem(pathItem *spec.PathItem) *spec.PathItem {
  302. if pathItem == nil {
  303. return nil
  304. }
  305. orig := pathItem
  306. cloned := false
  307. clone := func() {
  308. if !cloned {
  309. cloned = true
  310. pathItem = &spec.PathItem{}
  311. *pathItem = *orig
  312. }
  313. }
  314. if p, changed := w.walkParameters(pathItem.Parameters); changed {
  315. clone()
  316. pathItem.Parameters = p
  317. }
  318. if op := w.walkOperation(pathItem.Get); op != pathItem.Get {
  319. clone()
  320. pathItem.Get = op
  321. }
  322. if op := w.walkOperation(pathItem.Head); op != pathItem.Head {
  323. clone()
  324. pathItem.Head = op
  325. }
  326. if op := w.walkOperation(pathItem.Delete); op != pathItem.Delete {
  327. clone()
  328. pathItem.Delete = op
  329. }
  330. if op := w.walkOperation(pathItem.Options); op != pathItem.Options {
  331. clone()
  332. pathItem.Options = op
  333. }
  334. if op := w.walkOperation(pathItem.Patch); op != pathItem.Patch {
  335. clone()
  336. pathItem.Patch = op
  337. }
  338. if op := w.walkOperation(pathItem.Post); op != pathItem.Post {
  339. clone()
  340. pathItem.Post = op
  341. }
  342. if op := w.walkOperation(pathItem.Put); op != pathItem.Put {
  343. clone()
  344. pathItem.Put = op
  345. }
  346. return pathItem
  347. }
  348. func (w *mutatingReferenceWalker) walkPaths(paths *spec.Paths) *spec.Paths {
  349. if paths == nil {
  350. return nil
  351. }
  352. orig := paths
  353. cloned := false
  354. clone := func() {
  355. if !cloned {
  356. cloned = true
  357. paths = &spec.Paths{}
  358. *paths = *orig
  359. }
  360. }
  361. pathsCloned := false
  362. for k, v := range paths.Paths {
  363. if p := w.walkPathItem(&v); p != &v {
  364. if !pathsCloned {
  365. pathsCloned = true
  366. clone()
  367. paths.Paths = make(map[string]spec.PathItem, len(orig.Paths))
  368. for k2, v2 := range orig.Paths {
  369. paths.Paths[k2] = v2
  370. }
  371. }
  372. paths.Paths[k] = *p
  373. }
  374. }
  375. return paths
  376. }
  377. func (w *mutatingReferenceWalker) Start(swagger *spec.Swagger) *spec.Swagger {
  378. if swagger == nil {
  379. return nil
  380. }
  381. orig := swagger
  382. cloned := false
  383. clone := func() {
  384. if !cloned {
  385. cloned = true
  386. swagger = &spec.Swagger{}
  387. *swagger = *orig
  388. }
  389. }
  390. parametersCloned := false
  391. for k, v := range swagger.Parameters {
  392. if p := w.walkParameter(&v); p != &v {
  393. if !parametersCloned {
  394. parametersCloned = true
  395. clone()
  396. swagger.Parameters = make(map[string]spec.Parameter, len(orig.Parameters))
  397. for k2, v2 := range orig.Parameters {
  398. swagger.Parameters[k2] = v2
  399. }
  400. }
  401. swagger.Parameters[k] = *p
  402. }
  403. }
  404. responsesCloned := false
  405. for k, v := range swagger.Responses {
  406. if r := w.walkResponse(&v); r != &v {
  407. if !responsesCloned {
  408. responsesCloned = true
  409. clone()
  410. swagger.Responses = make(map[string]spec.Response, len(orig.Responses))
  411. for k2, v2 := range orig.Responses {
  412. swagger.Responses[k2] = v2
  413. }
  414. }
  415. swagger.Responses[k] = *r
  416. }
  417. }
  418. definitionsCloned := false
  419. for k, v := range swagger.Definitions {
  420. if s := w.walkSchema(&v); s != &v {
  421. if !definitionsCloned {
  422. definitionsCloned = true
  423. clone()
  424. swagger.Definitions = make(spec.Definitions, len(orig.Definitions))
  425. for k2, v2 := range orig.Definitions {
  426. swagger.Definitions[k2] = v2
  427. }
  428. }
  429. swagger.Definitions[k] = *s
  430. }
  431. }
  432. if swagger.Paths != nil {
  433. if p := w.walkPaths(swagger.Paths); p != swagger.Paths {
  434. clone()
  435. swagger.Paths = p
  436. }
  437. }
  438. return swagger
  439. }