Skip to content

Commit

Permalink
Prevent infinite loop while loading openapi spec with recursive refer…
Browse files Browse the repository at this point in the history
…ences (#310)
  • Loading branch information
hottestseason authored Mar 1, 2021
1 parent bdba5d1 commit 89012b7
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 2 deletions.
17 changes: 15 additions & 2 deletions openapi3/swagger_loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ type SwaggerLoader struct {

Context context.Context

visitedFiles map[string]struct{}
visitedFiles map[string]struct{}
visitedSwaggers map[string]*Swagger

visitedHeader map[*Header]struct{}
visitedParameter map[*Parameter]struct{}
Expand All @@ -53,6 +54,7 @@ func NewSwaggerLoader() *SwaggerLoader {

func (swaggerLoader *SwaggerLoader) reset() {
swaggerLoader.visitedFiles = make(map[string]struct{})
swaggerLoader.visitedSwaggers = make(map[string]*Swagger)
}

// LoadSwaggerFromURI loads a spec from a remote URL
Expand Down Expand Up @@ -170,11 +172,22 @@ func (swaggerLoader *SwaggerLoader) LoadSwaggerFromDataWithPath(data []byte, pat
}

func (swaggerLoader *SwaggerLoader) loadSwaggerFromDataWithPathInternal(data []byte, path *url.URL) (*Swagger, error) {
visited, ok := swaggerLoader.visitedSwaggers[path.String()]
if ok {
return visited, nil
}

swagger := &Swagger{}
swaggerLoader.visitedSwaggers[path.String()] = swagger

if err := yaml.Unmarshal(data, swagger); err != nil {
return nil, err
}
return swagger, swaggerLoader.ResolveRefsIn(swagger, path)
if err := swaggerLoader.ResolveRefsIn(swagger, path); err != nil {
return nil, err
}

return swagger, nil
}

// ResolveRefsIn expands references if for instance spec was just unmarshalled
Expand Down
17 changes: 17 additions & 0 deletions openapi3/swagger_loader_recursive_ref_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package openapi3

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestLoaderSupportsRecursiveReference(t *testing.T) {
loader := NewSwaggerLoader()
loader.IsExternalRefsAllowed = true
doc, err := loader.LoadSwaggerFromFile("testdata/recursiveRef/openapi.yml")
require.NoError(t, err)
require.NotNil(t, doc)
require.NoError(t, doc.Validate(loader.Context))
require.Equal(t, "bar", doc.Paths["/foo"].Get.Responses.Get(200).Value.Content.Get("application/json").Schema.Value.Properties["foo"].Value.Properties["bar"].Value.Items.Value.Example)
}
2 changes: 2 additions & 0 deletions openapi3/testdata/recursiveRef/components/Bar.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
type: string
example: bar
6 changes: 6 additions & 0 deletions openapi3/testdata/recursiveRef/components/Foo.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
type: object
properties:
bar:
type: array
items:
$ref: ../openapi.yml#/components/schemas/Bar
13 changes: 13 additions & 0 deletions openapi3/testdata/recursiveRef/openapi.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
openapi: "3.0.3"
info:
title: Recursive refs example
version: "1.0"
paths:
/foo:
$ref: ./paths/foo.yml
components:
schemas:
Foo:
$ref: ./components/Foo.yml
Bar:
$ref: ./components/Bar.yml
11 changes: 11 additions & 0 deletions openapi3/testdata/recursiveRef/paths/foo.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
get:
responses:
"200":
description: OK
content:
application/json:
schema:
type: object
properties:
foo:
$ref: ../openapi.yml#/components/schemas/Foo

0 comments on commit 89012b7

Please sign in to comment.