docs: add note about security report location
[express.git] / test / express.text.js
blob7c92f90e5aa9d1fc9296c0a920ad71226d09239a
2 var assert = require('assert')
3 var Buffer = require('safe-buffer').Buffer
4 var express = require('..')
5 var request = require('supertest')
7 describe('express.text()', function () {
8   before(function () {
9     this.app = createApp()
10   })
12   it('should parse text/plain', function (done) {
13     request(this.app)
14       .post('/')
15       .set('Content-Type', 'text/plain')
16       .send('user is tobi')
17       .expect(200, '"user is tobi"', done)
18   })
20   it('should 400 when invalid content-length', function (done) {
21     var app = express()
23     app.use(function (req, res, next) {
24       req.headers['content-length'] = '20' // bad length
25       next()
26     })
28     app.use(express.text())
30     app.post('/', function (req, res) {
31       res.json(req.body)
32     })
34     request(app)
35       .post('/')
36       .set('Content-Type', 'text/plain')
37       .send('user')
38       .expect(400, /content length/, done)
39   })
41   it('should handle Content-Length: 0', function (done) {
42     request(createApp({ limit: '1kb' }))
43       .post('/')
44       .set('Content-Type', 'text/plain')
45       .set('Content-Length', '0')
46       .expect(200, '""', done)
47   })
49   it('should handle empty message-body', function (done) {
50     request(createApp({ limit: '1kb' }))
51       .post('/')
52       .set('Content-Type', 'text/plain')
53       .set('Transfer-Encoding', 'chunked')
54       .send('')
55       .expect(200, '""', done)
56   })
58   it('should handle duplicated middleware', function (done) {
59     var app = express()
61     app.use(express.text())
62     app.use(express.text())
64     app.post('/', function (req, res) {
65       res.json(req.body)
66     })
68     request(app)
69       .post('/')
70       .set('Content-Type', 'text/plain')
71       .send('user is tobi')
72       .expect(200, '"user is tobi"', done)
73   })
75   describe('with defaultCharset option', function () {
76     it('should change default charset', function (done) {
77       var app = createApp({ defaultCharset: 'koi8-r' })
78       var test = request(app).post('/')
79       test.set('Content-Type', 'text/plain')
80       test.write(Buffer.from('6e616d6520697320cec5d4', 'hex'))
81       test.expect(200, '"name is нет"', done)
82     })
84     it('should honor content-type charset', function (done) {
85       var app = createApp({ defaultCharset: 'koi8-r' })
86       var test = request(app).post('/')
87       test.set('Content-Type', 'text/plain; charset=utf-8')
88       test.write(Buffer.from('6e616d6520697320e8aeba', 'hex'))
89       test.expect(200, '"name is 论"', done)
90     })
91   })
93   describe('with limit option', function () {
94     it('should 413 when over limit with Content-Length', function (done) {
95       var buf = Buffer.alloc(1028, '.')
96       request(createApp({ limit: '1kb' }))
97         .post('/')
98         .set('Content-Type', 'text/plain')
99         .set('Content-Length', '1028')
100         .send(buf.toString())
101         .expect(413, done)
102     })
104     it('should 413 when over limit with chunked encoding', function (done) {
105       var buf = Buffer.alloc(1028, '.')
106       var app = createApp({ limit: '1kb' })
107       var test = request(app).post('/')
108       test.set('Content-Type', 'text/plain')
109       test.set('Transfer-Encoding', 'chunked')
110       test.write(buf.toString())
111       test.expect(413, done)
112     })
114     it('should accept number of bytes', function (done) {
115       var buf = Buffer.alloc(1028, '.')
116       request(createApp({ limit: 1024 }))
117         .post('/')
118         .set('Content-Type', 'text/plain')
119         .send(buf.toString())
120         .expect(413, done)
121     })
123     it('should not change when options altered', function (done) {
124       var buf = Buffer.alloc(1028, '.')
125       var options = { limit: '1kb' }
126       var app = createApp(options)
128       options.limit = '100kb'
130       request(app)
131         .post('/')
132         .set('Content-Type', 'text/plain')
133         .send(buf.toString())
134         .expect(413, done)
135     })
137     it('should not hang response', function (done) {
138       var buf = Buffer.alloc(10240, '.')
139       var app = createApp({ limit: '8kb' })
140       var test = request(app).post('/')
141       test.set('Content-Type', 'text/plain')
142       test.write(buf)
143       test.write(buf)
144       test.write(buf)
145       test.expect(413, done)
146     })
147   })
149   describe('with inflate option', function () {
150     describe('when false', function () {
151       before(function () {
152         this.app = createApp({ inflate: false })
153       })
155       it('should not accept content-encoding', function (done) {
156         var test = request(this.app).post('/')
157         test.set('Content-Encoding', 'gzip')
158         test.set('Content-Type', 'text/plain')
159         test.write(Buffer.from('1f8b080000000000000bcb4bcc4d55c82c5678b16e170072b3e0200b000000', 'hex'))
160         test.expect(415, 'content encoding unsupported', done)
161       })
162     })
164     describe('when true', function () {
165       before(function () {
166         this.app = createApp({ inflate: true })
167       })
169       it('should accept content-encoding', function (done) {
170         var test = request(this.app).post('/')
171         test.set('Content-Encoding', 'gzip')
172         test.set('Content-Type', 'text/plain')
173         test.write(Buffer.from('1f8b080000000000000bcb4bcc4d55c82c5678b16e170072b3e0200b000000', 'hex'))
174         test.expect(200, '"name is 论"', done)
175       })
176     })
177   })
179   describe('with type option', function () {
180     describe('when "text/html"', function () {
181       before(function () {
182         this.app = createApp({ type: 'text/html' })
183       })
185       it('should parse for custom type', function (done) {
186         request(this.app)
187           .post('/')
188           .set('Content-Type', 'text/html')
189           .send('<b>tobi</b>')
190           .expect(200, '"<b>tobi</b>"', done)
191       })
193       it('should ignore standard type', function (done) {
194         request(this.app)
195           .post('/')
196           .set('Content-Type', 'text/plain')
197           .send('user is tobi')
198           .expect(200, '{}', done)
199       })
200     })
202     describe('when ["text/html", "text/plain"]', function () {
203       before(function () {
204         this.app = createApp({ type: ['text/html', 'text/plain'] })
205       })
207       it('should parse "text/html"', function (done) {
208         request(this.app)
209           .post('/')
210           .set('Content-Type', 'text/html')
211           .send('<b>tobi</b>')
212           .expect(200, '"<b>tobi</b>"', done)
213       })
215       it('should parse "text/plain"', function (done) {
216         request(this.app)
217           .post('/')
218           .set('Content-Type', 'text/plain')
219           .send('tobi')
220           .expect(200, '"tobi"', done)
221       })
223       it('should ignore "text/xml"', function (done) {
224         request(this.app)
225           .post('/')
226           .set('Content-Type', 'text/xml')
227           .send('<user>tobi</user>')
228           .expect(200, '{}', done)
229       })
230     })
232     describe('when a function', function () {
233       it('should parse when truthy value returned', function (done) {
234         var app = createApp({ type: accept })
236         function accept (req) {
237           return req.headers['content-type'] === 'text/vnd.something'
238         }
240         request(app)
241           .post('/')
242           .set('Content-Type', 'text/vnd.something')
243           .send('user is tobi')
244           .expect(200, '"user is tobi"', done)
245       })
247       it('should work without content-type', function (done) {
248         var app = createApp({ type: accept })
250         function accept (req) {
251           return true
252         }
254         var test = request(app).post('/')
255         test.write('user is tobi')
256         test.expect(200, '"user is tobi"', done)
257       })
259       it('should not invoke without a body', function (done) {
260         var app = createApp({ type: accept })
262         function accept (req) {
263           throw new Error('oops!')
264         }
266         request(app)
267           .get('/')
268           .expect(404, done)
269       })
270     })
271   })
273   describe('with verify option', function () {
274     it('should assert value is function', function () {
275       assert.throws(createApp.bind(null, { verify: 'lol' }),
276         /TypeError: option verify must be function/)
277     })
279     it('should error from verify', function (done) {
280       var app = createApp({ verify: function (req, res, buf) {
281         if (buf[0] === 0x20) throw new Error('no leading space')
282       } })
284       request(app)
285         .post('/')
286         .set('Content-Type', 'text/plain')
287         .send(' user is tobi')
288         .expect(403, 'no leading space', done)
289     })
291     it('should allow custom codes', function (done) {
292       var app = createApp({ verify: function (req, res, buf) {
293         if (buf[0] !== 0x20) return
294         var err = new Error('no leading space')
295         err.status = 400
296         throw err
297       } })
299       request(app)
300         .post('/')
301         .set('Content-Type', 'text/plain')
302         .send(' user is tobi')
303         .expect(400, 'no leading space', done)
304     })
306     it('should allow pass-through', function (done) {
307       var app = createApp({ verify: function (req, res, buf) {
308         if (buf[0] === 0x20) throw new Error('no leading space')
309       } })
311       request(app)
312         .post('/')
313         .set('Content-Type', 'text/plain')
314         .send('user is tobi')
315         .expect(200, '"user is tobi"', done)
316     })
318     it('should 415 on unknown charset prior to verify', function (done) {
319       var app = createApp({ verify: function (req, res, buf) {
320         throw new Error('unexpected verify call')
321       } })
323       var test = request(app).post('/')
324       test.set('Content-Type', 'text/plain; charset=x-bogus')
325       test.write(Buffer.from('00000000', 'hex'))
326       test.expect(415, 'unsupported charset "X-BOGUS"', done)
327     })
328   })
330   describe('charset', function () {
331     before(function () {
332       this.app = createApp()
333     })
335     it('should parse utf-8', function (done) {
336       var test = request(this.app).post('/')
337       test.set('Content-Type', 'text/plain; charset=utf-8')
338       test.write(Buffer.from('6e616d6520697320e8aeba', 'hex'))
339       test.expect(200, '"name is 论"', done)
340     })
342     it('should parse codepage charsets', function (done) {
343       var test = request(this.app).post('/')
344       test.set('Content-Type', 'text/plain; charset=koi8-r')
345       test.write(Buffer.from('6e616d6520697320cec5d4', 'hex'))
346       test.expect(200, '"name is нет"', done)
347     })
349     it('should parse when content-length != char length', function (done) {
350       var test = request(this.app).post('/')
351       test.set('Content-Type', 'text/plain; charset=utf-8')
352       test.set('Content-Length', '11')
353       test.write(Buffer.from('6e616d6520697320e8aeba', 'hex'))
354       test.expect(200, '"name is 论"', done)
355     })
357     it('should default to utf-8', function (done) {
358       var test = request(this.app).post('/')
359       test.set('Content-Type', 'text/plain')
360       test.write(Buffer.from('6e616d6520697320e8aeba', 'hex'))
361       test.expect(200, '"name is 论"', done)
362     })
364     it('should 415 on unknown charset', function (done) {
365       var test = request(this.app).post('/')
366       test.set('Content-Type', 'text/plain; charset=x-bogus')
367       test.write(Buffer.from('00000000', 'hex'))
368       test.expect(415, 'unsupported charset "X-BOGUS"', done)
369     })
370   })
372   describe('encoding', function () {
373     before(function () {
374       this.app = createApp({ limit: '10kb' })
375     })
377     it('should parse without encoding', function (done) {
378       var test = request(this.app).post('/')
379       test.set('Content-Type', 'text/plain')
380       test.write(Buffer.from('6e616d6520697320e8aeba', 'hex'))
381       test.expect(200, '"name is 论"', done)
382     })
384     it('should support identity encoding', function (done) {
385       var test = request(this.app).post('/')
386       test.set('Content-Encoding', 'identity')
387       test.set('Content-Type', 'text/plain')
388       test.write(Buffer.from('6e616d6520697320e8aeba', 'hex'))
389       test.expect(200, '"name is 论"', done)
390     })
392     it('should support gzip encoding', function (done) {
393       var test = request(this.app).post('/')
394       test.set('Content-Encoding', 'gzip')
395       test.set('Content-Type', 'text/plain')
396       test.write(Buffer.from('1f8b080000000000000bcb4bcc4d55c82c5678b16e170072b3e0200b000000', 'hex'))
397       test.expect(200, '"name is 论"', done)
398     })
400     it('should support deflate encoding', function (done) {
401       var test = request(this.app).post('/')
402       test.set('Content-Encoding', 'deflate')
403       test.set('Content-Type', 'text/plain')
404       test.write(Buffer.from('789ccb4bcc4d55c82c5678b16e17001a6f050e', 'hex'))
405       test.expect(200, '"name is 论"', done)
406     })
408     it('should be case-insensitive', function (done) {
409       var test = request(this.app).post('/')
410       test.set('Content-Encoding', 'GZIP')
411       test.set('Content-Type', 'text/plain')
412       test.write(Buffer.from('1f8b080000000000000bcb4bcc4d55c82c5678b16e170072b3e0200b000000', 'hex'))
413       test.expect(200, '"name is 论"', done)
414     })
416     it('should fail on unknown encoding', function (done) {
417       var test = request(this.app).post('/')
418       test.set('Content-Encoding', 'nulls')
419       test.set('Content-Type', 'text/plain')
420       test.write(Buffer.from('000000000000', 'hex'))
421       test.expect(415, 'unsupported content encoding "nulls"', done)
422     })
423   })
426 function createApp (options) {
427   var app = express()
429   app.use(express.text(options))
431   app.use(function (err, req, res, next) {
432     res.status(err.status || 500)
433     res.send(err.message)
434   })
436   app.post('/', function (req, res) {
437     res.json(req.body)
438   })
440   return app