Skip to content

Commit c4cb88c

Browse files
committed
Fixed issue with recursive reference causing RangeError
1 parent 1454f49 commit c4cb88c

File tree

3 files changed

+73
-4
lines changed

3 files changed

+73
-4
lines changed

lib/schemaUtils.js

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2271,16 +2271,21 @@ module.exports = {
22712271
* @param {object} components - components defined in the OAS spec. These are used to
22722272
* resolve references while generating params.
22732273
* @param {object} options - a standard list of options that's globally passed around. Check options.js for more.
2274+
* @param {*} seenRef - References that are repeated. Used to identify circular references.
22742275
* @returns {Object} reference object from the saved components
22752276
* @no-unit-tests
22762277
*/
2277-
getRefObject: function($ref, components, options) {
2278+
getRefObject: function($ref, components, options, seenRef = {}) {
22782279
var refObj, savedSchema;
22792280

22802281
if (typeof $ref !== 'string') {
22812282
return { value: `Invalid $ref: ${$ref} was found` };
22822283
}
22832284

2285+
if (seenRef[$ref]) {
2286+
return { value: `<Error: "${$ref}" contains circular references in it.` };
2287+
}
2288+
22842289
savedSchema = $ref.split('/').slice(1).map((elem) => {
22852290
// https://swagger.io/docs/specification/using-ref#escape
22862291
// since / is the default delimiter, slashes are escaped with ~1
@@ -2311,10 +2316,16 @@ module.exports = {
23112316
return { value: `reference ${$ref} not found in the given specification` };
23122317
}
23132318

2319+
// Mark current $ref as seen while processing it further
2320+
seenRef[$ref] = true;
2321+
23142322
if (refObj.$ref) {
2315-
return this.getRefObject(refObj.$ref, components, options);
2323+
return this.getRefObject(refObj.$ref, components, options, seenRef);
23162324
}
23172325

2326+
// Unmark current $ref once resolved
2327+
seenRef[$ref] = false;
2328+
23182329
return refObj;
23192330
},
23202331

test/unit/base.test.js

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,9 @@ describe('CONVERT FUNCTION TESTS ', function() {
9292
specWithNullParams =
9393
path.join(__dirname, VALID_OPENAPI_PATH, '/specWithNullParams.yaml'),
9494
acceptHeaderExample =
95-
path.join(__dirname, VALID_OPENAPI_PATH, '/acceptHeaderExample.json');
95+
path.join(__dirname, VALID_OPENAPI_PATH, '/acceptHeaderExample.json'),
96+
recursiveRefComponents =
97+
path.join(__dirname, VALID_OPENAPI_PATH, '/recursiveRefComponents.yaml');
9698

9799

98100
it('Should add collection level auth with type as `bearer`' +
@@ -1888,6 +1890,35 @@ describe('CONVERT FUNCTION TESTS ', function() {
18881890
done();
18891891
});
18901892
});
1893+
1894+
it('Should handle recursive references for non-schema $refs correctly', function(done) {
1895+
var openapi = fs.readFileSync(recursiveRefComponents, 'utf8');
1896+
Converter.convert({ type: 'string', data: openapi }, {},
1897+
(err, conversionResult) => {
1898+
expect(err).to.be.null;
1899+
expect(conversionResult.result).to.equal(true);
1900+
expect(conversionResult.output.length).to.equal(1);
1901+
expect(conversionResult.output[0].type).to.equal('collection');
1902+
expect(conversionResult.output[0].data).to.have.property('info');
1903+
expect(conversionResult.output[0].data).to.have.property('item');
1904+
expect(conversionResult.output[0].data.item.length).to.equal(1);
1905+
1906+
const item = conversionResult.output[0].data.item[0];
1907+
1908+
expect(item.request.header).to.be.undefined;
1909+
expect(item.request.url.query).to.be.empty;
1910+
expect(item.response.length).to.eql(2);
1911+
expect(item.response[0].header.length).to.eql(1);
1912+
expect(item.response[0].header[0].key).to.eql('Content-Type');
1913+
expect(item.response[0].header[0].value).to.eql('text/plain');
1914+
expect(item.response[0].body).to.be.empty;
1915+
expect(item.response[1].header.length).to.eql(1);
1916+
expect(item.response[1].header[0].key).to.eql('Content-Type');
1917+
expect(item.response[1].header[0].value).to.eql('text/plain');
1918+
expect(item.response[1].body).to.be.empty;
1919+
done();
1920+
});
1921+
});
18911922
});
18921923

18931924
describe('Converting swagger 2.0 files', function() {

test/unit/convertV2.test.js

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,9 @@ const expect = require('chai').expect,
8787
specWithNullParams =
8888
path.join(__dirname, VALID_OPENAPI_PATH, '/specWithNullParams.yaml'),
8989
acceptHeaderExample =
90-
path.join(__dirname, VALID_OPENAPI_PATH, '/acceptHeaderExample.json');
90+
path.join(__dirname, VALID_OPENAPI_PATH, '/acceptHeaderExample.json'),
91+
recursiveRefComponents =
92+
path.join(__dirname, VALID_OPENAPI_PATH, '/recursiveRefComponents.yaml');
9193

9294

9395
describe('The convert v2 Function', function() {
@@ -2179,4 +2181,29 @@ describe('The convert v2 Function', function() {
21792181
done();
21802182
});
21812183
});
2184+
2185+
it('Should handle recursive references for non-schema $refs correctly', function(done) {
2186+
var openapi = fs.readFileSync(recursiveRefComponents, 'utf8');
2187+
Converter.convertV2({ type: 'string', data: openapi }, {},
2188+
(err, conversionResult) => {
2189+
expect(err).to.be.null;
2190+
expect(conversionResult.result).to.equal(true);
2191+
expect(conversionResult.output.length).to.equal(1);
2192+
expect(conversionResult.output[0].type).to.equal('collection');
2193+
expect(conversionResult.output[0].data).to.have.property('info');
2194+
expect(conversionResult.output[0].data).to.have.property('item');
2195+
expect(conversionResult.output[0].data.item.length).to.equal(1);
2196+
2197+
const item = conversionResult.output[0].data.item[0].item[0];
2198+
2199+
expect(item.request.header).to.be.undefined;
2200+
expect(item.request.url.query).to.be.empty;
2201+
expect(item.response.length).to.eql(2);
2202+
expect(item.response[0].header).to.be.empty;
2203+
expect(item.response[0].body).to.be.undefined;
2204+
expect(item.response[1].header).to.be.empty;
2205+
expect(item.response[1].body).to.be.undefined;
2206+
done();
2207+
});
2208+
});
21822209
});

0 commit comments

Comments
 (0)