3 var assert
= require('assert')
4 var asyncHooks
= tryRequire('async_hooks')
5 var Buffer
= require('safe-buffer').Buffer
6 var express
= require('..')
7 var request
= require('supertest')
9 var describeAsyncHooks
= typeof asyncHooks
.AsyncLocalStorage
=== 'function'
13 describe('express.raw()', function () {
15 this.app
= createApp()
18 it('should parse application/octet-stream', function (done
) {
21 .set('Content-Type', 'application/octet-stream')
22 .send('the user is tobi')
23 .expect(200, { buf
: '746865207573657220697320746f6269' }, done
)
26 it('should 400 when invalid content-length', function (done
) {
29 app
.use(function (req
, res
, next
) {
30 req
.headers
['content-length'] = '20' // bad length
34 app
.use(express
.raw())
36 app
.post('/', function (req
, res
) {
37 if (Buffer
.isBuffer(req
.body
)) {
38 res
.json({ buf
: req
.body
.toString('hex') })
46 .set('Content-Type', 'application/octet-stream')
48 .expect(400, /content length/, done
)
51 it('should handle Content-Length: 0', function (done
) {
54 .set('Content-Type', 'application/octet-stream')
55 .set('Content-Length', '0')
56 .expect(200, { buf
: '' }, done
)
59 it('should handle empty message-body', function (done
) {
62 .set('Content-Type', 'application/octet-stream')
63 .set('Transfer-Encoding', 'chunked')
65 .expect(200, { buf
: '' }, done
)
68 it('should handle duplicated middleware', function (done
) {
71 app
.use(express
.raw())
72 app
.use(express
.raw())
74 app
.post('/', function (req
, res
) {
75 if (Buffer
.isBuffer(req
.body
)) {
76 res
.json({ buf
: req
.body
.toString('hex') })
84 .set('Content-Type', 'application/octet-stream')
85 .send('the user is tobi')
86 .expect(200, { buf
: '746865207573657220697320746f6269' }, done
)
89 describe('with limit option', function () {
90 it('should 413 when over limit with Content-Length', function (done
) {
91 var buf
= Buffer
.alloc(1028, '.')
92 var app
= createApp({ limit
: '1kb' })
93 var test
= request(app
).post('/')
94 test
.set('Content-Type', 'application/octet-stream')
95 test
.set('Content-Length', '1028')
97 test
.expect(413, done
)
100 it('should 413 when over limit with chunked encoding', function (done
) {
101 var buf
= Buffer
.alloc(1028, '.')
102 var app
= createApp({ limit
: '1kb' })
103 var test
= request(app
).post('/')
104 test
.set('Content-Type', 'application/octet-stream')
105 test
.set('Transfer-Encoding', 'chunked')
107 test
.expect(413, done
)
110 it('should 413 when inflated body over limit', function (done
) {
111 var app
= createApp({ limit
: '1kb' })
112 var test
= request(app
).post('/')
113 test
.set('Content-Encoding', 'gzip')
114 test
.set('Content-Type', 'application/octet-stream')
115 test
.write(Buffer
.from('1f8b080000000000000ad3d31b05a360148c64000087e5a14704040000', 'hex'))
116 test
.expect(413, done
)
119 it('should accept number of bytes', function (done
) {
120 var buf
= Buffer
.alloc(1028, '.')
121 var app
= createApp({ limit
: 1024 })
122 var test
= request(app
).post('/')
123 test
.set('Content-Type', 'application/octet-stream')
125 test
.expect(413, done
)
128 it('should not change when options altered', function (done
) {
129 var buf
= Buffer
.alloc(1028, '.')
130 var options
= { limit
: '1kb' }
131 var app
= createApp(options
)
133 options
.limit
= '100kb'
135 var test
= request(app
).post('/')
136 test
.set('Content-Type', 'application/octet-stream')
138 test
.expect(413, done
)
141 it('should not hang response', function (done
) {
142 var buf
= Buffer
.alloc(10240, '.')
143 var app
= createApp({ limit
: '8kb' })
144 var test
= request(app
).post('/')
145 test
.set('Content-Type', 'application/octet-stream')
149 test
.expect(413, done
)
152 it('should not error when inflating', function (done
) {
153 var app
= createApp({ limit
: '1kb' })
154 var test
= request(app
).post('/')
155 test
.set('Content-Encoding', 'gzip')
156 test
.set('Content-Type', 'application/octet-stream')
157 test
.write(Buffer
.from('1f8b080000000000000ad3d31b05a360148c64000087e5a147040400', 'hex'))
158 test
.expect(413, done
)
162 describe('with inflate option', function () {
163 describe('when false', function () {
165 this.app
= createApp({ inflate
: false })
168 it('should not accept content-encoding', function (done
) {
169 var test
= request(this.app
).post('/')
170 test
.set('Content-Encoding', 'gzip')
171 test
.set('Content-Type', 'application/octet-stream')
172 test
.write(Buffer
.from('1f8b080000000000000bcb4bcc4db57db16e170099a4bad608000000', 'hex'))
173 test
.expect(415, '[encoding.unsupported] content encoding unsupported', done
)
177 describe('when true', function () {
179 this.app
= createApp({ inflate
: true })
182 it('should accept content-encoding', function (done
) {
183 var test
= request(this.app
).post('/')
184 test
.set('Content-Encoding', 'gzip')
185 test
.set('Content-Type', 'application/octet-stream')
186 test
.write(Buffer
.from('1f8b080000000000000bcb4bcc4db57db16e170099a4bad608000000', 'hex'))
187 test
.expect(200, { buf
: '6e616d653de8aeba' }, done
)
192 describe('with type option', function () {
193 describe('when "application/vnd+octets"', function () {
195 this.app
= createApp({ type
: 'application/vnd+octets' })
198 it('should parse for custom type', function (done
) {
199 var test
= request(this.app
).post('/')
200 test
.set('Content-Type', 'application/vnd+octets')
201 test
.write(Buffer
.from('000102', 'hex'))
202 test
.expect(200, { buf
: '000102' }, done
)
205 it('should ignore standard type', function (done
) {
206 var test
= request(this.app
).post('/')
207 test
.set('Content-Type', 'application/octet-stream')
208 test
.write(Buffer
.from('000102', 'hex'))
209 test
.expect(200, '', done
)
213 describe('when ["application/octet-stream", "application/vnd+octets"]', function () {
215 this.app
= createApp({
216 type
: ['application/octet-stream', 'application/vnd+octets']
220 it('should parse "application/octet-stream"', function (done
) {
221 var test
= request(this.app
).post('/')
222 test
.set('Content-Type', 'application/octet-stream')
223 test
.write(Buffer
.from('000102', 'hex'))
224 test
.expect(200, { buf
: '000102' }, done
)
227 it('should parse "application/vnd+octets"', function (done
) {
228 var test
= request(this.app
).post('/')
229 test
.set('Content-Type', 'application/vnd+octets')
230 test
.write(Buffer
.from('000102', 'hex'))
231 test
.expect(200, { buf
: '000102' }, done
)
234 it('should ignore "application/x-foo"', function (done
) {
235 var test
= request(this.app
).post('/')
236 test
.set('Content-Type', 'application/x-foo')
237 test
.write(Buffer
.from('000102', 'hex'))
238 test
.expect(200, '', done
)
242 describe('when a function', function () {
243 it('should parse when truthy value returned', function (done
) {
244 var app
= createApp({ type
: accept
})
246 function accept (req
) {
247 return req
.headers
['content-type'] === 'application/vnd.octet'
250 var test
= request(app
).post('/')
251 test
.set('Content-Type', 'application/vnd.octet')
252 test
.write(Buffer
.from('000102', 'hex'))
253 test
.expect(200, { buf
: '000102' }, done
)
256 it('should work without content-type', function (done
) {
257 var app
= createApp({ type
: accept
})
259 function accept (req
) {
263 var test
= request(app
).post('/')
264 test
.write(Buffer
.from('000102', 'hex'))
265 test
.expect(200, { buf
: '000102' }, done
)
268 it('should not invoke without a body', function (done
) {
269 var app
= createApp({ type
: accept
})
271 function accept (req
) {
272 throw new Error('oops!')
282 describe('with verify option', function () {
283 it('should assert value is function', function () {
284 assert
.throws(createApp
.bind(null, { verify
: 'lol' }),
285 /TypeError: option verify must be function/)
288 it('should error from verify', function (done
) {
289 var app
= createApp({
290 verify: function (req
, res
, buf
) {
291 if (buf
[0] === 0x00) throw new Error('no leading null')
295 var test
= request(app
).post('/')
296 test
.set('Content-Type', 'application/octet-stream')
297 test
.write(Buffer
.from('000102', 'hex'))
298 test
.expect(403, '[entity.verify.failed] no leading null', done
)
301 it('should allow custom codes', function (done
) {
302 var app
= createApp({
303 verify: function (req
, res
, buf
) {
304 if (buf
[0] !== 0x00) return
305 var err
= new Error('no leading null')
311 var test
= request(app
).post('/')
312 test
.set('Content-Type', 'application/octet-stream')
313 test
.write(Buffer
.from('000102', 'hex'))
314 test
.expect(400, '[entity.verify.failed] no leading null', done
)
317 it('should allow pass-through', function (done
) {
318 var app
= createApp({
319 verify: function (req
, res
, buf
) {
320 if (buf
[0] === 0x00) throw new Error('no leading null')
324 var test
= request(app
).post('/')
325 test
.set('Content-Type', 'application/octet-stream')
326 test
.write(Buffer
.from('0102', 'hex'))
327 test
.expect(200, { buf
: '0102' }, done
)
331 describeAsyncHooks('async local storage', function () {
334 var store
= { foo
: 'bar' }
336 app
.use(function (req
, res
, next
) {
337 req
.asyncLocalStorage
= new asyncHooks
.AsyncLocalStorage()
338 req
.asyncLocalStorage
.run(store
, next
)
341 app
.use(express
.raw())
343 app
.use(function (req
, res
, next
) {
344 var local
= req
.asyncLocalStorage
.getStore()
347 res
.setHeader('x-store-foo', String(local
.foo
))
353 app
.use(function (err
, req
, res
, next
) {
354 var local
= req
.asyncLocalStorage
.getStore()
357 res
.setHeader('x-store-foo', String(local
.foo
))
360 res
.status(err
.status
|| 500)
361 res
.send('[' + err
.type
+ '] ' + err
.message
)
364 app
.post('/', function (req
, res
) {
365 if (Buffer
.isBuffer(req
.body
)) {
366 res
.json({ buf
: req
.body
.toString('hex') })
375 it('should presist store', function (done
) {
378 .set('Content-Type', 'application/octet-stream')
379 .send('the user is tobi')
381 .expect('x-store-foo', 'bar')
382 .expect({ buf
: '746865207573657220697320746f6269' })
386 it('should presist store when unmatched content-type', function (done
) {
389 .set('Content-Type', 'application/fizzbuzz')
392 .expect('x-store-foo', 'bar')
396 it('should presist store when inflated', function (done
) {
397 var test
= request(this.app
).post('/')
398 test
.set('Content-Encoding', 'gzip')
399 test
.set('Content-Type', 'application/octet-stream')
400 test
.write(Buffer
.from('1f8b080000000000000bcb4bcc4db57db16e170099a4bad608000000', 'hex'))
402 test
.expect('x-store-foo', 'bar')
403 test
.expect({ buf
: '6e616d653de8aeba' })
407 it('should presist store when inflate error', function (done
) {
408 var test
= request(this.app
).post('/')
409 test
.set('Content-Encoding', 'gzip')
410 test
.set('Content-Type', 'application/octet-stream')
411 test
.write(Buffer
.from('1f8b080000000000000bcb4bcc4db57db16e170099a4bad6080000', 'hex'))
413 test
.expect('x-store-foo', 'bar')
417 it('should presist store when limit exceeded', function (done
) {
420 .set('Content-Type', 'application/octet-stream')
421 .send('the user is ' + Buffer
.alloc(1024 * 100, '.').toString())
423 .expect('x-store-foo', 'bar')
428 describe('charset', function () {
430 this.app
= createApp()
433 it('should ignore charset', function (done
) {
434 var test
= request(this.app
).post('/')
435 test
.set('Content-Type', 'application/octet-stream; charset=utf-8')
436 test
.write(Buffer
.from('6e616d6520697320e8aeba', 'hex'))
437 test
.expect(200, { buf
: '6e616d6520697320e8aeba' }, done
)
441 describe('encoding', function () {
443 this.app
= createApp({ limit
: '10kb' })
446 it('should parse without encoding', function (done
) {
447 var test
= request(this.app
).post('/')
448 test
.set('Content-Type', 'application/octet-stream')
449 test
.write(Buffer
.from('6e616d653de8aeba', 'hex'))
450 test
.expect(200, { buf
: '6e616d653de8aeba' }, done
)
453 it('should support identity encoding', function (done
) {
454 var test
= request(this.app
).post('/')
455 test
.set('Content-Encoding', 'identity')
456 test
.set('Content-Type', 'application/octet-stream')
457 test
.write(Buffer
.from('6e616d653de8aeba', 'hex'))
458 test
.expect(200, { buf
: '6e616d653de8aeba' }, done
)
461 it('should support gzip encoding', function (done
) {
462 var test
= request(this.app
).post('/')
463 test
.set('Content-Encoding', 'gzip')
464 test
.set('Content-Type', 'application/octet-stream')
465 test
.write(Buffer
.from('1f8b080000000000000bcb4bcc4db57db16e170099a4bad608000000', 'hex'))
466 test
.expect(200, { buf
: '6e616d653de8aeba' }, done
)
469 it('should support deflate encoding', function (done
) {
470 var test
= request(this.app
).post('/')
471 test
.set('Content-Encoding', 'deflate')
472 test
.set('Content-Type', 'application/octet-stream')
473 test
.write(Buffer
.from('789ccb4bcc4db57db16e17001068042f', 'hex'))
474 test
.expect(200, { buf
: '6e616d653de8aeba' }, done
)
477 it('should be case-insensitive', function (done
) {
478 var test
= request(this.app
).post('/')
479 test
.set('Content-Encoding', 'GZIP')
480 test
.set('Content-Type', 'application/octet-stream')
481 test
.write(Buffer
.from('1f8b080000000000000bcb4bcc4db57db16e170099a4bad608000000', 'hex'))
482 test
.expect(200, { buf
: '6e616d653de8aeba' }, done
)
485 it('should 415 on unknown encoding', function (done
) {
486 var test
= request(this.app
).post('/')
487 test
.set('Content-Encoding', 'nulls')
488 test
.set('Content-Type', 'application/octet-stream')
489 test
.write(Buffer
.from('000000000000', 'hex'))
490 test
.expect(415, '[encoding.unsupported] unsupported content encoding "nulls"', done
)
495 function createApp (options
) {
498 app
.use(express
.raw(options
))
500 app
.use(function (err
, req
, res
, next
) {
501 res
.status(err
.status
|| 500)
502 res
.send(String(req
.headers
['x-error-property']
503 ? err
[req
.headers
['x-error-property']]
504 : ('[' + err
.type
+ '] ' + err
.message
)))
507 app
.post('/', function (req
, res
) {
508 if (Buffer
.isBuffer(req
.body
)) {
509 res
.json({ buf
: req
.body
.toString('hex') })
518 function tryRequire (name
) {