From 03cf1883c25df87d1bc1f8d57606b9264549cdca Mon Sep 17 00:00:00 2001 From: Sandy Chapman Date: Tue, 12 Apr 2016 13:31:37 -0300 Subject: [PATCH 1/2] Added a failing test case that will check to see if a redirect with null schema is failing validation. Added code to ensure unit test passes by doing a check if no data is passed to end and no data is written. In this situation some code expects undefined to be passed to the validators. Delay converting response buffers to string as long as possible. Also, don't convert buffers sourced from a file to a string as it'll mess with the encoding. There's nothing to validate on files anyway. --- middleware/swagger-validator.js | 27 ++++++++++-- test/2.0/test-middleware-swagger-validator.js | 42 ++++++++++++++++++- 2 files changed, 64 insertions(+), 5 deletions(-) diff --git a/middleware/swagger-validator.js b/middleware/swagger-validator.js index 3ac5f4caa9..9e27211fbe 100644 --- a/middleware/swagger-validator.js +++ b/middleware/swagger-validator.js @@ -31,6 +31,20 @@ var debug = require('debug')('swagger-tools:middleware:validator'); var mHelpers = require('./helpers'); var validators = require('../lib/validators'); +var checkIsFile = function (schema, version) { + var isFile = false; + if (version === '1.2') { + var type = (schema.items ? schema.items.type || schema.items.$ref : schema.type); + isFile = type === 'file'; + } + else { + if (!_.isUndefined(schema.schema)) { + isFile = schema.schema.type === 'file'; + } + } + return isFile; +}; + var sendData = function (swaggerVersion, res, data, encoding, skipped) { // 'res.end' requires a Buffer or String so if it's not one, create a String if (!(data instanceof Buffer) && !_.isString(data)) { @@ -201,6 +215,11 @@ var wrapEnd = function (req, res, next) { val = data; } } + else if(writtenData.length === 0) { + // Some code expects val to be undefined and not an empty string + // when no data is passed to 'end' or written with 'write'. + val = undefined; + } else if(writtenData) { val = Buffer.concat(writtenData); } @@ -214,9 +233,6 @@ var wrapEnd = function (req, res, next) { debug(' Response validation:'); // If the data is a buffer, convert it to a string so we can parse it prior to validation - if (val instanceof Buffer) { - val = val.toString(encoding); - } // Express removes the Content-Type header from 204/304 responses which makes response validation impossible if (_.isUndefined(res.getHeader('content-type')) && [204, 304].indexOf(res.statusCode) > -1) { @@ -279,6 +295,11 @@ var wrapEnd = function (req, res, next) { if (_.isUndefined(schema)) { sendData(swaggerVersion, res, val, encoding, true); } else { + // If the data is a buffer, convert it to a string so we can parse it prior to validation + var isFile = checkIsFile(schema, req.swagger.apiDeclaration ? '1.2' : '2.0'); + if (val instanceof Buffer && !isFile) { + val = val.toString(encoding); + } validateValue(req, schema, vPath, val, function (err) { if (err) { throw err; diff --git a/test/2.0/test-middleware-swagger-validator.js b/test/2.0/test-middleware-swagger-validator.js index 803282d196..82ba4c3f20 100644 --- a/test/2.0/test-middleware-swagger-validator.js +++ b/test/2.0/test-middleware-swagger-validator.js @@ -1130,8 +1130,46 @@ describe('Swagger Validator Middleware v2.0', function () { ], done)); }); }); - - + + it('should not return an error with a null schema on an empty response', function (done) { + var cPetStoreJson = _.cloneDeep(petStoreJson); + + cPetStoreJson.paths['/redirect'] = { + 'get': { + 'x-swagger-router-controller': 'Test', + 'operationId': 'redirectTest', + 'responses': { + '302': { + 'description': 'Redirect' + } + } + } + }; + + helpers.createServer([cPetStoreJson], { + swaggerRouterOptions: { + controllers: { + 'Test_redirectTest': function (req, res) { + res.statusCode = 302; + res.end(); + } + } + }, + swaggerValidatorOptions: { + validateResponse: true + } + }, function (app) { + request(app) + .get('/api/redirect') + .expect(302) + .end(function (err, res) { + if (err) { + throw err + '\n' + res.error.text; + } + done(); + }); + }); + }); it('should validate a valid piped response', function (done) { var cPetStoreJson = _.cloneDeep(petStoreJson); From 7f9cb814213619667068bc70bcef13d2b238657c Mon Sep 17 00:00:00 2001 From: Ulf Seltmann Date: Mon, 19 Dec 2016 17:52:59 +0100 Subject: [PATCH 2/2] added test for stream validation bug #463 --- test/2.0/test-middleware-swagger-validator.js | 51 ++++++++++++++++++ test/image.png | Bin 0 -> 156 bytes 2 files changed, 51 insertions(+) create mode 100644 test/image.png diff --git a/test/2.0/test-middleware-swagger-validator.js b/test/2.0/test-middleware-swagger-validator.js index 45130672b2..7a36102375 100644 --- a/test/2.0/test-middleware-swagger-validator.js +++ b/test/2.0/test-middleware-swagger-validator.js @@ -37,6 +37,8 @@ var async = require('async'); var helpers = require('../helpers'); var request = require('supertest'); var stream = require('stream'); +var fs = require('fs'); +var crypto = require('crypto'); var petStoreJson = _.cloneDeep(require('../../samples/2.0/petstore.json')); @@ -1575,6 +1577,55 @@ describe('Swagger Validator Middleware v2.0', function () { }); }); + it('should validate file and return it (issue #463)', function (done) { + var cPetStore = _.cloneDeep(petStoreJson); + + cPetStore.paths['/image'] = { + get: { + summary: 'Get image', + description: 'Retrieves image.', + operationId: 'getImage', + produces: ['image/png'], + responses: { + '200': { + description: 'OK', + schema: { + type: 'file' + } + } + } + } + }; + + helpers.createServer([cPetStore], { + swaggerRouterOptions: { + controllers: { + getImage: function (req, res) { + res.setHeader('Content-type', 'image/png'); + return fs.createReadStream('test/image.png').pipe(res); + } + } + }, + swaggerValidatorOptions: { + validateResponse: true + } + }, function (app) { + try { + request(app) + .get('/api/image') + .end(function(err, res) { + assert.strictEqual( + crypto.createHash('sha256').update(fs.readFileSync('test/image.png')).digest('hex'), //expected + crypto.createHash('sha256').update(res.body).digest('hex') //actual + ); + done(err); + }); + } catch (err) { + done(); + } + }); + }); + it('should not throw an error for empty responses that validate void (new issue)', function (done) { var cPetStoreJson = _.cloneDeep(petStoreJson); diff --git a/test/image.png b/test/image.png new file mode 100644 index 0000000000000000000000000000000000000000..bdcadbd1d0391b2589836cef6f5d0ffc08822452 GIT binary patch literal 156 zcmeAS@N?(olHy`uVBq!ia0vp^j6lrI!2~1?-xTZsQk(@Ik;OnUVGw3ym^DWND9B#o z>Fdh=fJc~LSb3_%<$j=$Y-UJAiF1B#Zfaf$kjuc}T$GwvlA5AWo>`Ki;O^-gkfN8$ t4ip#iba4#fxSssu|9^X7W@ctX35NPKW}z#W*#bb?JYD@<);T3K0RW9_BvJqX literal 0 HcmV?d00001