756 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			756 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 'use strict'
 | |
| 
 | |
| var assert = require('node:assert')
 | |
| var AsyncLocalStorage = require('node:async_hooks').AsyncLocalStorage
 | |
| const { Buffer } = require('node:buffer');
 | |
| 
 | |
| var express = require('..')
 | |
| var request = require('supertest')
 | |
| 
 | |
| describe('express.json()', function () {
 | |
|   it('should parse JSON', function (done) {
 | |
|     request(createApp())
 | |
|       .post('/')
 | |
|       .set('Content-Type', 'application/json')
 | |
|       .send('{"user":"tobi"}')
 | |
|       .expect(200, '{"user":"tobi"}', done)
 | |
|   })
 | |
| 
 | |
|   it('should handle Content-Length: 0', function (done) {
 | |
|     request(createApp())
 | |
|       .post('/')
 | |
|       .set('Content-Type', 'application/json')
 | |
|       .set('Content-Length', '0')
 | |
|       .expect(200, '{}', done)
 | |
|   })
 | |
| 
 | |
|   it('should handle empty message-body', function (done) {
 | |
|     request(createApp())
 | |
|       .post('/')
 | |
|       .set('Content-Type', 'application/json')
 | |
|       .set('Transfer-Encoding', 'chunked')
 | |
|       .expect(200, '{}', done)
 | |
|   })
 | |
| 
 | |
|   it('should handle no message-body', function (done) {
 | |
|     request(createApp())
 | |
|       .post('/')
 | |
|       .set('Content-Type', 'application/json')
 | |
|       .unset('Transfer-Encoding')
 | |
|       .expect(200, '{}', done)
 | |
|   })
 | |
| 
 | |
|   // The old node error message modification in body parser is catching this
 | |
|   it('should 400 when only whitespace', function (done) {
 | |
|     request(createApp())
 | |
|       .post('/')
 | |
|       .set('Content-Type', 'application/json')
 | |
|       .send('  \n')
 | |
|       .expect(400, '[entity.parse.failed] ' + parseError(' \n'), done)
 | |
|   })
 | |
| 
 | |
|   it('should 400 when invalid content-length', function (done) {
 | |
|     var app = express()
 | |
| 
 | |
|     app.use(function (req, res, next) {
 | |
|       req.headers['content-length'] = '20' // bad length
 | |
|       next()
 | |
|     })
 | |
| 
 | |
|     app.use(express.json())
 | |
| 
 | |
|     app.post('/', function (req, res) {
 | |
|       res.json(req.body)
 | |
|     })
 | |
| 
 | |
|     request(app)
 | |
|       .post('/')
 | |
|       .set('Content-Type', 'application/json')
 | |
|       .send('{"str":')
 | |
|       .expect(400, /content length/, done)
 | |
|   })
 | |
| 
 | |
|   it('should handle duplicated middleware', function (done) {
 | |
|     var app = express()
 | |
| 
 | |
|     app.use(express.json())
 | |
|     app.use(express.json())
 | |
| 
 | |
|     app.post('/', function (req, res) {
 | |
|       res.json(req.body)
 | |
|     })
 | |
| 
 | |
|     request(app)
 | |
|       .post('/')
 | |
|       .set('Content-Type', 'application/json')
 | |
|       .send('{"user":"tobi"}')
 | |
|       .expect(200, '{"user":"tobi"}', done)
 | |
|   })
 | |
| 
 | |
|   describe('when JSON is invalid', function () {
 | |
|     before(function () {
 | |
|       this.app = createApp()
 | |
|     })
 | |
| 
 | |
|     it('should 400 for bad token', function (done) {
 | |
|       request(this.app)
 | |
|         .post('/')
 | |
|         .set('Content-Type', 'application/json')
 | |
|         .send('{:')
 | |
|         .expect(400, '[entity.parse.failed] ' + parseError('{:'), done)
 | |
|     })
 | |
| 
 | |
|     it('should 400 for incomplete', function (done) {
 | |
|       request(this.app)
 | |
|         .post('/')
 | |
|         .set('Content-Type', 'application/json')
 | |
|         .send('{"user"')
 | |
|         .expect(400, '[entity.parse.failed] ' + parseError('{"user"'), done)
 | |
|     })
 | |
| 
 | |
|     it('should include original body on error object', function (done) {
 | |
|       request(this.app)
 | |
|         .post('/')
 | |
|         .set('Content-Type', 'application/json')
 | |
|         .set('X-Error-Property', 'body')
 | |
|         .send(' {"user"')
 | |
|         .expect(400, ' {"user"', done)
 | |
|     })
 | |
|   })
 | |
| 
 | |
|   describe('with limit option', function () {
 | |
|     it('should 413 when over limit with Content-Length', function (done) {
 | |
|       var buf = Buffer.alloc(1024, '.')
 | |
|       request(createApp({ limit: '1kb' }))
 | |
|         .post('/')
 | |
|         .set('Content-Type', 'application/json')
 | |
|         .set('Content-Length', '1034')
 | |
|         .send(JSON.stringify({ str: buf.toString() }))
 | |
|         .expect(413, '[entity.too.large] request entity too large', done)
 | |
|     })
 | |
| 
 | |
|     it('should 413 when over limit with chunked encoding', function (done) {
 | |
|       var app = createApp({ limit: '1kb' })
 | |
|       var buf = Buffer.alloc(1024, '.')
 | |
|       var test = request(app).post('/')
 | |
|       test.set('Content-Type', 'application/json')
 | |
|       test.set('Transfer-Encoding', 'chunked')
 | |
|       test.write('{"str":')
 | |
|       test.write('"' + buf.toString() + '"}')
 | |
|       test.expect(413, done)
 | |
|     })
 | |
| 
 | |
|     it('should 413 when inflated body over limit', function (done) {
 | |
|       var app = createApp({ limit: '1kb' })
 | |
|       var test = request(app).post('/')
 | |
|       test.set('Content-Encoding', 'gzip')
 | |
|       test.set('Content-Type', 'application/json')
 | |
|       test.write(Buffer.from('1f8b080000000000000aab562a2e2952b252d21b05a360148c58a0540b0066f7ce1e0a040000', 'hex'))
 | |
|       test.expect(413, done)
 | |
|     })
 | |
| 
 | |
|     it('should accept number of bytes', function (done) {
 | |
|       var buf = Buffer.alloc(1024, '.')
 | |
|       request(createApp({ limit: 1024 }))
 | |
|         .post('/')
 | |
|         .set('Content-Type', 'application/json')
 | |
|         .send(JSON.stringify({ str: buf.toString() }))
 | |
|         .expect(413, done)
 | |
|     })
 | |
| 
 | |
|     it('should not change when options altered', function (done) {
 | |
|       var buf = Buffer.alloc(1024, '.')
 | |
|       var options = { limit: '1kb' }
 | |
|       var app = createApp(options)
 | |
| 
 | |
|       options.limit = '100kb'
 | |
| 
 | |
|       request(app)
 | |
|         .post('/')
 | |
|         .set('Content-Type', 'application/json')
 | |
|         .send(JSON.stringify({ str: buf.toString() }))
 | |
|         .expect(413, done)
 | |
|     })
 | |
| 
 | |
|     it('should not hang response', function (done) {
 | |
|       var buf = Buffer.alloc(10240, '.')
 | |
|       var app = createApp({ limit: '8kb' })
 | |
|       var test = request(app).post('/')
 | |
|       test.set('Content-Type', 'application/json')
 | |
|       test.write(buf)
 | |
|       test.write(buf)
 | |
|       test.write(buf)
 | |
|       test.expect(413, done)
 | |
|     })
 | |
| 
 | |
|     it('should not error when inflating', function (done) {
 | |
|       var app = createApp({ limit: '1kb' })
 | |
|       var test = request(app).post('/')
 | |
|       test.set('Content-Encoding', 'gzip')
 | |
|       test.set('Content-Type', 'application/json')
 | |
|       test.write(Buffer.from('1f8b080000000000000aab562a2e2952b252d21b05a360148c58a0540b0066f7ce1e0a0400', 'hex'))
 | |
|       test.expect(413, done)
 | |
|     })
 | |
|   })
 | |
| 
 | |
|   describe('with inflate option', function () {
 | |
|     describe('when false', function () {
 | |
|       before(function () {
 | |
|         this.app = createApp({ inflate: false })
 | |
|       })
 | |
| 
 | |
|       it('should not accept content-encoding', function (done) {
 | |
|         var test = request(this.app).post('/')
 | |
|         test.set('Content-Encoding', 'gzip')
 | |
|         test.set('Content-Type', 'application/json')
 | |
|         test.write(Buffer.from('1f8b080000000000000bab56ca4bcc4d55b2527ab16e97522d00515be1cc0e000000', 'hex'))
 | |
|         test.expect(415, '[encoding.unsupported] content encoding unsupported', done)
 | |
|       })
 | |
|     })
 | |
| 
 | |
|     describe('when true', function () {
 | |
|       before(function () {
 | |
|         this.app = createApp({ inflate: true })
 | |
|       })
 | |
| 
 | |
|       it('should accept content-encoding', function (done) {
 | |
|         var test = request(this.app).post('/')
 | |
|         test.set('Content-Encoding', 'gzip')
 | |
|         test.set('Content-Type', 'application/json')
 | |
|         test.write(Buffer.from('1f8b080000000000000bab56ca4bcc4d55b2527ab16e97522d00515be1cc0e000000', 'hex'))
 | |
|         test.expect(200, '{"name":"论"}', done)
 | |
|       })
 | |
|     })
 | |
|   })
 | |
| 
 | |
|   describe('with strict option', function () {
 | |
|     describe('when undefined', function () {
 | |
|       before(function () {
 | |
|         this.app = createApp()
 | |
|       })
 | |
| 
 | |
|       it('should 400 on primitives', function (done) {
 | |
|         request(this.app)
 | |
|           .post('/')
 | |
|           .set('Content-Type', 'application/json')
 | |
|           .send('true')
 | |
|           .expect(400, '[entity.parse.failed] ' + parseError('#rue').replace(/#/g, 't'), done)
 | |
|       })
 | |
|     })
 | |
| 
 | |
|     describe('when false', function () {
 | |
|       before(function () {
 | |
|         this.app = createApp({ strict: false })
 | |
|       })
 | |
| 
 | |
|       it('should parse primitives', function (done) {
 | |
|         request(this.app)
 | |
|           .post('/')
 | |
|           .set('Content-Type', 'application/json')
 | |
|           .send('true')
 | |
|           .expect(200, 'true', done)
 | |
|       })
 | |
|     })
 | |
| 
 | |
|     describe('when true', function () {
 | |
|       before(function () {
 | |
|         this.app = createApp({ strict: true })
 | |
|       })
 | |
| 
 | |
|       it('should not parse primitives', function (done) {
 | |
|         request(this.app)
 | |
|           .post('/')
 | |
|           .set('Content-Type', 'application/json')
 | |
|           .send('true')
 | |
|           .expect(400, '[entity.parse.failed] ' + parseError('#rue').replace(/#/g, 't'), done)
 | |
|       })
 | |
| 
 | |
|       it('should not parse primitives with leading whitespaces', function (done) {
 | |
|         request(this.app)
 | |
|           .post('/')
 | |
|           .set('Content-Type', 'application/json')
 | |
|           .send('    true')
 | |
|           .expect(400, '[entity.parse.failed] ' + parseError('    #rue').replace(/#/g, 't'), done)
 | |
|       })
 | |
| 
 | |
|       it('should allow leading whitespaces in JSON', function (done) {
 | |
|         request(this.app)
 | |
|           .post('/')
 | |
|           .set('Content-Type', 'application/json')
 | |
|           .send('   { "user": "tobi" }')
 | |
|           .expect(200, '{"user":"tobi"}', done)
 | |
|       })
 | |
| 
 | |
|       it('should include correct message in stack trace', function (done) {
 | |
|         request(this.app)
 | |
|           .post('/')
 | |
|           .set('Content-Type', 'application/json')
 | |
|           .set('X-Error-Property', 'stack')
 | |
|           .send('true')
 | |
|           .expect(400)
 | |
|           .expect(shouldContainInBody(parseError('#rue').replace(/#/g, 't')))
 | |
|           .end(done)
 | |
|       })
 | |
|     })
 | |
|   })
 | |
| 
 | |
|   describe('with type option', function () {
 | |
|     describe('when "application/vnd.api+json"', function () {
 | |
|       before(function () {
 | |
|         this.app = createApp({ type: 'application/vnd.api+json' })
 | |
|       })
 | |
| 
 | |
|       it('should parse JSON for custom type', function (done) {
 | |
|         request(this.app)
 | |
|           .post('/')
 | |
|           .set('Content-Type', 'application/vnd.api+json')
 | |
|           .send('{"user":"tobi"}')
 | |
|           .expect(200, '{"user":"tobi"}', done)
 | |
|       })
 | |
| 
 | |
|       it('should ignore standard type', function (done) {
 | |
|         request(this.app)
 | |
|           .post('/')
 | |
|           .set('Content-Type', 'application/json')
 | |
|           .send('{"user":"tobi"}')
 | |
|           .expect(200, '', done)
 | |
|       })
 | |
|     })
 | |
| 
 | |
|     describe('when ["application/json", "application/vnd.api+json"]', function () {
 | |
|       before(function () {
 | |
|         this.app = createApp({
 | |
|           type: ['application/json', 'application/vnd.api+json']
 | |
|         })
 | |
|       })
 | |
| 
 | |
|       it('should parse JSON for "application/json"', function (done) {
 | |
|         request(this.app)
 | |
|           .post('/')
 | |
|           .set('Content-Type', 'application/json')
 | |
|           .send('{"user":"tobi"}')
 | |
|           .expect(200, '{"user":"tobi"}', done)
 | |
|       })
 | |
| 
 | |
|       it('should parse JSON for "application/vnd.api+json"', function (done) {
 | |
|         request(this.app)
 | |
|           .post('/')
 | |
|           .set('Content-Type', 'application/vnd.api+json')
 | |
|           .send('{"user":"tobi"}')
 | |
|           .expect(200, '{"user":"tobi"}', done)
 | |
|       })
 | |
| 
 | |
|       it('should ignore "application/x-json"', function (done) {
 | |
|         request(this.app)
 | |
|           .post('/')
 | |
|           .set('Content-Type', 'application/x-json')
 | |
|           .send('{"user":"tobi"}')
 | |
|           .expect(200, '', done)
 | |
|       })
 | |
|     })
 | |
| 
 | |
|     describe('when a function', function () {
 | |
|       it('should parse when truthy value returned', function (done) {
 | |
|         var app = createApp({ type: accept })
 | |
| 
 | |
|         function accept (req) {
 | |
|           return req.headers['content-type'] === 'application/vnd.api+json'
 | |
|         }
 | |
| 
 | |
|         request(app)
 | |
|           .post('/')
 | |
|           .set('Content-Type', 'application/vnd.api+json')
 | |
|           .send('{"user":"tobi"}')
 | |
|           .expect(200, '{"user":"tobi"}', done)
 | |
|       })
 | |
| 
 | |
|       it('should work without content-type', function (done) {
 | |
|         var app = createApp({ type: accept })
 | |
| 
 | |
|         function accept (req) {
 | |
|           return true
 | |
|         }
 | |
| 
 | |
|         var test = request(app).post('/')
 | |
|         test.write('{"user":"tobi"}')
 | |
|         test.expect(200, '{"user":"tobi"}', done)
 | |
|       })
 | |
| 
 | |
|       it('should not invoke without a body', function (done) {
 | |
|         var app = createApp({ type: accept })
 | |
| 
 | |
|         function accept (req) {
 | |
|           throw new Error('oops!')
 | |
|         }
 | |
| 
 | |
|         request(app)
 | |
|           .get('/')
 | |
|           .expect(404, done)
 | |
|       })
 | |
|     })
 | |
|   })
 | |
| 
 | |
|   describe('with verify option', function () {
 | |
|     it('should assert value if function', function () {
 | |
|       assert.throws(createApp.bind(null, { verify: 'lol' }),
 | |
|         /TypeError: option verify must be function/)
 | |
|     })
 | |
| 
 | |
|     it('should error from verify', function (done) {
 | |
|       var app = createApp({
 | |
|         verify: function (req, res, buf) {
 | |
|           if (buf[0] === 0x5b) throw new Error('no arrays')
 | |
|         }
 | |
|       })
 | |
| 
 | |
|       request(app)
 | |
|         .post('/')
 | |
|         .set('Content-Type', 'application/json')
 | |
|         .send('["tobi"]')
 | |
|         .expect(403, '[entity.verify.failed] no arrays', done)
 | |
|     })
 | |
| 
 | |
|     it('should allow custom codes', function (done) {
 | |
|       var app = createApp({
 | |
|         verify: function (req, res, buf) {
 | |
|           if (buf[0] !== 0x5b) return
 | |
|           var err = new Error('no arrays')
 | |
|           err.status = 400
 | |
|           throw err
 | |
|         }
 | |
|       })
 | |
| 
 | |
|       request(app)
 | |
|         .post('/')
 | |
|         .set('Content-Type', 'application/json')
 | |
|         .send('["tobi"]')
 | |
|         .expect(400, '[entity.verify.failed] no arrays', done)
 | |
|     })
 | |
| 
 | |
|     it('should allow custom type', function (done) {
 | |
|       var app = createApp({
 | |
|         verify: function (req, res, buf) {
 | |
|           if (buf[0] !== 0x5b) return
 | |
|           var err = new Error('no arrays')
 | |
|           err.type = 'foo.bar'
 | |
|           throw err
 | |
|         }
 | |
|       })
 | |
| 
 | |
|       request(app)
 | |
|         .post('/')
 | |
|         .set('Content-Type', 'application/json')
 | |
|         .send('["tobi"]')
 | |
|         .expect(403, '[foo.bar] no arrays', done)
 | |
|     })
 | |
| 
 | |
|     it('should include original body on error object', function (done) {
 | |
|       var app = createApp({
 | |
|         verify: function (req, res, buf) {
 | |
|           if (buf[0] === 0x5b) throw new Error('no arrays')
 | |
|         }
 | |
|       })
 | |
| 
 | |
|       request(app)
 | |
|         .post('/')
 | |
|         .set('Content-Type', 'application/json')
 | |
|         .set('X-Error-Property', 'body')
 | |
|         .send('["tobi"]')
 | |
|         .expect(403, '["tobi"]', done)
 | |
|     })
 | |
| 
 | |
|     it('should allow pass-through', function (done) {
 | |
|       var app = createApp({
 | |
|         verify: function (req, res, buf) {
 | |
|           if (buf[0] === 0x5b) throw new Error('no arrays')
 | |
|         }
 | |
|       })
 | |
| 
 | |
|       request(app)
 | |
|         .post('/')
 | |
|         .set('Content-Type', 'application/json')
 | |
|         .send('{"user":"tobi"}')
 | |
|         .expect(200, '{"user":"tobi"}', done)
 | |
|     })
 | |
| 
 | |
|     it('should work with different charsets', function (done) {
 | |
|       var app = createApp({
 | |
|         verify: function (req, res, buf) {
 | |
|           if (buf[0] === 0x5b) throw new Error('no arrays')
 | |
|         }
 | |
|       })
 | |
| 
 | |
|       var test = request(app).post('/')
 | |
|       test.set('Content-Type', 'application/json; charset=utf-16')
 | |
|       test.write(Buffer.from('feff007b0022006e0061006d00650022003a00228bba0022007d', 'hex'))
 | |
|       test.expect(200, '{"name":"论"}', done)
 | |
|     })
 | |
| 
 | |
|     it('should 415 on unknown charset prior to verify', function (done) {
 | |
|       var app = createApp({
 | |
|         verify: function (req, res, buf) {
 | |
|           throw new Error('unexpected verify call')
 | |
|         }
 | |
|       })
 | |
| 
 | |
|       var test = request(app).post('/')
 | |
|       test.set('Content-Type', 'application/json; charset=x-bogus')
 | |
|       test.write(Buffer.from('00000000', 'hex'))
 | |
|       test.expect(415, '[charset.unsupported] unsupported charset "X-BOGUS"', done)
 | |
|     })
 | |
|   })
 | |
| 
 | |
|   describe('async local storage', function () {
 | |
|     before(function () {
 | |
|       var app = express()
 | |
|       var store = { foo: 'bar' }
 | |
| 
 | |
|       app.use(function (req, res, next) {
 | |
|         req.asyncLocalStorage = new AsyncLocalStorage()
 | |
|         req.asyncLocalStorage.run(store, next)
 | |
|       })
 | |
| 
 | |
|       app.use(express.json())
 | |
| 
 | |
|       app.use(function (req, res, next) {
 | |
|         var local = req.asyncLocalStorage.getStore()
 | |
| 
 | |
|         if (local) {
 | |
|           res.setHeader('x-store-foo', String(local.foo))
 | |
|         }
 | |
| 
 | |
|         next()
 | |
|       })
 | |
| 
 | |
|       app.use(function (err, req, res, next) {
 | |
|         var local = req.asyncLocalStorage.getStore()
 | |
| 
 | |
|         if (local) {
 | |
|           res.setHeader('x-store-foo', String(local.foo))
 | |
|         }
 | |
| 
 | |
|         res.status(err.status || 500)
 | |
|         res.send('[' + err.type + '] ' + err.message)
 | |
|       })
 | |
| 
 | |
|       app.post('/', function (req, res) {
 | |
|         res.json(req.body)
 | |
|       })
 | |
| 
 | |
|       this.app = app
 | |
|     })
 | |
| 
 | |
|     it('should persist store', function (done) {
 | |
|       request(this.app)
 | |
|         .post('/')
 | |
|         .set('Content-Type', 'application/json')
 | |
|         .send('{"user":"tobi"}')
 | |
|         .expect(200)
 | |
|         .expect('x-store-foo', 'bar')
 | |
|         .expect('{"user":"tobi"}')
 | |
|         .end(done)
 | |
|     })
 | |
| 
 | |
|     it('should persist store when unmatched content-type', function (done) {
 | |
|       request(this.app)
 | |
|         .post('/')
 | |
|         .set('Content-Type', 'application/fizzbuzz')
 | |
|         .send('buzz')
 | |
|         .expect(200)
 | |
|         .expect('x-store-foo', 'bar')
 | |
|         .expect('')
 | |
|         .end(done)
 | |
|     })
 | |
| 
 | |
|     it('should persist store when inflated', function (done) {
 | |
|       var test = request(this.app).post('/')
 | |
|       test.set('Content-Encoding', 'gzip')
 | |
|       test.set('Content-Type', 'application/json')
 | |
|       test.write(Buffer.from('1f8b080000000000000bab56ca4bcc4d55b2527ab16e97522d00515be1cc0e000000', 'hex'))
 | |
|       test.expect(200)
 | |
|       test.expect('x-store-foo', 'bar')
 | |
|       test.expect('{"name":"论"}')
 | |
|       test.end(done)
 | |
|     })
 | |
| 
 | |
|     it('should persist store when inflate error', function (done) {
 | |
|       var test = request(this.app).post('/')
 | |
|       test.set('Content-Encoding', 'gzip')
 | |
|       test.set('Content-Type', 'application/json')
 | |
|       test.write(Buffer.from('1f8b080000000000000bab56cc4d55b2527ab16e97522d00515be1cc0e000000', 'hex'))
 | |
|       test.expect(400)
 | |
|       test.expect('x-store-foo', 'bar')
 | |
|       test.end(done)
 | |
|     })
 | |
| 
 | |
|     it('should persist store when parse error', function (done) {
 | |
|       request(this.app)
 | |
|         .post('/')
 | |
|         .set('Content-Type', 'application/json')
 | |
|         .send('{"user":')
 | |
|         .expect(400)
 | |
|         .expect('x-store-foo', 'bar')
 | |
|         .end(done)
 | |
|     })
 | |
| 
 | |
|     it('should persist store when limit exceeded', function (done) {
 | |
|       request(this.app)
 | |
|         .post('/')
 | |
|         .set('Content-Type', 'application/json')
 | |
|         .send('{"user":"' + Buffer.alloc(1024 * 100, '.').toString() + '"}')
 | |
|         .expect(413)
 | |
|         .expect('x-store-foo', 'bar')
 | |
|         .end(done)
 | |
|     })
 | |
|   })
 | |
| 
 | |
|   describe('charset', function () {
 | |
|     before(function () {
 | |
|       this.app = createApp()
 | |
|     })
 | |
| 
 | |
|     it('should parse utf-8', function (done) {
 | |
|       var test = request(this.app).post('/')
 | |
|       test.set('Content-Type', 'application/json; charset=utf-8')
 | |
|       test.write(Buffer.from('7b226e616d65223a22e8aeba227d', 'hex'))
 | |
|       test.expect(200, '{"name":"论"}', done)
 | |
|     })
 | |
| 
 | |
|     it('should parse utf-16', function (done) {
 | |
|       var test = request(this.app).post('/')
 | |
|       test.set('Content-Type', 'application/json; charset=utf-16')
 | |
|       test.write(Buffer.from('feff007b0022006e0061006d00650022003a00228bba0022007d', 'hex'))
 | |
|       test.expect(200, '{"name":"论"}', done)
 | |
|     })
 | |
| 
 | |
|     it('should parse when content-length != char length', function (done) {
 | |
|       var test = request(this.app).post('/')
 | |
|       test.set('Content-Type', 'application/json; charset=utf-8')
 | |
|       test.set('Content-Length', '13')
 | |
|       test.write(Buffer.from('7b2274657374223a22c3a5227d', 'hex'))
 | |
|       test.expect(200, '{"test":"å"}', done)
 | |
|     })
 | |
| 
 | |
|     it('should default to utf-8', function (done) {
 | |
|       var test = request(this.app).post('/')
 | |
|       test.set('Content-Type', 'application/json')
 | |
|       test.write(Buffer.from('7b226e616d65223a22e8aeba227d', 'hex'))
 | |
|       test.expect(200, '{"name":"论"}', done)
 | |
|     })
 | |
| 
 | |
|     it('should fail on unknown charset', function (done) {
 | |
|       var test = request(this.app).post('/')
 | |
|       test.set('Content-Type', 'application/json; charset=koi8-r')
 | |
|       test.write(Buffer.from('7b226e616d65223a22cec5d4227d', 'hex'))
 | |
|       test.expect(415, '[charset.unsupported] unsupported charset "KOI8-R"', done)
 | |
|     })
 | |
|   })
 | |
| 
 | |
|   describe('encoding', function () {
 | |
|     before(function () {
 | |
|       this.app = createApp({ limit: '1kb' })
 | |
|     })
 | |
| 
 | |
|     it('should parse without encoding', function (done) {
 | |
|       var test = request(this.app).post('/')
 | |
|       test.set('Content-Type', 'application/json')
 | |
|       test.write(Buffer.from('7b226e616d65223a22e8aeba227d', 'hex'))
 | |
|       test.expect(200, '{"name":"论"}', done)
 | |
|     })
 | |
| 
 | |
|     it('should support identity encoding', function (done) {
 | |
|       var test = request(this.app).post('/')
 | |
|       test.set('Content-Encoding', 'identity')
 | |
|       test.set('Content-Type', 'application/json')
 | |
|       test.write(Buffer.from('7b226e616d65223a22e8aeba227d', 'hex'))
 | |
|       test.expect(200, '{"name":"论"}', done)
 | |
|     })
 | |
| 
 | |
|     it('should support gzip encoding', function (done) {
 | |
|       var test = request(this.app).post('/')
 | |
|       test.set('Content-Encoding', 'gzip')
 | |
|       test.set('Content-Type', 'application/json')
 | |
|       test.write(Buffer.from('1f8b080000000000000bab56ca4bcc4d55b2527ab16e97522d00515be1cc0e000000', 'hex'))
 | |
|       test.expect(200, '{"name":"论"}', done)
 | |
|     })
 | |
| 
 | |
|     it('should support deflate encoding', function (done) {
 | |
|       var test = request(this.app).post('/')
 | |
|       test.set('Content-Encoding', 'deflate')
 | |
|       test.set('Content-Type', 'application/json')
 | |
|       test.write(Buffer.from('789cab56ca4bcc4d55b2527ab16e97522d00274505ac', 'hex'))
 | |
|       test.expect(200, '{"name":"论"}', done)
 | |
|     })
 | |
| 
 | |
|     it('should be case-insensitive', function (done) {
 | |
|       var test = request(this.app).post('/')
 | |
|       test.set('Content-Encoding', 'GZIP')
 | |
|       test.set('Content-Type', 'application/json')
 | |
|       test.write(Buffer.from('1f8b080000000000000bab56ca4bcc4d55b2527ab16e97522d00515be1cc0e000000', 'hex'))
 | |
|       test.expect(200, '{"name":"论"}', done)
 | |
|     })
 | |
| 
 | |
|     it('should 415 on unknown encoding', function (done) {
 | |
|       var test = request(this.app).post('/')
 | |
|       test.set('Content-Encoding', 'nulls')
 | |
|       test.set('Content-Type', 'application/json')
 | |
|       test.write(Buffer.from('000000000000', 'hex'))
 | |
|       test.expect(415, '[encoding.unsupported] unsupported content encoding "nulls"', done)
 | |
|     })
 | |
| 
 | |
|     it('should 400 on malformed encoding', function (done) {
 | |
|       var test = request(this.app).post('/')
 | |
|       test.set('Content-Encoding', 'gzip')
 | |
|       test.set('Content-Type', 'application/json')
 | |
|       test.write(Buffer.from('1f8b080000000000000bab56cc4d55b2527ab16e97522d00515be1cc0e000000', 'hex'))
 | |
|       test.expect(400, done)
 | |
|     })
 | |
| 
 | |
|     it('should 413 when inflated value exceeds limit', function (done) {
 | |
|       // gzip'd data exceeds 1kb, but deflated below 1kb
 | |
|       var test = request(this.app).post('/')
 | |
|       test.set('Content-Encoding', 'gzip')
 | |
|       test.set('Content-Type', 'application/json')
 | |
|       test.write(Buffer.from('1f8b080000000000000bedc1010d000000c2a0f74f6d0f071400000000000000', 'hex'))
 | |
|       test.write(Buffer.from('0000000000000000000000000000000000000000000000000000000000000000', 'hex'))
 | |
|       test.write(Buffer.from('0000000000000000004f0625b3b71650c30000', 'hex'))
 | |
|       test.expect(413, done)
 | |
|     })
 | |
|   })
 | |
| })
 | |
| 
 | |
| function createApp (options) {
 | |
|   var app = express()
 | |
| 
 | |
|   app.use(express.json(options))
 | |
| 
 | |
|   app.use(function (err, req, res, next) {
 | |
|     // console.log(err)
 | |
|     res.status(err.status || 500)
 | |
|     res.send(String(req.headers['x-error-property']
 | |
|       ? err[req.headers['x-error-property']]
 | |
|       : ('[' + err.type + '] ' + err.message)))
 | |
|   })
 | |
| 
 | |
|   app.post('/', function (req, res) {
 | |
|     res.json(req.body)
 | |
|   })
 | |
| 
 | |
|   return app
 | |
| }
 | |
| 
 | |
| function parseError (str) {
 | |
|   try {
 | |
|     JSON.parse(str); throw new SyntaxError('strict violation')
 | |
|   } catch (e) {
 | |
|     return e.message
 | |
|   }
 | |
| }
 | |
| 
 | |
| function shouldContainInBody (str) {
 | |
|   return function (res) {
 | |
|     assert.ok(res.text.indexOf(str) !== -1,
 | |
|       'expected \'' + res.text + '\' to contain \'' + str + '\'')
 | |
|   }
 | |
| }
 |