Infinite loop on validation with recursive references and unresolved refs
Description
Having an OpenAPI 3.0 spec with these two conditions:
- includes a remote
$refdeeply nested inside a locally resolved$ref - includes a schema with a circular references
Causes infinite loop when trying to validate the request body using jsonschema.
Expected behaviour
The infinite loop does not happen, validation is done and response is served.
Actual behaviour
Code enters an infinite loop and server never responds
Steps to reproduce
import connexion
def view(*data):
return {}
app = connexion.FlaskApp(__name__, specification_dir='openapi/')
app.add_api('my_api.yaml')
app.run(port=8080)
my_api.yaml
openapi: 3.0.0
info:
title: Sample API
description: Optional
version: '0.1'
servers:
- url: http://api.example.com
description: Optional server description, e.g. Main (production) server
paths:
/:
post:
operationId: 'main.view'
summary: S
description: D
responses:
'200':
description: A JSON array of user names
content:
application/json:
schema:
type: object
requestBody:
content:
application/json:
schema:
type: object
properties:
foo:
$ref: '#/components/schemas/Foo'
bar:
$ref: '#/components/schemas/Bar'
components:
schemas:
Foo:
type: array
items:
$ref: 'file:///tmp/connextest/openapi/referred_schema.json#/components/schemas/FooElement'
Bar:
type: object
properties:
child:
$ref: '#/components/schemas/Bar'
FooElement:
type: string
/tmp/referred_schema.json
{
"components": {
"schemas": {
"FooElement": {
"type": "string"
}
}
}
}
To generate infinite loop:
$ python main.py &
$ echo '{"foo": [1], "bar": {}}' | http POST :8080/ 'Content-Type: application/json'
Additional info:
-
In the example above
components.schemas.Bar.properties.childis the recursive reference. -
components.schemas.Foo.itemsis the unsolved$ref. -
components.schemas.Foo.itemsis unresolved due toresolve_refsimplementation (missing recursive call in 'try' path if '$ref' is missing) -
components.schemas.Bar.properties.childis resolved with a circular reference tocomponents.schemas.Bar -
jsonschemareceives the schema with the circular reference, and crashes when trying to solve the unsolved$ref
I see two possible roads to fix the issue:
- fix the recursion in
resolve_refsalso for resolved nodes not directly including a$ref, but maybe with a nested$ref - avoid resolving refs altogether in
components.schemas. jsonschema is perfectly able to solve the refs while validating, why connexion needs to solve everything in advance ?
Output of the commands:
$ python --version
Python 3.10.7
$ pip show connexion | grep "^Version\:"
Version: 2.14.1
Can reproduce.