it('parses field names with arrays and file', function (done) { var payload = '----WebKitFormBoundaryE19zNvXGzXaLvS5C\r\n' + 'Content-Disposition: form-data; name="a[b]"\r\n' + '\r\n' + '3\r\n' + '----WebKitFormBoundaryE19zNvXGzXaLvS5C\r\n' + 'Content-Disposition: form-data; name="a[c]"\r\n' + '\r\n' + '4\r\n' + '----WebKitFormBoundaryE19zNvXGzXaLvS5C\r\n' + 'Content-Disposition: form-data; name="file"; filename="test.txt"\r\n' + 'Content-Type: plain/text\r\n' + '\r\n' + 'and\r\n' + '----WebKitFormBoundaryE19zNvXGzXaLvS5C--\r\n'; var request = Wreck.toReadableStream(payload); request.headers = { 'content-type': 'multipart/form-data; boundary="--WebKitFormBoundaryE19zNvXGzXaLvS5C"' }; Subtext.parse(request, null, { parse: true, output: 'data' }, function (err, parsed) { expect(err).to.not.exist; expect(parsed.payload.a.b + parsed.payload.file + parsed.payload.a.c).to.equal('3and4'); done(); }); });
it('should set status 200 for OPTIONS requests', function (done) { var stream = Wreck.toReadableStream(JSON.stringify({ the: 'body' })); stream.headers = { some: 'header', }; stream.statusCode = 405; plugin.internals.addCorsAndBearerToken(null, stream, { method: 'options', headers: {} }, function (data) { var fixture = JSON.stringify({"the": "body"}) + '\n'; expect(data).to.eql(fixture); return { code: function(statusCode) { expect(statusCode).to.eql(200); return { hold: function () { function Resp() {}; Resp.prototype.send = function() { expect(this.headers).to.be.an('object'); done(); }; return new Resp(); } }; } }; }); });
Wreck.read(part, {}, (ignoreErr, payload) => { // Error handled by dispenser.once('error') if (this.settings.output === 'stream') { // Output: 'stream' const item = Wreck.toReadableStream(payload); item.hapi = { filename: part.filename, headers: part.headers }; return set(part.name, item); } const ct = part.headers['content-type'] || ''; const mime = ct.split(';')[0].trim().toLowerCase(); if (!mime) { return set(part.name, payload); } if (!payload.length) { return set(part.name, {}); } internals.object(payload, mime, this.settings, (err, result) => { return set(part.name, err ? payload : result); }); });
it('should strip any set-cookie headers and add them into the body', function (done) { var stream = Wreck.toReadableStream(JSON.stringify({ the: 'body' })); stream.headers = { some: 'header', 'set-cookie': ['AuthSession=some-token; Version=bla bla bla'] }; stream.statusCode = 200; plugin.internals.addCorsAndBearerToken(null, stream, { headers: {} }, function (data) { var fixture = JSON.stringify({"the": "body", "bearerToken": "some-token"}) + '\n'; expect(data).to.eql(fixture); return { code: function(statusCode) { expect(statusCode).to.eql(200); return { hold: function () { function Resp() {}; Resp.prototype.send = function() { expect(this.headers['set-cookie']).to.be.an('undefined'); }; done(); return new Resp(); } }; } }; }); });
Wreck.read(part, {}, (ignoreErr, payload) => { // Error handled by dispenser.once('error') if (output === 'stream') { // Output: 'stream' const item = Wreck.toReadableStream(payload); item.hapi = { filename: part.filename, headers: part.headers }; return set(part.name, item); } const ct = part.headers['content-type'] || ''; const mime = ct.split(';')[0].trim().toLowerCase(); const annotate = (value) => set(part.name, output === 'annotated' ? { filename: part.filename, headers: part.headers, payload: value } : value); if (!mime) { return annotate(payload); } if (!payload.length) { return annotate({}); } this.object(payload, mime, (err, result) => annotate(err ? payload : result)); });
it('should call reply and hold', function (done) { var stream = Wreck.toReadableStream(JSON.stringify({ the: 'body' })); stream.headers = {}; stream.statusCode = 200; plugin.internals.addCorsAndBearerToken(null, stream, { headers: {} }, function (data) { var fixture = JSON.stringify({"the": "body"}) + '\n'; expect(data).to.eql(fixture); return { code: function(statusCode) { expect(statusCode).to.eql(200); return { hold: function () { function Resp() {}; Resp.prototype.send = function() { expect(this.headers).to.be.an('object'); done(); }; return new Resp(); } }; } }; }); });
Wreck.read(part, {}, function (err, payload) { // err handled by dispenser.once('error') if (self.settings.output === 'stream') { // Output: 'stream' var item = Wreck.toReadableStream(payload); item.hapi = { filename: part.filename, headers: part.headers }; return set(part.name, item); } var contentType = part.headers['content-type'] || ''; var mime = contentType.split(';')[0].trim().toLowerCase(); if (!mime) { return set(part.name, payload); } if (!payload.length) { return set(part.name, {}); } internals.object(payload, mime, function (err, result) { return set(part.name, err ? payload : result); }); });
internals.validateRawDataPayload = function (request, wl, fn) { const stream = Wreck.toReadableStream(request.payload); stream.headers = request.headers; return internals.parseBufferPayload(stream, wl, fn); };
const read = function (err, data) { if (err) { return reply(); } const stream = Wreck.toReadableStream(data); stream.headers = request.headers; Subtext.parse(stream, null, options, copy); };
it('peeks at multipart in stream mode', function (done) { var payload = '--AaB03x\r\n' + 'content-disposition: form-data; name="x"\r\n' + '\r\n' + 'First\r\n' + '--AaB03x\r\n' + 'content-disposition: form-data; name="x"\r\n' + '\r\n' + 'Second\r\n' + '--AaB03x\r\n' + 'content-disposition: form-data; name="x"\r\n' + '\r\n' + 'Third\r\n' + '--AaB03x\r\n' + 'content-disposition: form-data; name="field1"\r\n' + '\r\n' + 'Joe Blow\r\nalmost tricked you!\r\n' + '--AaB03x\r\n' + 'content-disposition: form-data; name="field1"\r\n' + '\r\n' + 'Repeated name segment\r\n' + '--AaB03x\r\n' + 'content-disposition: form-data; name="pics"; filename="file1.txt"\r\n' + 'Content-Type: text/plain\r\n' + '\r\n' + '... contents of file1.txt ...\r\r\n' + '--AaB03x--\r\n'; var request = Wreck.toReadableStream(payload); request.headers = { 'content-type': 'multipart/form-data; boundary=AaB03x' }; var raw = ''; var tap = new Stream.Transform(); tap._transform = function (chunk, encoding, callback) { raw += chunk.toString(); this.push(chunk, encoding); callback(); }; Subtext.parse(request, tap, { parse: true, output: 'stream' }, function (err, parsed) { expect(err).to.not.exist; expect(parsed.payload.x).to.deep.equal(['First', 'Second', 'Third']); expect(parsed.payload.field1).to.deep.equal(['Joe Blow\r\nalmost tricked you!', 'Repeated name segment']); expect(parsed.payload.pics.hapi.filename).to.equal('file1.txt'); expect(raw).to.equal(payload); done(); }); });
const _read = function (err, data) { if (err) { return fn(err); } const stream = Wreck.toReadableStream(data); stream.headers = request.headers; internals.parseBufferPayload(stream, wl, fn); };
it('errors on invalid upload directory (parse true)', function (done) { var request = Wreck.toReadableStream('payload'); request.headers = {}; Subtext.parse(request, null, { parse: true, output: 'file', uploads: '/a/b/c/no/such/folder' }, function (err, parsed) { expect(err).to.exist; expect(err.message).to.contain('ENOENT'); done(); }); });
it('returns a subset of a stream', (done) => { const random = new Buffer(5000); const source = Wreck.toReadableStream(random); const range = Ammo.header('bytes=1000-4000', 5000); const stream = new Ammo.Stream(range[0]); Wreck.read(source.pipe(stream), {}, (err, buffer) => { expect(buffer.toString()).to.equal(random.slice(1000, 4001).toString()); done(); }); });
it('errors on invalid JSON payload', function (done) { var payload = '{"x":"1","y":"2","z":"3"'; var request = Wreck.toReadableStream(payload); request.headers = {}; Subtext.parse(request, null, { parse: true, output: 'data' }, function (err, parsed) { expect(err).to.exist; expect(err.message).to.equal('Invalid request payload JSON format'); done(); }); });
it('returns a parsed body', function (done) { var payload = '{"x":"1","y":"2","z":"3"}'; var request = Wreck.toReadableStream(payload); request.headers = {}; Subtext.parse(request, null, { parse: true, output: 'data' }, function (err, parsed) { expect(err).to.not.exist; expect(parsed.mime).to.equal('application/json'); expect(parsed.payload).to.deep.equal(JSON.parse(payload)); done(); }); });
Zlib.gzip(payload, function (err, compressed) { var request = Wreck.toReadableStream(compressed); request.headers = { 'content-encoding': 'gzip' }; Subtext.parse(request, null, { parse: true, output: 'data' }, function (err, parsed) { expect(err).to.not.exist; expect(parsed.payload).to.deep.equal(JSON.parse(payload)); done(); }); });
Zlib.deflate(payload, function (err, compressed) { var request = Wreck.toReadableStream(compressed); request.headers = { 'content-encoding': 'deflate' }; Subtext.parse(request, null, { parse: 'gunzip', output: 'data' }, function (err, parsed) { expect(err).to.not.exist; expect(parsed.payload.toString()).to.equal(payload); done(); }); });
it('limits maxBytes when content-length header missing', function (done) { var payload = '{"x":"1","y":"2","z":"3"}'; var request = Wreck.toReadableStream(payload); request.headers = {}; request.destroy = function () { }; Subtext.parse(request, null, { parse: false, output: 'data', maxBytes: 10 }, function (err, parsed) { expect(err).to.exist; expect(err.message).to.equal('Payload content length greater than maximum allowed: 10'); done(); }); });
it('returns a raw body', function (done) { var payload = '{"x":"1","y":"2","z":"3"}'; var request = Wreck.toReadableStream(payload); request.headers = {}; Subtext.parse(request, null, { parse: false, output: 'data' }, function (err, parsed) { expect(err).to.not.exist; expect(parsed.mime).to.equal('application/json'); expect(Buffer.isBuffer(parsed.payload)).to.be.true; expect(parsed.payload.toString()).to.equal(payload); done(); }); });
it('saves file', function (done) { var request = Wreck.toReadableStream('payload'); request.headers = {}; Subtext.parse(request, null, { parse: false, output: 'file' }, function (err, parsed) { expect(err).to.not.exist; var receivedContents = Fs.readFileSync(parsed.payload.path); Fs.unlinkSync(parsed.payload.path); expect(receivedContents.toString()).to.equal('payload'); done(); }); });
it('errors on invalid content type header', function (done) { var payload = '{"x":"1","y":"2","z":"3"}'; var request = Wreck.toReadableStream(payload); request.headers = { 'content-type': 'steve' }; Subtext.parse(request, null, { parse: true, output: 'data' }, function (err, parsed) { expect(err).to.exist; expect(err.message).to.equal('Invalid content-type header'); done(); }); });
it('errors on an unallowed content-type (array)', function (done) { var payload = '{"x":"1","y":"2","z":"3"}'; var request = Wreck.toReadableStream(payload); request.headers = { 'content-type': 'text/plain' }; Subtext.parse(request, null, { parse: true, output: 'data', allow: ['application/json'] }, function (err, parsed) { expect(err).to.exist; expect(err.message).to.equal('Unsupported Media Type'); done(); }); });
it('errors on unsupported content type', function (done) { var payload = '{"x":"1","y":"2","z":"3"}'; var request = Wreck.toReadableStream(payload); request.headers = { 'content-type': 'james/bond' }; Subtext.parse(request, null, { parse: true, output: 'data' }, function (err, parsed) { expect(err).to.exist; expect(err.message).to.equal('Unsupported Media Type'); done(); }); });
it('errors on malformed zipped payload (parse gunzip only)', function (done) { var payload = '7d8d78347h8347d58w347hd58w374d58w37h5d8w37hd4'; var request = Wreck.toReadableStream(payload); request.headers = { 'content-encoding': 'gzip' }; Subtext.parse(request, null, { parse: 'gunzip', output: 'data' }, function (err, parsed) { expect(err).to.exist; expect(err.message).to.equal('Invalid compressed payload'); done(); }); });
it('parses form encoded payload (with qs arraylimit set to 0)', function (done) { var payload = 'x[0]=1&x[100]=2'; var request = Wreck.toReadableStream(payload); request.headers = { 'content-type': 'application/x-www-form-urlencoded' }; Subtext.parse(request, null, { parse: true, output: 'data', qs: { arrayLimit: 0 } }, function (err, parsed) { expect(err).to.not.exist(); expect(parsed.mime).to.equal('application/x-www-form-urlencoded'); expect(parsed.payload).to.deep.equal({ x: { 0: '1', 100: '2' } }); done(); }); });
it('parses form encoded payload (with qs arraylimit set to 30) as flat zero indexed array', function (done) { var payload = 'x[0]=0&x[1]=1&x[2]=2&x[3]=3&x[4]=4&x[5]=5&x[6]=6&x[7]=7&x[8]=8&x[9]=9&x[10]=10&x[11]=11&x[12]=12&x[13]=13&x[14]=14&x[15]=15&x[16]=16&x[17]=17&x[18]=18&x[19]=19&x[20]=20&x[21]=21&x[22]=22&x[23]=23&x[24]=24&x[25]=25&x[26]=26&x[27]=27&x[28]=28&x[29]=29&'; var request = Wreck.toReadableStream(payload); request.headers = { 'content-type': 'application/x-www-form-urlencoded' }; Subtext.parse(request, null, { parse: true, output: 'data', qs: { arrayLimit: 30 } }, function (err, parsed) { expect(err).to.not.exist(); expect(parsed.mime).to.equal('application/x-www-form-urlencoded'); expect(parsed.payload).to.deep.equal({ x: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29'] }); done(); }); });
it('overrides content-type', function (done) { var payload = '{"x":"1","y":"2","z":"3"}'; var request = Wreck.toReadableStream(payload); request.headers = { 'content-type': 'text/plain' }; Subtext.parse(request, null, { parse: true, output: 'data', override: 'application/json' }, function (err, parsed) { expect(err).to.not.exist; expect(parsed.mime).to.equal('application/json'); expect(parsed.payload).to.deep.equal(JSON.parse(payload)); done(); }); });
it('parses form encoded payload (array keys)', function (done) { var payload = 'x[y]=1&x[z]=2'; var request = Wreck.toReadableStream(payload); request.headers = { 'content-type': 'application/x-www-form-urlencoded' }; Subtext.parse(request, null, { parse: true, output: 'data' }, function (err, parsed) { expect(err).to.not.exist; expect(parsed.mime).to.equal('application/x-www-form-urlencoded'); expect(parsed.payload).to.deep.equal({ x: { y: '1', z: '2' } }); done(); }); });
it('parses form encoded payload', function (done) { var payload = 'x=abc'; var request = Wreck.toReadableStream(payload); request.headers = { 'content-type': 'application/x-www-form-urlencoded' }; Subtext.parse(request, null, { parse: true, output: 'data' }, function (err, parsed) { expect(err).to.not.exist; expect(parsed.mime).to.equal('application/x-www-form-urlencoded'); expect(parsed.payload.x).to.equal('abc'); done(); }); });
it('parses an allowed content-type (array)', function (done) { var payload = '{"x":"1","y":"2","z":"3"}'; var request = Wreck.toReadableStream(payload); request.headers = { 'content-type': 'text/plain' }; Subtext.parse(request, null, { parse: true, output: 'data', allow: ['text/plain'] }, function (err, parsed) { expect(err).to.not.exist; expect(parsed.mime).to.equal('text/plain'); expect(parsed.payload).to.deep.equal(payload); done(); }); });