3 var assert
= require('assert')
4 var asyncHooks
= tryRequire('async_hooks')
5 var express
= require('..')
6 var request
= require('supertest')
8 var describeAsyncHooks
= typeof asyncHooks
.AsyncLocalStorage
=== 'function'
12 describe('express.text()', function () {
14 this.app
= createApp()
17 it('should parse text/plain', function (done
) {
20 .set('Content-Type', 'text/plain')
22 .expect(200, '"user is tobi"', done
)
25 it('should 400 when invalid content-length', function (done
) {
28 app
.use(function (req
, res
, next
) {
29 req
.headers
['content-length'] = '20' // bad length
33 app
.use(express
.text())
35 app
.post('/', function (req
, res
) {
41 .set('Content-Type', 'text/plain')
43 .expect(400, /content length/, done
)
46 it('should handle Content-Length: 0', function (done
) {
47 request(createApp({ limit
: '1kb' }))
49 .set('Content-Type', 'text/plain')
50 .set('Content-Length', '0')
51 .expect(200, '""', done
)
54 it('should handle empty message-body', function (done
) {
55 request(createApp({ limit
: '1kb' }))
57 .set('Content-Type', 'text/plain')
58 .set('Transfer-Encoding', 'chunked')
60 .expect(200, '""', done
)
63 it('should handle duplicated middleware', function (done
) {
66 app
.use(express
.text())
67 app
.use(express
.text())
69 app
.post('/', function (req
, res
) {
75 .set('Content-Type', 'text/plain')
77 .expect(200, '"user is tobi"', done
)
80 describe('with defaultCharset option', function () {
81 it('should change default charset', function (done
) {
82 var server
= createApp({ defaultCharset
: 'koi8-r' })
83 var test
= request(server
).post('/')
84 test
.set('Content-Type', 'text/plain')
85 test
.write(Buffer
.from('6e616d6520697320cec5d4', 'hex'))
86 test
.expect(200, '"name is нет"', done
)
89 it('should honor content-type charset', function (done
) {
90 var server
= createApp({ defaultCharset
: 'koi8-r' })
91 var test
= request(server
).post('/')
92 test
.set('Content-Type', 'text/plain; charset=utf-8')
93 test
.write(Buffer
.from('6e616d6520697320e8aeba', 'hex'))
94 test
.expect(200, '"name is 论"', done
)
98 describe('with limit option', function () {
99 it('should 413 when over limit with Content-Length', function (done
) {
100 var buf
= Buffer
.alloc(1028, '.')
101 request(createApp({ limit
: '1kb' }))
103 .set('Content-Type', 'text/plain')
104 .set('Content-Length', '1028')
105 .send(buf
.toString())
109 it('should 413 when over limit with chunked encoding', function (done
) {
110 var app
= createApp({ limit
: '1kb' })
111 var buf
= Buffer
.alloc(1028, '.')
112 var test
= request(app
).post('/')
113 test
.set('Content-Type', 'text/plain')
114 test
.set('Transfer-Encoding', 'chunked')
115 test
.write(buf
.toString())
116 test
.expect(413, done
)
119 it('should 413 when inflated body over limit', function (done
) {
120 var app
= createApp({ limit
: '1kb' })
121 var test
= request(app
).post('/')
122 test
.set('Content-Encoding', 'gzip')
123 test
.set('Content-Type', 'text/plain')
124 test
.write(Buffer
.from('1f8b080000000000000ad3d31b05a360148c64000087e5a14704040000', 'hex'))
125 test
.expect(413, done
)
128 it('should accept number of bytes', function (done
) {
129 var buf
= Buffer
.alloc(1028, '.')
130 request(createApp({ limit
: 1024 }))
132 .set('Content-Type', 'text/plain')
133 .send(buf
.toString())
137 it('should not change when options altered', function (done
) {
138 var buf
= Buffer
.alloc(1028, '.')
139 var options
= { limit
: '1kb' }
140 var app
= createApp(options
)
142 options
.limit
= '100kb'
146 .set('Content-Type', 'text/plain')
147 .send(buf
.toString())
151 it('should not hang response', function (done
) {
152 var app
= createApp({ limit
: '8kb' })
153 var buf
= Buffer
.alloc(10240, '.')
154 var test
= request(app
).post('/')
155 test
.set('Content-Type', 'text/plain')
159 test
.expect(413, done
)
162 it('should not error when inflating', function (done
) {
163 var app
= createApp({ limit
: '1kb' })
164 var test
= request(app
).post('/')
165 test
.set('Content-Encoding', 'gzip')
166 test
.set('Content-Type', 'text/plain')
167 test
.write(Buffer
.from('1f8b080000000000000ad3d31b05a360148c64000087e5a1470404', 'hex'))
168 setTimeout(function () {
169 test
.expect(413, done
)
174 describe('with inflate option', function () {
175 describe('when false', function () {
177 this.app
= createApp({ inflate
: false })
180 it('should not accept content-encoding', function (done
) {
181 var test
= request(this.app
).post('/')
182 test
.set('Content-Encoding', 'gzip')
183 test
.set('Content-Type', 'text/plain')
184 test
.write(Buffer
.from('1f8b080000000000000bcb4bcc4d55c82c5678b16e170072b3e0200b000000', 'hex'))
185 test
.expect(415, '[encoding.unsupported] content encoding unsupported', done
)
189 describe('when true', function () {
191 this.app
= createApp({ inflate
: true })
194 it('should accept content-encoding', function (done
) {
195 var test
= request(this.app
).post('/')
196 test
.set('Content-Encoding', 'gzip')
197 test
.set('Content-Type', 'text/plain')
198 test
.write(Buffer
.from('1f8b080000000000000bcb4bcc4d55c82c5678b16e170072b3e0200b000000', 'hex'))
199 test
.expect(200, '"name is 论"', done
)
204 describe('with type option', function () {
205 describe('when "text/html"', function () {
207 this.app
= createApp({ type
: 'text/html' })
210 it('should parse for custom type', function (done
) {
213 .set('Content-Type', 'text/html')
215 .expect(200, '"<b>tobi</b>"', done
)
218 it('should ignore standard type', function (done
) {
221 .set('Content-Type', 'text/plain')
222 .send('user is tobi')
223 .expect(200, '', done
)
227 describe('when ["text/html", "text/plain"]', function () {
229 this.app
= createApp({ type
: ['text/html', 'text/plain'] })
232 it('should parse "text/html"', function (done
) {
235 .set('Content-Type', 'text/html')
237 .expect(200, '"<b>tobi</b>"', done
)
240 it('should parse "text/plain"', function (done
) {
243 .set('Content-Type', 'text/plain')
245 .expect(200, '"tobi"', done
)
248 it('should ignore "text/xml"', function (done
) {
251 .set('Content-Type', 'text/xml')
252 .send('<user>tobi</user>')
253 .expect(200, '', done
)
257 describe('when a function', function () {
258 it('should parse when truthy value returned', function (done
) {
259 var app
= createApp({ type
: accept
})
261 function accept (req
) {
262 return req
.headers
['content-type'] === 'text/vnd.something'
267 .set('Content-Type', 'text/vnd.something')
268 .send('user is tobi')
269 .expect(200, '"user is tobi"', done
)
272 it('should work without content-type', function (done
) {
273 var app
= createApp({ type
: accept
})
275 function accept (req
) {
279 var test
= request(app
).post('/')
280 test
.write('user is tobi')
281 test
.expect(200, '"user is tobi"', done
)
284 it('should not invoke without a body', function (done
) {
285 var app
= createApp({ type
: accept
})
287 function accept (req
) {
288 throw new Error('oops!')
298 describe('with verify option', function () {
299 it('should assert value is function', function () {
300 assert
.throws(createApp
.bind(null, { verify
: 'lol' }),
301 /TypeError: option verify must be function/)
304 it('should error from verify', function (done
) {
305 var app
= createApp({
306 verify: function (req
, res
, buf
) {
307 if (buf
[0] === 0x20) throw new Error('no leading space')
313 .set('Content-Type', 'text/plain')
314 .send(' user is tobi')
315 .expect(403, '[entity.verify.failed] no leading space', done
)
318 it('should allow custom codes', function (done
) {
319 var app
= createApp({
320 verify: function (req
, res
, buf
) {
321 if (buf
[0] !== 0x20) return
322 var err
= new Error('no leading space')
330 .set('Content-Type', 'text/plain')
331 .send(' user is tobi')
332 .expect(400, '[entity.verify.failed] no leading space', done
)
335 it('should allow pass-through', function (done
) {
336 var app
= createApp({
337 verify: function (req
, res
, buf
) {
338 if (buf
[0] === 0x20) throw new Error('no leading space')
344 .set('Content-Type', 'text/plain')
345 .send('user is tobi')
346 .expect(200, '"user is tobi"', done
)
349 it('should 415 on unknown charset prior to verify', function (done
) {
350 var app
= createApp({
351 verify: function (req
, res
, buf
) {
352 throw new Error('unexpected verify call')
356 var test
= request(app
).post('/')
357 test
.set('Content-Type', 'text/plain; charset=x-bogus')
358 test
.write(Buffer
.from('00000000', 'hex'))
359 test
.expect(415, '[charset.unsupported] unsupported charset "X-BOGUS"', done
)
363 describeAsyncHooks('async local storage', function () {
366 var store
= { foo
: 'bar' }
368 app
.use(function (req
, res
, next
) {
369 req
.asyncLocalStorage
= new asyncHooks
.AsyncLocalStorage()
370 req
.asyncLocalStorage
.run(store
, next
)
373 app
.use(express
.text())
375 app
.use(function (req
, res
, next
) {
376 var local
= req
.asyncLocalStorage
.getStore()
379 res
.setHeader('x-store-foo', String(local
.foo
))
385 app
.use(function (err
, req
, res
, next
) {
386 var local
= req
.asyncLocalStorage
.getStore()
389 res
.setHeader('x-store-foo', String(local
.foo
))
392 res
.status(err
.status
|| 500)
393 res
.send('[' + err
.type
+ '] ' + err
.message
)
396 app
.post('/', function (req
, res
) {
403 it('should presist store', function (done
) {
406 .set('Content-Type', 'text/plain')
407 .send('user is tobi')
409 .expect('x-store-foo', 'bar')
410 .expect('"user is tobi"')
414 it('should presist store when unmatched content-type', function (done
) {
417 .set('Content-Type', 'application/fizzbuzz')
420 .expect('x-store-foo', 'bar')
424 it('should presist store when inflated', function (done
) {
425 var test
= request(this.app
).post('/')
426 test
.set('Content-Encoding', 'gzip')
427 test
.set('Content-Type', 'text/plain')
428 test
.write(Buffer
.from('1f8b080000000000000bcb4bcc4d55c82c5678b16e170072b3e0200b000000', 'hex'))
430 test
.expect('x-store-foo', 'bar')
431 test
.expect('"name is 论"')
435 it('should presist store when inflate error', function (done
) {
436 var test
= request(this.app
).post('/')
437 test
.set('Content-Encoding', 'gzip')
438 test
.set('Content-Type', 'text/plain')
439 test
.write(Buffer
.from('1f8b080000000000000bcb4bcc4d55c82c5678b16e170072b3e0200b0000', 'hex'))
441 test
.expect('x-store-foo', 'bar')
445 it('should presist store when limit exceeded', function (done
) {
448 .set('Content-Type', 'text/plain')
449 .send('user is ' + Buffer
.alloc(1024 * 100, '.').toString())
451 .expect('x-store-foo', 'bar')
456 describe('charset', function () {
458 this.app
= createApp()
461 it('should parse utf-8', function (done
) {
462 var test
= request(this.app
).post('/')
463 test
.set('Content-Type', 'text/plain; charset=utf-8')
464 test
.write(Buffer
.from('6e616d6520697320e8aeba', 'hex'))
465 test
.expect(200, '"name is 论"', done
)
468 it('should parse codepage charsets', function (done
) {
469 var test
= request(this.app
).post('/')
470 test
.set('Content-Type', 'text/plain; charset=koi8-r')
471 test
.write(Buffer
.from('6e616d6520697320cec5d4', 'hex'))
472 test
.expect(200, '"name is нет"', done
)
475 it('should parse when content-length != char length', function (done
) {
476 var test
= request(this.app
).post('/')
477 test
.set('Content-Type', 'text/plain; charset=utf-8')
478 test
.set('Content-Length', '11')
479 test
.write(Buffer
.from('6e616d6520697320e8aeba', 'hex'))
480 test
.expect(200, '"name is 论"', done
)
483 it('should default to utf-8', function (done
) {
484 var test
= request(this.app
).post('/')
485 test
.set('Content-Type', 'text/plain')
486 test
.write(Buffer
.from('6e616d6520697320e8aeba', 'hex'))
487 test
.expect(200, '"name is 论"', done
)
490 it('should 415 on unknown charset', function (done
) {
491 var test
= request(this.app
).post('/')
492 test
.set('Content-Type', 'text/plain; charset=x-bogus')
493 test
.write(Buffer
.from('00000000', 'hex'))
494 test
.expect(415, '[charset.unsupported] unsupported charset "X-BOGUS"', done
)
498 describe('encoding', function () {
500 this.app
= createApp({ limit
: '10kb' })
503 it('should parse without encoding', function (done
) {
504 var test
= request(this.app
).post('/')
505 test
.set('Content-Type', 'text/plain')
506 test
.write(Buffer
.from('6e616d6520697320e8aeba', 'hex'))
507 test
.expect(200, '"name is 论"', done
)
510 it('should support identity encoding', function (done
) {
511 var test
= request(this.app
).post('/')
512 test
.set('Content-Encoding', 'identity')
513 test
.set('Content-Type', 'text/plain')
514 test
.write(Buffer
.from('6e616d6520697320e8aeba', 'hex'))
515 test
.expect(200, '"name is 论"', done
)
518 it('should support gzip encoding', function (done
) {
519 var test
= request(this.app
).post('/')
520 test
.set('Content-Encoding', 'gzip')
521 test
.set('Content-Type', 'text/plain')
522 test
.write(Buffer
.from('1f8b080000000000000bcb4bcc4d55c82c5678b16e170072b3e0200b000000', 'hex'))
523 test
.expect(200, '"name is 论"', done
)
526 it('should support deflate encoding', function (done
) {
527 var test
= request(this.app
).post('/')
528 test
.set('Content-Encoding', 'deflate')
529 test
.set('Content-Type', 'text/plain')
530 test
.write(Buffer
.from('789ccb4bcc4d55c82c5678b16e17001a6f050e', 'hex'))
531 test
.expect(200, '"name is 论"', done
)
534 it('should be case-insensitive', function (done
) {
535 var test
= request(this.app
).post('/')
536 test
.set('Content-Encoding', 'GZIP')
537 test
.set('Content-Type', 'text/plain')
538 test
.write(Buffer
.from('1f8b080000000000000bcb4bcc4d55c82c5678b16e170072b3e0200b000000', 'hex'))
539 test
.expect(200, '"name is 论"', done
)
542 it('should 415 on unknown encoding', function (done
) {
543 var test
= request(this.app
).post('/')
544 test
.set('Content-Encoding', 'nulls')
545 test
.set('Content-Type', 'text/plain')
546 test
.write(Buffer
.from('000000000000', 'hex'))
547 test
.expect(415, '[encoding.unsupported] unsupported content encoding "nulls"', done
)
552 function createApp (options
) {
555 app
.use(express
.text(options
))
557 app
.use(function (err
, req
, res
, next
) {
558 res
.status(err
.status
|| 500)
559 res
.send(String(req
.headers
['x-error-property']
560 ? err
[req
.headers
['x-error-property']]
561 : ('[' + err
.type
+ '] ' + err
.message
)))
564 app
.post('/', function (req
, res
) {
571 function tryRequire (name
) {