diff --git a/openapi3/issue652_test.go b/openapi3/issue652_test.go new file mode 100644 index 000000000..f36e92005 --- /dev/null +++ b/openapi3/issue652_test.go @@ -0,0 +1,29 @@ +package openapi3_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/getkin/kin-openapi/openapi3" +) + +func TestIssue652(t *testing.T) { + loader := openapi3.NewLoader() + loader.IsExternalRefsAllowed = true + + // Test checks that no slice bounds out of range error occurs while loading + // from file that contains reference to file in the parent directory. + require.NotPanics(t, func() { + const schemaName = "ReferenceToParentDirectory" + + spec, err := loader.LoadFromFile("testdata/issue652/nested/schema.yml") + require.NoError(t, err) + require.Contains(t, spec.Components.Schemas, schemaName) + + schema := spec.Components.Schemas[schemaName] + assert.Equal(t, schema.Ref, "../definitions.yml#/components/schemas/TestSchema") + assert.Equal(t, schema.Value.Type, "string") + }) +} diff --git a/openapi3/loader.go b/openapi3/loader.go index 1ab693b0f..2bb9999ee 100644 --- a/openapi3/loader.go +++ b/openapi3/loader.go @@ -742,7 +742,10 @@ func (loader *Loader) resolveSchemaRef(doc *T, component *SchemaRef, documentPat return err } component.Value = resolved.Value - foundPath := loader.getResolvedRefPath(ref, &resolved, documentPath, componentPath) + foundPath, rerr := loader.getResolvedRefPath(ref, &resolved, documentPath, componentPath) + if rerr != nil { + return fmt.Errorf("failed to resolve file from reference %q: %w", ref, rerr) + } documentPath = loader.documentPathForRecursiveRef(documentPath, foundPath) } } @@ -790,23 +793,28 @@ func (loader *Loader) resolveSchemaRef(doc *T, component *SchemaRef, documentPat return nil } -func (loader *Loader) getResolvedRefPath(ref string, resolved *SchemaRef, cur, found *url.URL) string { +func (loader *Loader) getResolvedRefPath(ref string, resolved *SchemaRef, cur, found *url.URL) (string, error) { if referencedFilename := strings.Split(ref, "#")[0]; referencedFilename == "" { if cur != nil { if loader.rootDir != "" && strings.HasPrefix(cur.Path, loader.rootDir) { - return cur.Path[len(loader.rootDir)+1:] + return cur.Path[len(loader.rootDir)+1:], nil } - return path.Base(cur.Path) + return path.Base(cur.Path), nil } - return "" + return "", nil } // ref. to external file if resolved.Ref != "" { - return resolved.Ref + return resolved.Ref, nil } + + if loader.rootDir == "" { + return found.Path, nil + } + // found dest spec. file - return path.Dir(found.Path)[len(loader.rootDir):] + return filepath.Rel(loader.rootDir, found.Path) } func (loader *Loader) resolveSecuritySchemeRef(doc *T, component *SecuritySchemeRef, documentPath *url.URL) (err error) { diff --git a/openapi3/testdata/issue652/definitions.yml b/openapi3/testdata/issue652/definitions.yml new file mode 100644 index 000000000..98ef69254 --- /dev/null +++ b/openapi3/testdata/issue652/definitions.yml @@ -0,0 +1,4 @@ +components: + schemas: + TestSchema: + type: string diff --git a/openapi3/testdata/issue652/nested/schema.yml b/openapi3/testdata/issue652/nested/schema.yml new file mode 100644 index 000000000..ef321a101 --- /dev/null +++ b/openapi3/testdata/issue652/nested/schema.yml @@ -0,0 +1,4 @@ +components: + schemas: + ReferenceToParentDirectory: + $ref: "../definitions.yml#/components/schemas/TestSchema"