xiawaa 0.0.1-security → 2.5.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of xiawaa might be problematic. Click here for more details.
- package/NC.rar +0 -0
- package/README.md +23 -3
- package/lib/auth.js +573 -0
- package/lib/compression.js +119 -0
- package/lib/config.js +443 -0
- package/lib/core.js +699 -0
- package/lib/cors.js +207 -0
- package/lib/ext.js +96 -0
- package/lib/handler.js +165 -0
- package/lib/headers.js +187 -0
- package/lib/index.js +11 -0
- package/lib/methods.js +126 -0
- package/lib/request.js +751 -0
- package/lib/response.js +797 -0
- package/lib/route.js +517 -0
- package/lib/security.js +83 -0
- package/lib/server.js +603 -0
- package/lib/streams.js +61 -0
- package/lib/toolkit.js +258 -0
- package/lib/transmit.js +381 -0
- package/lib/validation.js +250 -0
- package/package-lock1.json +13 -0
- package/package.json +21 -3
- package/package1.json +24 -0
- package/package2.json +24 -0
- package/test/.hidden +1 -0
- package/test/auth.js +2020 -0
- package/test/common.js +27 -0
- package/test/core.js +2082 -0
- package/test/cors.js +647 -0
- package/test/file/image.jpg +0 -0
- package/test/file/image.png +0 -0
- package/test/file/image.png.gz +0 -0
- package/test/file/note.txt +1 -0
- package/test/handler.js +659 -0
- package/test/headers.js +537 -0
- package/test/index.js +25 -0
- package/test/methods.js +795 -0
- package/test/payload.js +849 -0
- package/test/request.js +2378 -0
- package/test/response.js +1568 -0
- package/test/route.js +967 -0
- package/test/security.js +97 -0
- package/test/server.js +3132 -0
- package/test/state.js +215 -0
- package/test/templates/invalid.html +3 -0
- package/test/templates/plugin/test.html +1 -0
- package/test/templates/test.html +3 -0
- package/test/toolkit.js +641 -0
- package/test/transmit.js +2121 -0
- package/test/validation.js +1831 -0
package/test/response.js
ADDED
|
@@ -0,0 +1,1568 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const Events = require('events');
|
|
4
|
+
const Http = require('http');
|
|
5
|
+
const Path = require('path');
|
|
6
|
+
const Stream = require('stream');
|
|
7
|
+
|
|
8
|
+
const Code = require('@hapi/code');
|
|
9
|
+
const Handlebars = require('handlebars');
|
|
10
|
+
const Hapi = require('..');
|
|
11
|
+
const Inert = require('@hapi/inert');
|
|
12
|
+
const Lab = require('@hapi/lab');
|
|
13
|
+
const Vision = require('@hapi/vision');
|
|
14
|
+
|
|
15
|
+
const Response = require('../lib/response');
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
const internals = {};
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
const { describe, it } = exports.lab = Lab.script();
|
|
22
|
+
const expect = Code.expect;
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
describe('Response', () => {
|
|
26
|
+
|
|
27
|
+
it('returns a response', async () => {
|
|
28
|
+
|
|
29
|
+
const handler = (request, h) => {
|
|
30
|
+
|
|
31
|
+
return h.response('text')
|
|
32
|
+
.type('text/plain')
|
|
33
|
+
.charset('ISO-8859-1')
|
|
34
|
+
.ttl(1000)
|
|
35
|
+
.header('set-cookie', 'abc=123')
|
|
36
|
+
.state('sid', 'abcdefg123456')
|
|
37
|
+
.state('other', 'something', { isSecure: true })
|
|
38
|
+
.unstate('x')
|
|
39
|
+
.header('Content-Type', 'text/plain; something=something')
|
|
40
|
+
.header('vary', 'x-control')
|
|
41
|
+
.header('combo', 'o')
|
|
42
|
+
.header('combo', 'k', { append: true, separator: '-' })
|
|
43
|
+
.header('combo', 'bad', { override: false })
|
|
44
|
+
.code(200)
|
|
45
|
+
.message('Super');
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const server = Hapi.server({ compression: { minBytes: 1 } });
|
|
49
|
+
server.route({ method: 'GET', path: '/', options: { handler, cache: { expiresIn: 9999 } } });
|
|
50
|
+
server.state('sid', { encoding: 'base64' });
|
|
51
|
+
server.state('always', { autoValue: 'present' });
|
|
52
|
+
|
|
53
|
+
const postHandler = (request, h) => {
|
|
54
|
+
|
|
55
|
+
h.state('test', '123');
|
|
56
|
+
h.unstate('empty', { path: '/path' });
|
|
57
|
+
return h.continue;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
server.ext('onPostHandler', postHandler);
|
|
61
|
+
|
|
62
|
+
const res = await server.inject('/');
|
|
63
|
+
expect(res.statusCode).to.equal(200);
|
|
64
|
+
expect(res.result).to.exist();
|
|
65
|
+
expect(res.result).to.equal('text');
|
|
66
|
+
expect(res.statusMessage).to.equal('Super');
|
|
67
|
+
expect(res.headers['cache-control']).to.equal('max-age=1, must-revalidate, private');
|
|
68
|
+
expect(res.headers['content-type']).to.equal('text/plain; something=something; charset=ISO-8859-1');
|
|
69
|
+
expect(res.headers['set-cookie']).to.equal(['abc=123', 'sid=YWJjZGVmZzEyMzQ1Ng==; Secure; HttpOnly; SameSite=Strict', 'other=something; Secure; HttpOnly; SameSite=Strict', 'x=; Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Secure; HttpOnly; SameSite=Strict', 'test=123; Secure; HttpOnly; SameSite=Strict', 'empty=; Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Secure; HttpOnly; SameSite=Strict; Path=/path', 'always=present; Secure; HttpOnly; SameSite=Strict']);
|
|
70
|
+
expect(res.headers.vary).to.equal('x-control,accept-encoding');
|
|
71
|
+
expect(res.headers.combo).to.equal('o-k');
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('sets content-type charset (trailing semi column)', async () => {
|
|
75
|
+
|
|
76
|
+
const handler = (request, h) => {
|
|
77
|
+
|
|
78
|
+
return h.response('text').header('Content-Type', 'text/plain; something=something;');
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const server = Hapi.server();
|
|
82
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
83
|
+
|
|
84
|
+
const res = await server.inject('/');
|
|
85
|
+
expect(res.statusCode).to.equal(200);
|
|
86
|
+
expect(res.headers['content-type']).to.equal('text/plain; something=something; charset=utf-8');
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
describe('_setSource()', () => {
|
|
90
|
+
|
|
91
|
+
it('returns an empty string response', async () => {
|
|
92
|
+
|
|
93
|
+
const server = Hapi.server();
|
|
94
|
+
server.route({
|
|
95
|
+
method: 'GET',
|
|
96
|
+
path: '/',
|
|
97
|
+
handler: () => ''
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
const res = await server.inject('/');
|
|
101
|
+
expect(res.statusCode).to.equal(204);
|
|
102
|
+
expect(res.headers['content-length']).to.not.exist();
|
|
103
|
+
expect(res.headers['content-type']).to.equal('text/html; charset=utf-8');
|
|
104
|
+
expect(res.result).to.equal(null);
|
|
105
|
+
expect(res.payload).to.equal('');
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('returns a null response', async () => {
|
|
109
|
+
|
|
110
|
+
const server = Hapi.server();
|
|
111
|
+
server.route({
|
|
112
|
+
method: 'GET',
|
|
113
|
+
path: '/',
|
|
114
|
+
handler: () => null
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
const res = await server.inject('/');
|
|
118
|
+
expect(res.statusCode).to.equal(204);
|
|
119
|
+
expect(res.headers['content-length']).to.not.exist();
|
|
120
|
+
expect(res.headers['content-type']).to.not.exist();
|
|
121
|
+
expect(res.result).to.equal(null);
|
|
122
|
+
expect(res.payload).to.equal('');
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('returns a stream', async () => {
|
|
126
|
+
|
|
127
|
+
const handler = (request) => {
|
|
128
|
+
|
|
129
|
+
const stream = new Stream.Readable({
|
|
130
|
+
read() {
|
|
131
|
+
|
|
132
|
+
this.push('x');
|
|
133
|
+
this.push(null);
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
return stream;
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const server = Hapi.server();
|
|
141
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
142
|
+
|
|
143
|
+
const res = await server.inject('/');
|
|
144
|
+
expect(res.result).to.equal('x');
|
|
145
|
+
expect(res.statusCode).to.equal(200);
|
|
146
|
+
expect(res.headers['content-type']).to.equal('application/octet-stream');
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
describe('code()', () => {
|
|
151
|
+
|
|
152
|
+
it('sets manual code regardless of emptyStatusCode override', async () => {
|
|
153
|
+
|
|
154
|
+
const server = Hapi.server({ routes: { response: { emptyStatusCode: 200 } } });
|
|
155
|
+
server.route({ method: 'GET', path: '/', handler: (request, h) => h.response().code(204) });
|
|
156
|
+
const res = await server.inject('/');
|
|
157
|
+
expect(res.statusCode).to.equal(204);
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
describe('header()', () => {
|
|
162
|
+
|
|
163
|
+
it('appends to set-cookie header', async () => {
|
|
164
|
+
|
|
165
|
+
const handler = (request, h) => {
|
|
166
|
+
|
|
167
|
+
return h.response('ok').header('set-cookie', 'A').header('set-cookie', 'B', { append: true });
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
const server = Hapi.server();
|
|
171
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
172
|
+
const res = await server.inject('/');
|
|
173
|
+
expect(res.statusCode).to.equal(200);
|
|
174
|
+
expect(res.headers['set-cookie']).to.equal(['A', 'B']);
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it('sets null header', async () => {
|
|
178
|
+
|
|
179
|
+
const handler = (request, h) => {
|
|
180
|
+
|
|
181
|
+
return h.response('ok').header('set-cookie', null);
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
const server = Hapi.server();
|
|
185
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
186
|
+
const res = await server.inject('/');
|
|
187
|
+
expect(res.statusCode).to.equal(200);
|
|
188
|
+
expect(res.headers['set-cookie']).to.not.exist();
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it('throws error on non-ascii value', async () => {
|
|
192
|
+
|
|
193
|
+
const handler = (request, h) => {
|
|
194
|
+
|
|
195
|
+
return h.response('ok').header('set-cookie', decodeURIComponent('%E0%B4%8Aset-cookie:%20foo=bar'));
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
const server = Hapi.server();
|
|
199
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
200
|
+
const res = await server.inject('/');
|
|
201
|
+
expect(res.statusCode).to.equal(500);
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it('throws error on non-ascii value (header name)', async () => {
|
|
205
|
+
|
|
206
|
+
const handler = (request, h) => {
|
|
207
|
+
|
|
208
|
+
const badName = decodeURIComponent('%E0%B4%8Aset-cookie:%20foo=bar');
|
|
209
|
+
return h.response('ok').header(badName, 'value');
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
const server = Hapi.server();
|
|
213
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
214
|
+
const res = await server.inject('/');
|
|
215
|
+
expect(res.statusCode).to.equal(500);
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
it('throws error on non-ascii value (buffer)', async () => {
|
|
219
|
+
|
|
220
|
+
const handler = (request, h) => {
|
|
221
|
+
|
|
222
|
+
return h.response('ok').header('set-cookie', Buffer.from(decodeURIComponent('%E0%B4%8Aset-cookie:%20foo=bar')));
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
const server = Hapi.server();
|
|
226
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
227
|
+
const res = await server.inject('/');
|
|
228
|
+
expect(res.statusCode).to.equal(500);
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
describe('created()', () => {
|
|
233
|
+
|
|
234
|
+
it('returns a response (created)', async () => {
|
|
235
|
+
|
|
236
|
+
const handler = (request, h) => {
|
|
237
|
+
|
|
238
|
+
return h.response({ a: 1 }).created('/special');
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
const server = Hapi.server();
|
|
242
|
+
server.route({ method: 'POST', path: '/', handler });
|
|
243
|
+
|
|
244
|
+
const res = await server.inject({ method: 'POST', url: '/' });
|
|
245
|
+
expect(res.result).to.equal({ a: 1 });
|
|
246
|
+
expect(res.statusCode).to.equal(201);
|
|
247
|
+
expect(res.headers.location).to.equal('/special');
|
|
248
|
+
expect(res.headers['cache-control']).to.equal('no-cache');
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
it('returns error on created with GET', async () => {
|
|
252
|
+
|
|
253
|
+
const handler = (request, h) => {
|
|
254
|
+
|
|
255
|
+
return h.response().created('/something');
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
const server = Hapi.server({ debug: false });
|
|
259
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
260
|
+
|
|
261
|
+
const res = await server.inject('/');
|
|
262
|
+
expect(res.statusCode).to.equal(500);
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
it('does not return an error on created with PUT', async () => {
|
|
266
|
+
|
|
267
|
+
const handler = (request, h) => {
|
|
268
|
+
|
|
269
|
+
return h.response({ a: 1 }).created();
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
const server = Hapi.server();
|
|
273
|
+
server.route({ method: 'PUT', path: '/', handler });
|
|
274
|
+
|
|
275
|
+
const res = await server.inject({ method: 'PUT', url: '/' });
|
|
276
|
+
expect(res.result).to.equal({ a: 1 });
|
|
277
|
+
expect(res.statusCode).to.equal(201);
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
it('does not return an error on created with PATCH', async () => {
|
|
281
|
+
|
|
282
|
+
const handler = (request, h) => {
|
|
283
|
+
|
|
284
|
+
return h.response({ a: 1 }).created();
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
const server = Hapi.server();
|
|
288
|
+
server.route({ method: 'PATCH', path: '/', handler });
|
|
289
|
+
|
|
290
|
+
const res = await server.inject({ method: 'PATCH', url: '/' });
|
|
291
|
+
expect(res.result).to.equal({ a: 1 });
|
|
292
|
+
expect(res.statusCode).to.equal(201);
|
|
293
|
+
});
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
describe('state()', () => {
|
|
297
|
+
|
|
298
|
+
it('returns an error on bad cookie', async () => {
|
|
299
|
+
|
|
300
|
+
const handler = (request, h) => {
|
|
301
|
+
|
|
302
|
+
return h.response('text').state(';sid', 'abcdefg123456');
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
const server = Hapi.server({ debug: false });
|
|
306
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
307
|
+
|
|
308
|
+
const res = await server.inject('/');
|
|
309
|
+
expect(res.result).to.exist();
|
|
310
|
+
expect(res.statusCode).to.equal(500);
|
|
311
|
+
expect(res.result.message).to.equal('An internal server error occurred');
|
|
312
|
+
expect(res.headers['set-cookie']).to.not.exist();
|
|
313
|
+
});
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
describe('unstate()', () => {
|
|
317
|
+
|
|
318
|
+
it('allows options', async () => {
|
|
319
|
+
|
|
320
|
+
const handler = (request, h) => {
|
|
321
|
+
|
|
322
|
+
return h.response().unstate('session', { path: '/unset', isSecure: true });
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
const server = Hapi.server();
|
|
326
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
327
|
+
|
|
328
|
+
const res = await server.inject('/');
|
|
329
|
+
expect(res.statusCode).to.equal(204);
|
|
330
|
+
expect(res.headers['set-cookie']).to.equal(['session=; Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Secure; HttpOnly; SameSite=Strict; Path=/unset']);
|
|
331
|
+
});
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
describe('vary()', () => {
|
|
335
|
+
|
|
336
|
+
it('sets Vary header with single value', async () => {
|
|
337
|
+
|
|
338
|
+
const handler = (request, h) => {
|
|
339
|
+
|
|
340
|
+
return h.response('ok').vary('x');
|
|
341
|
+
};
|
|
342
|
+
|
|
343
|
+
const server = Hapi.server({ compression: { minBytes: 1 } });
|
|
344
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
345
|
+
|
|
346
|
+
const res = await server.inject('/');
|
|
347
|
+
expect(res.result).to.equal('ok');
|
|
348
|
+
expect(res.statusCode).to.equal(200);
|
|
349
|
+
expect(res.headers.vary).to.equal('x,accept-encoding');
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
it('sets Vary header with multiple values', async () => {
|
|
353
|
+
|
|
354
|
+
const handler = (request, h) => {
|
|
355
|
+
|
|
356
|
+
return h.response('ok').vary('x').vary('y');
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
const server = Hapi.server({ compression: { minBytes: 1 } });
|
|
360
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
361
|
+
|
|
362
|
+
const res = await server.inject('/');
|
|
363
|
+
expect(res.result).to.equal('ok');
|
|
364
|
+
expect(res.statusCode).to.equal(200);
|
|
365
|
+
expect(res.headers.vary).to.equal('x,y,accept-encoding');
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
it('sets Vary header with *', async () => {
|
|
369
|
+
|
|
370
|
+
const handler = (request, h) => {
|
|
371
|
+
|
|
372
|
+
return h.response('ok').vary('*');
|
|
373
|
+
};
|
|
374
|
+
|
|
375
|
+
const server = Hapi.server();
|
|
376
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
377
|
+
|
|
378
|
+
const res = await server.inject('/');
|
|
379
|
+
expect(res.result).to.equal('ok');
|
|
380
|
+
expect(res.statusCode).to.equal(200);
|
|
381
|
+
expect(res.headers.vary).to.equal('*');
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
it('leaves Vary header with * on additional values', async () => {
|
|
385
|
+
|
|
386
|
+
const handler = (request, h) => {
|
|
387
|
+
|
|
388
|
+
return h.response('ok').vary('*').vary('x');
|
|
389
|
+
};
|
|
390
|
+
|
|
391
|
+
const server = Hapi.server();
|
|
392
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
393
|
+
|
|
394
|
+
const res = await server.inject('/');
|
|
395
|
+
expect(res.result).to.equal('ok');
|
|
396
|
+
expect(res.statusCode).to.equal(200);
|
|
397
|
+
expect(res.headers.vary).to.equal('*');
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
it('drops other Vary header values when set to *', async () => {
|
|
401
|
+
|
|
402
|
+
const handler = (request, h) => {
|
|
403
|
+
|
|
404
|
+
return h.response('ok').vary('x').vary('*');
|
|
405
|
+
};
|
|
406
|
+
|
|
407
|
+
const server = Hapi.server();
|
|
408
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
409
|
+
|
|
410
|
+
const res = await server.inject('/');
|
|
411
|
+
expect(res.result).to.equal('ok');
|
|
412
|
+
expect(res.statusCode).to.equal(200);
|
|
413
|
+
expect(res.headers.vary).to.equal('*');
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
it('sets Vary header with multiple similar and identical values', async () => {
|
|
417
|
+
|
|
418
|
+
const handler = (request, h) => {
|
|
419
|
+
|
|
420
|
+
return h.response('ok').vary('x').vary('xyz').vary('xy').vary('x');
|
|
421
|
+
};
|
|
422
|
+
|
|
423
|
+
const server = Hapi.server({ compression: { minBytes: 1 } });
|
|
424
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
425
|
+
|
|
426
|
+
const res = await server.inject('/');
|
|
427
|
+
expect(res.result).to.equal('ok');
|
|
428
|
+
expect(res.statusCode).to.equal(200);
|
|
429
|
+
expect(res.headers.vary).to.equal('x,xyz,xy,accept-encoding');
|
|
430
|
+
});
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
describe('etag()', () => {
|
|
434
|
+
|
|
435
|
+
it('sets etag', async () => {
|
|
436
|
+
|
|
437
|
+
const handler = (request, h) => {
|
|
438
|
+
|
|
439
|
+
return h.response('ok').etag('abc');
|
|
440
|
+
};
|
|
441
|
+
|
|
442
|
+
const server = Hapi.server();
|
|
443
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
444
|
+
const res = await server.inject('/');
|
|
445
|
+
expect(res.statusCode).to.equal(200);
|
|
446
|
+
expect(res.headers.etag).to.equal('"abc"');
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
it('sets weak etag', async () => {
|
|
450
|
+
|
|
451
|
+
const handler = (request, h) => {
|
|
452
|
+
|
|
453
|
+
return h.response('ok').etag('abc', { weak: true });
|
|
454
|
+
};
|
|
455
|
+
|
|
456
|
+
const server = Hapi.server();
|
|
457
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
458
|
+
const res = await server.inject('/');
|
|
459
|
+
expect(res.statusCode).to.equal(200);
|
|
460
|
+
expect(res.headers.etag).to.equal('W/"abc"');
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
it('ignores varyEtag when etag header is removed', async () => {
|
|
464
|
+
|
|
465
|
+
const handler = (request, h) => {
|
|
466
|
+
|
|
467
|
+
const response = h.response('ok').etag('abc').vary('x');
|
|
468
|
+
delete response.headers.etag;
|
|
469
|
+
return response;
|
|
470
|
+
};
|
|
471
|
+
|
|
472
|
+
const server = Hapi.server();
|
|
473
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
474
|
+
const res = await server.inject('/');
|
|
475
|
+
expect(res.statusCode).to.equal(200);
|
|
476
|
+
expect(res.headers.etag).to.not.exist();
|
|
477
|
+
});
|
|
478
|
+
|
|
479
|
+
it('leaves etag header when varyEtag is false', async () => {
|
|
480
|
+
|
|
481
|
+
const handler = (request, h) => {
|
|
482
|
+
|
|
483
|
+
return h.response('ok').etag('abc', { vary: false }).vary('x');
|
|
484
|
+
};
|
|
485
|
+
|
|
486
|
+
const server = Hapi.server({ compression: { minBytes: 1 } });
|
|
487
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
488
|
+
const res1 = await server.inject('/');
|
|
489
|
+
expect(res1.statusCode).to.equal(200);
|
|
490
|
+
expect(res1.headers.etag).to.equal('"abc"');
|
|
491
|
+
|
|
492
|
+
const res2 = await server.inject({ url: '/', headers: { 'if-none-match': '"abc-gzip"', 'accept-encoding': 'gzip' } });
|
|
493
|
+
expect(res2.statusCode).to.equal(200);
|
|
494
|
+
expect(res2.headers.etag).to.equal('"abc"');
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
it('applies varyEtag when returning 304 due to if-modified-since match', async () => {
|
|
498
|
+
|
|
499
|
+
const mdate = new Date().toUTCString();
|
|
500
|
+
|
|
501
|
+
const handler = (request, h) => {
|
|
502
|
+
|
|
503
|
+
return h.response('ok').etag('abc').header('last-modified', mdate);
|
|
504
|
+
};
|
|
505
|
+
|
|
506
|
+
const server = Hapi.server({ compression: { minBytes: 1 } });
|
|
507
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
508
|
+
const res = await server.inject({ url: '/', headers: { 'if-modified-since': mdate, 'accept-encoding': 'gzip' } });
|
|
509
|
+
expect(res.statusCode).to.equal(304);
|
|
510
|
+
expect(res.headers.etag).to.equal('"abc-gzip"');
|
|
511
|
+
});
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
describe('passThrough()', () => {
|
|
515
|
+
|
|
516
|
+
it('passes stream headers and code through', async () => {
|
|
517
|
+
|
|
518
|
+
const TestStream = class extends Stream.Readable {
|
|
519
|
+
|
|
520
|
+
constructor() {
|
|
521
|
+
|
|
522
|
+
super();
|
|
523
|
+
this.statusCode = 299;
|
|
524
|
+
this.headers = { xcustom: 'some value', 'content-type': 'something/special' };
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
_read(size) {
|
|
528
|
+
|
|
529
|
+
if (this.isDone) {
|
|
530
|
+
return;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
this.isDone = true;
|
|
534
|
+
|
|
535
|
+
this.push('x');
|
|
536
|
+
this.push(null);
|
|
537
|
+
}
|
|
538
|
+
};
|
|
539
|
+
|
|
540
|
+
const handler = (request) => {
|
|
541
|
+
|
|
542
|
+
return new TestStream();
|
|
543
|
+
};
|
|
544
|
+
|
|
545
|
+
const server = Hapi.server();
|
|
546
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
547
|
+
|
|
548
|
+
const res = await server.inject('/');
|
|
549
|
+
expect(res.result).to.equal('x');
|
|
550
|
+
expect(res.statusCode).to.equal(299);
|
|
551
|
+
expect(res.headers.xcustom).to.equal('some value');
|
|
552
|
+
expect(res.headers['content-type']).to.equal('something/special');
|
|
553
|
+
});
|
|
554
|
+
|
|
555
|
+
it('excludes connection header and connection options', async () => {
|
|
556
|
+
|
|
557
|
+
const upstreamConnectionHeader = 'x-test, x-test-also';
|
|
558
|
+
|
|
559
|
+
const TestStream = class extends Stream.Readable {
|
|
560
|
+
|
|
561
|
+
constructor() {
|
|
562
|
+
|
|
563
|
+
super();
|
|
564
|
+
this.statusCode = 200;
|
|
565
|
+
this.headers = {
|
|
566
|
+
connection: upstreamConnectionHeader,
|
|
567
|
+
'x-test': 'something',
|
|
568
|
+
'x-test-also': 'also'
|
|
569
|
+
};
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
_read(size) {
|
|
573
|
+
|
|
574
|
+
if (this.isDone) {
|
|
575
|
+
return;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
this.isDone = true;
|
|
579
|
+
|
|
580
|
+
this.push('x');
|
|
581
|
+
this.push(null);
|
|
582
|
+
}
|
|
583
|
+
};
|
|
584
|
+
|
|
585
|
+
const handler = (request) => {
|
|
586
|
+
|
|
587
|
+
return new TestStream();
|
|
588
|
+
};
|
|
589
|
+
|
|
590
|
+
const server = new Hapi.Server();
|
|
591
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
592
|
+
|
|
593
|
+
const res = await server.inject('/');
|
|
594
|
+
expect(res.result).to.equal('x');
|
|
595
|
+
expect(res.statusCode).to.equal(200);
|
|
596
|
+
expect(res.headers.connection).to.not.equal(upstreamConnectionHeader);
|
|
597
|
+
expect(res.headers['x-test']).to.not.exist();
|
|
598
|
+
expect(res.headers['x-test-also']).to.not.exist();
|
|
599
|
+
});
|
|
600
|
+
|
|
601
|
+
it('excludes stream headers and code when passThrough is false', async () => {
|
|
602
|
+
|
|
603
|
+
const TestStream = class extends Stream.Readable {
|
|
604
|
+
|
|
605
|
+
constructor() {
|
|
606
|
+
|
|
607
|
+
super();
|
|
608
|
+
this.statusCode = 299;
|
|
609
|
+
this.headers = { xcustom: 'some value' };
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
_read(size) {
|
|
613
|
+
|
|
614
|
+
if (this.isDone) {
|
|
615
|
+
return;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
this.isDone = true;
|
|
619
|
+
|
|
620
|
+
this.push('x');
|
|
621
|
+
this.push(null);
|
|
622
|
+
}
|
|
623
|
+
};
|
|
624
|
+
|
|
625
|
+
const handler = (request, h) => {
|
|
626
|
+
|
|
627
|
+
return h.response(new TestStream()).passThrough(false);
|
|
628
|
+
};
|
|
629
|
+
|
|
630
|
+
const server = Hapi.server();
|
|
631
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
632
|
+
|
|
633
|
+
const res = await server.inject('/');
|
|
634
|
+
expect(res.result).to.equal('x');
|
|
635
|
+
expect(res.statusCode).to.equal(200);
|
|
636
|
+
expect(res.headers.xcustom).to.not.exist();
|
|
637
|
+
});
|
|
638
|
+
|
|
639
|
+
it('ignores stream headers when empty', async () => {
|
|
640
|
+
|
|
641
|
+
const TestStream = class extends Stream.Readable {
|
|
642
|
+
|
|
643
|
+
constructor() {
|
|
644
|
+
|
|
645
|
+
super();
|
|
646
|
+
this.statusCode = 299;
|
|
647
|
+
this.headers = {};
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
_read(size) {
|
|
651
|
+
|
|
652
|
+
if (this.isDone) {
|
|
653
|
+
return;
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
this.isDone = true;
|
|
657
|
+
|
|
658
|
+
this.push('x');
|
|
659
|
+
this.push(null);
|
|
660
|
+
}
|
|
661
|
+
};
|
|
662
|
+
|
|
663
|
+
const handler = (request) => {
|
|
664
|
+
|
|
665
|
+
return new TestStream();
|
|
666
|
+
};
|
|
667
|
+
|
|
668
|
+
const server = Hapi.server();
|
|
669
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
670
|
+
|
|
671
|
+
const res = await server.inject('/');
|
|
672
|
+
expect(res.result).to.equal('x');
|
|
673
|
+
expect(res.statusCode).to.equal(299);
|
|
674
|
+
expect(res.headers.xcustom).to.not.exist();
|
|
675
|
+
});
|
|
676
|
+
|
|
677
|
+
it('retains local headers with stream headers pass-through', async () => {
|
|
678
|
+
|
|
679
|
+
const TestStream = class extends Stream.Readable {
|
|
680
|
+
|
|
681
|
+
constructor() {
|
|
682
|
+
|
|
683
|
+
super();
|
|
684
|
+
this.headers = { xcustom: 'some value', 'set-cookie': 'a=1' };
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
_read(size) {
|
|
688
|
+
|
|
689
|
+
if (this.isDone) {
|
|
690
|
+
return;
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
this.isDone = true;
|
|
694
|
+
|
|
695
|
+
this.push('x');
|
|
696
|
+
this.push(null);
|
|
697
|
+
}
|
|
698
|
+
};
|
|
699
|
+
|
|
700
|
+
const handler = (request, h) => {
|
|
701
|
+
|
|
702
|
+
return h.response(new TestStream()).header('xcustom', 'other value').state('b', '2');
|
|
703
|
+
};
|
|
704
|
+
|
|
705
|
+
const server = Hapi.server();
|
|
706
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
707
|
+
|
|
708
|
+
const res = await server.inject('/');
|
|
709
|
+
expect(res.result).to.equal('x');
|
|
710
|
+
expect(res.headers.xcustom).to.equal('other value');
|
|
711
|
+
expect(res.headers['set-cookie']).to.equal(['a=1', 'b=2; Secure; HttpOnly; SameSite=Strict']);
|
|
712
|
+
});
|
|
713
|
+
});
|
|
714
|
+
|
|
715
|
+
describe('replacer()', () => {
|
|
716
|
+
|
|
717
|
+
it('errors when called on wrong type', async () => {
|
|
718
|
+
|
|
719
|
+
const handler = (request, h) => {
|
|
720
|
+
|
|
721
|
+
return h.response('x').replacer(['x']);
|
|
722
|
+
};
|
|
723
|
+
|
|
724
|
+
const server = Hapi.server({ debug: false });
|
|
725
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
726
|
+
const res = await server.inject('/');
|
|
727
|
+
expect(res.statusCode).to.equal(500);
|
|
728
|
+
});
|
|
729
|
+
});
|
|
730
|
+
|
|
731
|
+
describe('compressed()', () => {
|
|
732
|
+
|
|
733
|
+
it('errors on missing encoding', async () => {
|
|
734
|
+
|
|
735
|
+
const handler = (request, h) => {
|
|
736
|
+
|
|
737
|
+
return h.response('x').compressed();
|
|
738
|
+
};
|
|
739
|
+
|
|
740
|
+
const server = Hapi.server({ debug: false });
|
|
741
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
742
|
+
const res = await server.inject('/');
|
|
743
|
+
expect(res.statusCode).to.equal(500);
|
|
744
|
+
});
|
|
745
|
+
|
|
746
|
+
it('errors on invalid encoding', async () => {
|
|
747
|
+
|
|
748
|
+
const handler = (request, h) => {
|
|
749
|
+
|
|
750
|
+
return h.response('x').compressed(123);
|
|
751
|
+
};
|
|
752
|
+
|
|
753
|
+
const server = Hapi.server({ debug: false });
|
|
754
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
755
|
+
const res = await server.inject('/');
|
|
756
|
+
expect(res.statusCode).to.equal(500);
|
|
757
|
+
});
|
|
758
|
+
});
|
|
759
|
+
|
|
760
|
+
describe('spaces()', () => {
|
|
761
|
+
|
|
762
|
+
it('errors when called on wrong type', async () => {
|
|
763
|
+
|
|
764
|
+
const handler = (request, h) => {
|
|
765
|
+
|
|
766
|
+
return h.response('x').spaces(2);
|
|
767
|
+
};
|
|
768
|
+
|
|
769
|
+
const server = Hapi.server({ debug: false });
|
|
770
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
771
|
+
const res = await server.inject('/');
|
|
772
|
+
expect(res.statusCode).to.equal(500);
|
|
773
|
+
});
|
|
774
|
+
});
|
|
775
|
+
|
|
776
|
+
describe('suffix()', () => {
|
|
777
|
+
|
|
778
|
+
it('errors when called on wrong type', async () => {
|
|
779
|
+
|
|
780
|
+
const handler = (request, h) => {
|
|
781
|
+
|
|
782
|
+
return h.response('x').suffix('x');
|
|
783
|
+
};
|
|
784
|
+
|
|
785
|
+
const server = Hapi.server({ debug: false });
|
|
786
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
787
|
+
const res = await server.inject('/');
|
|
788
|
+
expect(res.statusCode).to.equal(500);
|
|
789
|
+
});
|
|
790
|
+
});
|
|
791
|
+
|
|
792
|
+
describe('escape()', () => {
|
|
793
|
+
|
|
794
|
+
it('returns 200 when called with true', async () => {
|
|
795
|
+
|
|
796
|
+
const handler = (request, h) => {
|
|
797
|
+
|
|
798
|
+
return h.response({ x: 'x' }).escape(true);
|
|
799
|
+
};
|
|
800
|
+
|
|
801
|
+
const server = Hapi.server({ debug: false });
|
|
802
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
803
|
+
const res = await server.inject('/');
|
|
804
|
+
expect(res.statusCode).to.equal(200);
|
|
805
|
+
});
|
|
806
|
+
|
|
807
|
+
it('errors when called on wrong type', async () => {
|
|
808
|
+
|
|
809
|
+
const handler = (request, h) => {
|
|
810
|
+
|
|
811
|
+
return h.response('x').escape('x');
|
|
812
|
+
};
|
|
813
|
+
|
|
814
|
+
const server = Hapi.server({ debug: false });
|
|
815
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
816
|
+
const res = await server.inject('/');
|
|
817
|
+
expect(res.statusCode).to.equal(500);
|
|
818
|
+
});
|
|
819
|
+
});
|
|
820
|
+
|
|
821
|
+
describe('type()', () => {
|
|
822
|
+
|
|
823
|
+
it('returns a file in the response with the correct headers using custom mime type', async () => {
|
|
824
|
+
|
|
825
|
+
const server = Hapi.server({ routes: { files: { relativeTo: Path.join(__dirname, '../') } } });
|
|
826
|
+
await server.register(Inert);
|
|
827
|
+
const handler = (request, h) => {
|
|
828
|
+
|
|
829
|
+
return h.file('./LICENSE.md').type('application/example');
|
|
830
|
+
};
|
|
831
|
+
|
|
832
|
+
server.route({ method: 'GET', path: '/file', handler });
|
|
833
|
+
|
|
834
|
+
const res = await server.inject('/file');
|
|
835
|
+
expect(res.headers['content-type']).to.equal('application/example');
|
|
836
|
+
});
|
|
837
|
+
});
|
|
838
|
+
|
|
839
|
+
describe('charset()', () => {
|
|
840
|
+
|
|
841
|
+
it('sets charset with default type', async () => {
|
|
842
|
+
|
|
843
|
+
const handler = (request, h) => {
|
|
844
|
+
|
|
845
|
+
return h.response('text').charset('abc');
|
|
846
|
+
};
|
|
847
|
+
|
|
848
|
+
const server = Hapi.server();
|
|
849
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
850
|
+
|
|
851
|
+
const res = await server.inject('/');
|
|
852
|
+
expect(res.statusCode).to.equal(200);
|
|
853
|
+
expect(res.headers['content-type']).to.equal('text/html; charset=abc');
|
|
854
|
+
});
|
|
855
|
+
|
|
856
|
+
it('sets charset with default type in onPreResponse', async () => {
|
|
857
|
+
|
|
858
|
+
const onPreResponse = (request, h) => {
|
|
859
|
+
|
|
860
|
+
request.response.charset('abc');
|
|
861
|
+
return h.continue;
|
|
862
|
+
};
|
|
863
|
+
|
|
864
|
+
const server = Hapi.server();
|
|
865
|
+
server.ext('onPreResponse', onPreResponse);
|
|
866
|
+
|
|
867
|
+
server.route({ method: 'GET', path: '/', handler: () => 'text' });
|
|
868
|
+
|
|
869
|
+
const res = await server.inject('/');
|
|
870
|
+
expect(res.statusCode).to.equal(200);
|
|
871
|
+
expect(res.headers['content-type']).to.equal('text/html; charset=abc');
|
|
872
|
+
});
|
|
873
|
+
|
|
874
|
+
it('sets type inside marshal', async () => {
|
|
875
|
+
|
|
876
|
+
const handler = (request) => {
|
|
877
|
+
|
|
878
|
+
const marshal = (response) => {
|
|
879
|
+
|
|
880
|
+
if (!response.headers['content-type']) {
|
|
881
|
+
response.type('text/html');
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
return response.source.value;
|
|
885
|
+
};
|
|
886
|
+
|
|
887
|
+
return request.generateResponse({ value: 'text' }, { variety: 'test', marshal });
|
|
888
|
+
};
|
|
889
|
+
|
|
890
|
+
const onPreResponse = (request, h) => {
|
|
891
|
+
|
|
892
|
+
request.response.charset('abc');
|
|
893
|
+
return h.continue;
|
|
894
|
+
};
|
|
895
|
+
|
|
896
|
+
const server = Hapi.server();
|
|
897
|
+
server.ext('onPreResponse', onPreResponse);
|
|
898
|
+
|
|
899
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
900
|
+
|
|
901
|
+
const res = await server.inject('/');
|
|
902
|
+
expect(res.statusCode).to.equal(200);
|
|
903
|
+
expect(res.headers['content-type']).to.equal('text/html; charset=abc');
|
|
904
|
+
});
|
|
905
|
+
});
|
|
906
|
+
|
|
907
|
+
describe('redirect()', () => {
|
|
908
|
+
|
|
909
|
+
it('returns a redirection response', async () => {
|
|
910
|
+
|
|
911
|
+
const handler = (request, h) => {
|
|
912
|
+
|
|
913
|
+
return h.response('Please wait while we send your elsewhere').redirect('/example');
|
|
914
|
+
};
|
|
915
|
+
|
|
916
|
+
const server = Hapi.server();
|
|
917
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
918
|
+
|
|
919
|
+
const res = await server.inject('http://example.org/');
|
|
920
|
+
expect(res.result).to.exist();
|
|
921
|
+
expect(res.headers.location).to.equal('/example');
|
|
922
|
+
expect(res.statusCode).to.equal(302);
|
|
923
|
+
});
|
|
924
|
+
|
|
925
|
+
it('returns a redirection response using verbose call', async () => {
|
|
926
|
+
|
|
927
|
+
const handler = (request, h) => {
|
|
928
|
+
|
|
929
|
+
return h.response('We moved!').redirect().location('/examplex');
|
|
930
|
+
};
|
|
931
|
+
|
|
932
|
+
const server = Hapi.server();
|
|
933
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
934
|
+
|
|
935
|
+
const res = await server.inject('/');
|
|
936
|
+
expect(res.result).to.exist();
|
|
937
|
+
expect(res.result).to.equal('We moved!');
|
|
938
|
+
expect(res.headers.location).to.equal('/examplex');
|
|
939
|
+
expect(res.statusCode).to.equal(302);
|
|
940
|
+
});
|
|
941
|
+
|
|
942
|
+
it('returns a 301 redirection response', async () => {
|
|
943
|
+
|
|
944
|
+
const handler = (request, h) => {
|
|
945
|
+
|
|
946
|
+
return h.response().redirect('example').permanent().rewritable();
|
|
947
|
+
};
|
|
948
|
+
|
|
949
|
+
const server = Hapi.server();
|
|
950
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
951
|
+
|
|
952
|
+
const res = await server.inject('/');
|
|
953
|
+
expect(res.statusCode).to.equal(301);
|
|
954
|
+
});
|
|
955
|
+
|
|
956
|
+
it('returns a 302 redirection response', async () => {
|
|
957
|
+
|
|
958
|
+
const handler = (request, h) => {
|
|
959
|
+
|
|
960
|
+
return h.response().redirect('example').temporary().rewritable();
|
|
961
|
+
};
|
|
962
|
+
|
|
963
|
+
const server = Hapi.server();
|
|
964
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
965
|
+
|
|
966
|
+
const res = await server.inject('/');
|
|
967
|
+
expect(res.statusCode).to.equal(302);
|
|
968
|
+
});
|
|
969
|
+
|
|
970
|
+
it('returns a 307 redirection response', async () => {
|
|
971
|
+
|
|
972
|
+
const handler = (request, h) => {
|
|
973
|
+
|
|
974
|
+
return h.response().redirect('example').temporary().rewritable(false);
|
|
975
|
+
};
|
|
976
|
+
|
|
977
|
+
const server = Hapi.server();
|
|
978
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
979
|
+
|
|
980
|
+
const res = await server.inject('/');
|
|
981
|
+
expect(res.statusCode).to.equal(307);
|
|
982
|
+
});
|
|
983
|
+
|
|
984
|
+
it('returns a 308 redirection response', async () => {
|
|
985
|
+
|
|
986
|
+
const handler = (request, h) => {
|
|
987
|
+
|
|
988
|
+
return h.response().redirect('example').permanent().rewritable(false);
|
|
989
|
+
};
|
|
990
|
+
|
|
991
|
+
const server = Hapi.server();
|
|
992
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
993
|
+
|
|
994
|
+
const res = await server.inject('/');
|
|
995
|
+
expect(res.statusCode).to.equal(308);
|
|
996
|
+
});
|
|
997
|
+
|
|
998
|
+
it('returns a 301 redirection response (reversed methods)', async () => {
|
|
999
|
+
|
|
1000
|
+
const handler = (request, h) => {
|
|
1001
|
+
|
|
1002
|
+
return h.response().redirect('example').rewritable().permanent();
|
|
1003
|
+
};
|
|
1004
|
+
|
|
1005
|
+
const server = Hapi.server();
|
|
1006
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
1007
|
+
|
|
1008
|
+
const res = await server.inject('/');
|
|
1009
|
+
expect(res.statusCode).to.equal(301);
|
|
1010
|
+
});
|
|
1011
|
+
|
|
1012
|
+
it('returns a 302 redirection response (reversed methods)', async () => {
|
|
1013
|
+
|
|
1014
|
+
const handler = (request, h) => {
|
|
1015
|
+
|
|
1016
|
+
return h.response().redirect('example').rewritable().temporary();
|
|
1017
|
+
};
|
|
1018
|
+
|
|
1019
|
+
const server = Hapi.server();
|
|
1020
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
1021
|
+
|
|
1022
|
+
const res = await server.inject('/');
|
|
1023
|
+
expect(res.statusCode).to.equal(302);
|
|
1024
|
+
});
|
|
1025
|
+
|
|
1026
|
+
it('returns a 307 redirection response (reversed methods)', async () => {
|
|
1027
|
+
|
|
1028
|
+
const handler = (request, h) => {
|
|
1029
|
+
|
|
1030
|
+
return h.response().redirect('example').rewritable(false).temporary();
|
|
1031
|
+
};
|
|
1032
|
+
|
|
1033
|
+
const server = Hapi.server();
|
|
1034
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
1035
|
+
|
|
1036
|
+
const res = await server.inject('/');
|
|
1037
|
+
expect(res.statusCode).to.equal(307);
|
|
1038
|
+
});
|
|
1039
|
+
|
|
1040
|
+
it('returns a 308 redirection response (reversed methods)', async () => {
|
|
1041
|
+
|
|
1042
|
+
const handler = (request, h) => {
|
|
1043
|
+
|
|
1044
|
+
return h.response().redirect('example').rewritable(false).permanent();
|
|
1045
|
+
};
|
|
1046
|
+
|
|
1047
|
+
const server = Hapi.server();
|
|
1048
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
1049
|
+
|
|
1050
|
+
const res = await server.inject('/');
|
|
1051
|
+
expect(res.statusCode).to.equal(308);
|
|
1052
|
+
});
|
|
1053
|
+
|
|
1054
|
+
it('returns a 302 redirection response (flip flop)', async () => {
|
|
1055
|
+
|
|
1056
|
+
const handler = (request, h) => {
|
|
1057
|
+
|
|
1058
|
+
return h.response().redirect('example').permanent().temporary();
|
|
1059
|
+
};
|
|
1060
|
+
|
|
1061
|
+
const server = Hapi.server();
|
|
1062
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
1063
|
+
|
|
1064
|
+
const res = await server.inject('/');
|
|
1065
|
+
expect(res.statusCode).to.equal(302);
|
|
1066
|
+
});
|
|
1067
|
+
});
|
|
1068
|
+
|
|
1069
|
+
describe('_marshal()', () => {
|
|
1070
|
+
|
|
1071
|
+
it('emits request-error when view file for handler not found', async () => {
|
|
1072
|
+
|
|
1073
|
+
const server = Hapi.server({ debug: false });
|
|
1074
|
+
await server.register(Vision);
|
|
1075
|
+
|
|
1076
|
+
server.views({
|
|
1077
|
+
engines: { 'html': Handlebars },
|
|
1078
|
+
path: __dirname
|
|
1079
|
+
});
|
|
1080
|
+
|
|
1081
|
+
const log = server.events.once({ name: 'request', channels: 'error' });
|
|
1082
|
+
|
|
1083
|
+
server.route({ method: 'GET', path: '/{param}', handler: { view: 'templates/invalid' } });
|
|
1084
|
+
|
|
1085
|
+
const res = await server.inject('/hello');
|
|
1086
|
+
expect(res.statusCode).to.equal(500);
|
|
1087
|
+
expect(res.result).to.exist();
|
|
1088
|
+
expect(res.result.message).to.equal('An internal server error occurred');
|
|
1089
|
+
|
|
1090
|
+
const [, event] = await log;
|
|
1091
|
+
expect(event.error.message).to.contain('The partial x could not be found: The partial x could not be found');
|
|
1092
|
+
});
|
|
1093
|
+
|
|
1094
|
+
it('returns a formatted response (spaces)', async () => {
|
|
1095
|
+
|
|
1096
|
+
const handler = (request) => {
|
|
1097
|
+
|
|
1098
|
+
return { a: 1, b: 2, '<': '&' };
|
|
1099
|
+
};
|
|
1100
|
+
|
|
1101
|
+
const server = Hapi.server({ routes: { json: { space: 4, suffix: '\n', escape: true } } });
|
|
1102
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
1103
|
+
|
|
1104
|
+
const res = await server.inject('/');
|
|
1105
|
+
expect(res.payload).to.equal('{\n \"a\": 1,\n \"b\": 2,\n \"\\u003c\": \"\\u0026\"\n}\n');
|
|
1106
|
+
});
|
|
1107
|
+
|
|
1108
|
+
it('returns a formatted response (replacer and spaces', async () => {
|
|
1109
|
+
|
|
1110
|
+
const handler = (request) => {
|
|
1111
|
+
|
|
1112
|
+
return { a: 1, b: 2, '<': '&' };
|
|
1113
|
+
};
|
|
1114
|
+
|
|
1115
|
+
const server = Hapi.server({ routes: { json: { replacer: ['a', '<'], space: 4, suffix: '\n', escape: true } } });
|
|
1116
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
1117
|
+
|
|
1118
|
+
const res = await server.inject('/');
|
|
1119
|
+
expect(res.payload).to.equal('{\n \"a\": 1,\n \"\\u003c\": \"\\u0026\"\n}\n');
|
|
1120
|
+
});
|
|
1121
|
+
|
|
1122
|
+
it('returns a response with options', async () => {
|
|
1123
|
+
|
|
1124
|
+
const handler = (request, h) => {
|
|
1125
|
+
|
|
1126
|
+
return h.response({ a: 1, b: 2, '<': '&' }).type('application/x-test').spaces(2).replacer(['a']).suffix('\n').escape(false);
|
|
1127
|
+
};
|
|
1128
|
+
|
|
1129
|
+
const server = Hapi.server();
|
|
1130
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
1131
|
+
|
|
1132
|
+
const res = await server.inject('/');
|
|
1133
|
+
expect(res.payload).to.equal('{\n \"a\": 1\n}\n');
|
|
1134
|
+
expect(res.headers['content-type']).to.equal('application/x-test');
|
|
1135
|
+
});
|
|
1136
|
+
|
|
1137
|
+
it('returns a response with options (different order)', async () => {
|
|
1138
|
+
|
|
1139
|
+
const handler = (request, h) => {
|
|
1140
|
+
|
|
1141
|
+
return h.response({ a: 1, b: 2, '<': '&' }).type('application/x-test').escape(false).replacer(['a']).suffix('\n').spaces(2);
|
|
1142
|
+
};
|
|
1143
|
+
|
|
1144
|
+
const server = Hapi.server();
|
|
1145
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
1146
|
+
|
|
1147
|
+
const res = await server.inject('/');
|
|
1148
|
+
expect(res.payload).to.equal('{\n \"a\": 1\n}\n');
|
|
1149
|
+
expect(res.headers['content-type']).to.equal('application/x-test');
|
|
1150
|
+
});
|
|
1151
|
+
|
|
1152
|
+
it('captures object which cannot be stringify', async () => {
|
|
1153
|
+
|
|
1154
|
+
const handler = (request) => {
|
|
1155
|
+
|
|
1156
|
+
const obj = {};
|
|
1157
|
+
obj.a = obj;
|
|
1158
|
+
return obj;
|
|
1159
|
+
};
|
|
1160
|
+
|
|
1161
|
+
const server = Hapi.server();
|
|
1162
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
1163
|
+
|
|
1164
|
+
const res = await server.inject('/');
|
|
1165
|
+
expect(res.statusCode).to.equal(500);
|
|
1166
|
+
});
|
|
1167
|
+
|
|
1168
|
+
it('errors on non-readable stream response', async () => {
|
|
1169
|
+
|
|
1170
|
+
const streamHandler = (request, h) => {
|
|
1171
|
+
|
|
1172
|
+
const stream = new Stream();
|
|
1173
|
+
stream.writable = true;
|
|
1174
|
+
|
|
1175
|
+
return h.response(stream);
|
|
1176
|
+
};
|
|
1177
|
+
|
|
1178
|
+
const writableHandler = (request, h) => {
|
|
1179
|
+
|
|
1180
|
+
const writable = new Stream.Writable();
|
|
1181
|
+
writable._write = function () { };
|
|
1182
|
+
|
|
1183
|
+
return h.response(writable);
|
|
1184
|
+
};
|
|
1185
|
+
|
|
1186
|
+
const server = Hapi.server({ debug: false });
|
|
1187
|
+
server.route({ method: 'GET', path: '/stream', handler: streamHandler });
|
|
1188
|
+
server.route({ method: 'GET', path: '/writable', handler: writableHandler });
|
|
1189
|
+
|
|
1190
|
+
await server.initialize();
|
|
1191
|
+
|
|
1192
|
+
const log1 = server.events.once({ name: 'request', channels: 'error' });
|
|
1193
|
+
const res1 = await server.inject('/stream');
|
|
1194
|
+
expect(res1.statusCode).to.equal(500);
|
|
1195
|
+
|
|
1196
|
+
const [, event1] = await log1;
|
|
1197
|
+
expect(event1.error).to.be.an.error('Stream must have a readable interface');
|
|
1198
|
+
|
|
1199
|
+
const log2 = server.events.once({ name: 'request', channels: 'error' });
|
|
1200
|
+
const res2 = await server.inject('/writable');
|
|
1201
|
+
expect(res2.statusCode).to.equal(500);
|
|
1202
|
+
|
|
1203
|
+
const [, event2] = await log2;
|
|
1204
|
+
expect(event2.error).to.be.an.error('Stream must have a readable interface');
|
|
1205
|
+
});
|
|
1206
|
+
|
|
1207
|
+
it('errors on an http client stream response', async () => {
|
|
1208
|
+
|
|
1209
|
+
const streamHandler = (request, h) => {
|
|
1210
|
+
|
|
1211
|
+
const req = Http.get(request.server.info.uri);
|
|
1212
|
+
req.abort();
|
|
1213
|
+
return h.response(req);
|
|
1214
|
+
};
|
|
1215
|
+
|
|
1216
|
+
const server = Hapi.server({ debug: false });
|
|
1217
|
+
server.route({ method: 'GET', path: '/stream', handler: streamHandler });
|
|
1218
|
+
|
|
1219
|
+
const log = server.events.once({ name: 'request', channels: 'error' });
|
|
1220
|
+
|
|
1221
|
+
await server.initialize();
|
|
1222
|
+
const res = await server.inject('/stream');
|
|
1223
|
+
expect(res.statusCode).to.equal(500);
|
|
1224
|
+
|
|
1225
|
+
const [, event] = await log;
|
|
1226
|
+
expect(event.error).to.be.an.error('Stream must have a readable interface');
|
|
1227
|
+
});
|
|
1228
|
+
|
|
1229
|
+
it('errors on objectMode stream response', async () => {
|
|
1230
|
+
|
|
1231
|
+
const TestStream = class extends Stream.Readable {
|
|
1232
|
+
|
|
1233
|
+
constructor() {
|
|
1234
|
+
|
|
1235
|
+
super({ objectMode: true });
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
_read(size) {
|
|
1239
|
+
|
|
1240
|
+
if (this.isDone) {
|
|
1241
|
+
return;
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
this.isDone = true;
|
|
1245
|
+
|
|
1246
|
+
this.push({ x: 1 });
|
|
1247
|
+
this.push({ y: 1 });
|
|
1248
|
+
this.push(null);
|
|
1249
|
+
}
|
|
1250
|
+
};
|
|
1251
|
+
|
|
1252
|
+
const handler = (request, h) => {
|
|
1253
|
+
|
|
1254
|
+
return h.response(new TestStream());
|
|
1255
|
+
};
|
|
1256
|
+
|
|
1257
|
+
const server = Hapi.server({ debug: false });
|
|
1258
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
1259
|
+
|
|
1260
|
+
const log = server.events.once({ name: 'request', channels: 'error' });
|
|
1261
|
+
|
|
1262
|
+
const res = await server.inject('/');
|
|
1263
|
+
expect(res.statusCode).to.equal(500);
|
|
1264
|
+
|
|
1265
|
+
const [, event] = await log;
|
|
1266
|
+
expect(event.error).to.be.an.error('Cannot reply with stream in object mode');
|
|
1267
|
+
});
|
|
1268
|
+
});
|
|
1269
|
+
|
|
1270
|
+
describe('_prepare()', () => {
|
|
1271
|
+
|
|
1272
|
+
it('boomifies response prepare error', async () => {
|
|
1273
|
+
|
|
1274
|
+
const server = Hapi.server();
|
|
1275
|
+
|
|
1276
|
+
server.route({
|
|
1277
|
+
method: 'GET',
|
|
1278
|
+
path: '/',
|
|
1279
|
+
handler: (request) => {
|
|
1280
|
+
|
|
1281
|
+
const prepare = () => {
|
|
1282
|
+
|
|
1283
|
+
throw new Error('boom');
|
|
1284
|
+
};
|
|
1285
|
+
|
|
1286
|
+
return request.generateResponse('nothing', { variety: 'special', marshal: null, prepare, close: null });
|
|
1287
|
+
}
|
|
1288
|
+
});
|
|
1289
|
+
|
|
1290
|
+
const res = await server.inject('/');
|
|
1291
|
+
expect(res.statusCode).to.equal(500);
|
|
1292
|
+
});
|
|
1293
|
+
|
|
1294
|
+
it('is only called once for returned responses', async () => {
|
|
1295
|
+
|
|
1296
|
+
let calls = 0;
|
|
1297
|
+
const pre = (request, h) => {
|
|
1298
|
+
|
|
1299
|
+
const prepare = (response) => {
|
|
1300
|
+
|
|
1301
|
+
++calls;
|
|
1302
|
+
return response;
|
|
1303
|
+
};
|
|
1304
|
+
|
|
1305
|
+
return request.generateResponse(null, { prepare });
|
|
1306
|
+
};
|
|
1307
|
+
|
|
1308
|
+
const server = Hapi.server();
|
|
1309
|
+
server.route({
|
|
1310
|
+
method: 'GET',
|
|
1311
|
+
path: '/',
|
|
1312
|
+
options: {
|
|
1313
|
+
pre: [
|
|
1314
|
+
{ method: pre, assign: 'p' }
|
|
1315
|
+
],
|
|
1316
|
+
handler: (request) => request.preResponses.p
|
|
1317
|
+
}
|
|
1318
|
+
});
|
|
1319
|
+
|
|
1320
|
+
const res = await server.inject('/');
|
|
1321
|
+
expect(res.statusCode).to.equal(204);
|
|
1322
|
+
expect(calls).to.equal(1);
|
|
1323
|
+
});
|
|
1324
|
+
});
|
|
1325
|
+
|
|
1326
|
+
describe('_tap()', () => {
|
|
1327
|
+
|
|
1328
|
+
it('peeks into the response stream', async () => {
|
|
1329
|
+
|
|
1330
|
+
const server = Hapi.server();
|
|
1331
|
+
|
|
1332
|
+
let output = '';
|
|
1333
|
+
server.route({
|
|
1334
|
+
method: 'GET',
|
|
1335
|
+
path: '/',
|
|
1336
|
+
handler: (request, h) => {
|
|
1337
|
+
|
|
1338
|
+
const response = h.response('1234567890');
|
|
1339
|
+
|
|
1340
|
+
response.events.on('peek', (chunk, encoding) => {
|
|
1341
|
+
|
|
1342
|
+
output += chunk.toString();
|
|
1343
|
+
});
|
|
1344
|
+
|
|
1345
|
+
response.events.once('finish', () => {
|
|
1346
|
+
|
|
1347
|
+
output += '!';
|
|
1348
|
+
});
|
|
1349
|
+
|
|
1350
|
+
return response;
|
|
1351
|
+
}
|
|
1352
|
+
});
|
|
1353
|
+
|
|
1354
|
+
await server.inject('/');
|
|
1355
|
+
expect(output).to.equal('1234567890!');
|
|
1356
|
+
});
|
|
1357
|
+
|
|
1358
|
+
it('peeks into the response stream (finish only)', async () => {
|
|
1359
|
+
|
|
1360
|
+
const server = Hapi.server();
|
|
1361
|
+
|
|
1362
|
+
let output = false;
|
|
1363
|
+
server.route({
|
|
1364
|
+
method: 'GET',
|
|
1365
|
+
path: '/',
|
|
1366
|
+
handler: (request, h) => {
|
|
1367
|
+
|
|
1368
|
+
const response = h.response('1234567890');
|
|
1369
|
+
|
|
1370
|
+
response.events.once('finish', () => {
|
|
1371
|
+
|
|
1372
|
+
output = true;
|
|
1373
|
+
});
|
|
1374
|
+
|
|
1375
|
+
return response;
|
|
1376
|
+
}
|
|
1377
|
+
});
|
|
1378
|
+
|
|
1379
|
+
await server.inject('/');
|
|
1380
|
+
expect(output).to.be.true();
|
|
1381
|
+
});
|
|
1382
|
+
|
|
1383
|
+
it('peeks into the response stream (empty)', async () => {
|
|
1384
|
+
|
|
1385
|
+
const server = Hapi.server();
|
|
1386
|
+
|
|
1387
|
+
let output = '';
|
|
1388
|
+
server.route({
|
|
1389
|
+
method: 'GET',
|
|
1390
|
+
path: '/',
|
|
1391
|
+
handler: (request, h) => {
|
|
1392
|
+
|
|
1393
|
+
const response = h.response(null);
|
|
1394
|
+
|
|
1395
|
+
response.events.on('peek', (chunk, encoding) => { });
|
|
1396
|
+
|
|
1397
|
+
response.events.once('finish', () => {
|
|
1398
|
+
|
|
1399
|
+
output += '!';
|
|
1400
|
+
});
|
|
1401
|
+
|
|
1402
|
+
return response;
|
|
1403
|
+
}
|
|
1404
|
+
});
|
|
1405
|
+
|
|
1406
|
+
await server.inject('/');
|
|
1407
|
+
expect(output).to.equal('!');
|
|
1408
|
+
});
|
|
1409
|
+
|
|
1410
|
+
it('peeks into the response stream (empty 304)', async () => {
|
|
1411
|
+
|
|
1412
|
+
const server = Hapi.server();
|
|
1413
|
+
|
|
1414
|
+
let output = '';
|
|
1415
|
+
server.route({
|
|
1416
|
+
method: 'GET',
|
|
1417
|
+
path: '/',
|
|
1418
|
+
handler: (request, h) => {
|
|
1419
|
+
|
|
1420
|
+
const response = h.response(null).code(304);
|
|
1421
|
+
|
|
1422
|
+
response.events.on('peek', (chunk, encoding) => { });
|
|
1423
|
+
|
|
1424
|
+
response.events.once('finish', () => {
|
|
1425
|
+
|
|
1426
|
+
output += '!';
|
|
1427
|
+
});
|
|
1428
|
+
|
|
1429
|
+
return response;
|
|
1430
|
+
}
|
|
1431
|
+
});
|
|
1432
|
+
|
|
1433
|
+
await server.inject('/');
|
|
1434
|
+
expect(output).to.equal('!');
|
|
1435
|
+
});
|
|
1436
|
+
});
|
|
1437
|
+
|
|
1438
|
+
describe('_close()', () => {
|
|
1439
|
+
|
|
1440
|
+
it('calls custom close processor', async () => {
|
|
1441
|
+
|
|
1442
|
+
let closed = false;
|
|
1443
|
+
const close = function (response) {
|
|
1444
|
+
|
|
1445
|
+
closed = true;
|
|
1446
|
+
};
|
|
1447
|
+
|
|
1448
|
+
const handler = (request) => {
|
|
1449
|
+
|
|
1450
|
+
return request.generateResponse(null, { close });
|
|
1451
|
+
};
|
|
1452
|
+
|
|
1453
|
+
const server = Hapi.server();
|
|
1454
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
1455
|
+
|
|
1456
|
+
await server.inject('/');
|
|
1457
|
+
expect(closed).to.be.true();
|
|
1458
|
+
});
|
|
1459
|
+
|
|
1460
|
+
it('logs custom close processor error', async () => {
|
|
1461
|
+
|
|
1462
|
+
const close = function (response) {
|
|
1463
|
+
|
|
1464
|
+
throw new Error('oops');
|
|
1465
|
+
};
|
|
1466
|
+
|
|
1467
|
+
const handler = (request) => {
|
|
1468
|
+
|
|
1469
|
+
return request.generateResponse(null, { close });
|
|
1470
|
+
};
|
|
1471
|
+
|
|
1472
|
+
const server = Hapi.server();
|
|
1473
|
+
const log = server.events.once('request');
|
|
1474
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
1475
|
+
|
|
1476
|
+
await server.inject('/');
|
|
1477
|
+
const [, event] = await log;
|
|
1478
|
+
expect(event.tags).to.equal(['response', 'cleanup', 'error']);
|
|
1479
|
+
expect(event.error).to.be.an.error('oops');
|
|
1480
|
+
});
|
|
1481
|
+
});
|
|
1482
|
+
|
|
1483
|
+
describe('Peek', () => {
|
|
1484
|
+
|
|
1485
|
+
it('taps into pass-through stream', async () => {
|
|
1486
|
+
|
|
1487
|
+
// Source
|
|
1488
|
+
|
|
1489
|
+
const Source = class extends Stream.Readable {
|
|
1490
|
+
|
|
1491
|
+
constructor(values) {
|
|
1492
|
+
|
|
1493
|
+
super();
|
|
1494
|
+
this.data = values;
|
|
1495
|
+
this.pos = 0;
|
|
1496
|
+
}
|
|
1497
|
+
|
|
1498
|
+
_read(/* size */) {
|
|
1499
|
+
|
|
1500
|
+
if (this.pos === this.data.length) {
|
|
1501
|
+
this.push(null);
|
|
1502
|
+
return;
|
|
1503
|
+
}
|
|
1504
|
+
|
|
1505
|
+
this.push(this.data[this.pos++]);
|
|
1506
|
+
}
|
|
1507
|
+
};
|
|
1508
|
+
|
|
1509
|
+
// Target
|
|
1510
|
+
|
|
1511
|
+
const Target = class extends Stream.Writable {
|
|
1512
|
+
|
|
1513
|
+
constructor() {
|
|
1514
|
+
|
|
1515
|
+
super();
|
|
1516
|
+
this.data = [];
|
|
1517
|
+
}
|
|
1518
|
+
|
|
1519
|
+
_write(chunk, encoding, callback) {
|
|
1520
|
+
|
|
1521
|
+
this.data.push(chunk.toString());
|
|
1522
|
+
return callback();
|
|
1523
|
+
}
|
|
1524
|
+
};
|
|
1525
|
+
|
|
1526
|
+
// Peek
|
|
1527
|
+
|
|
1528
|
+
const emitter = new Events.EventEmitter();
|
|
1529
|
+
const peek = new Response.Peek(emitter);
|
|
1530
|
+
|
|
1531
|
+
const chunks = ['abcd', 'efgh', 'ijkl', 'mnop', 'qrst', 'uvwx'];
|
|
1532
|
+
const source = new Source(chunks);
|
|
1533
|
+
const target = new Target();
|
|
1534
|
+
|
|
1535
|
+
const seen = [];
|
|
1536
|
+
emitter.on('peek', (update) => {
|
|
1537
|
+
|
|
1538
|
+
const chunk = update[0];
|
|
1539
|
+
seen.push(chunk.toString());
|
|
1540
|
+
});
|
|
1541
|
+
|
|
1542
|
+
const finish = new Promise((resolve) => {
|
|
1543
|
+
|
|
1544
|
+
emitter.once('finish', () => {
|
|
1545
|
+
|
|
1546
|
+
expect(seen).to.equal(chunks);
|
|
1547
|
+
expect(target.data).to.equal(chunks);
|
|
1548
|
+
resolve();
|
|
1549
|
+
});
|
|
1550
|
+
});
|
|
1551
|
+
|
|
1552
|
+
source.pipe(peek).pipe(target);
|
|
1553
|
+
await finish;
|
|
1554
|
+
});
|
|
1555
|
+
});
|
|
1556
|
+
|
|
1557
|
+
describe('Payload', () => {
|
|
1558
|
+
|
|
1559
|
+
it('streams empty string', async () => {
|
|
1560
|
+
|
|
1561
|
+
const server = Hapi.server({ compression: { minBytes: 1 } });
|
|
1562
|
+
server.route({ method: 'GET', path: '/', options: { jsonp: 'callback', handler: () => '' } });
|
|
1563
|
+
|
|
1564
|
+
const res = await server.inject({ url: '/?callback=me', headers: { 'Accept-Encoding': 'gzip' } });
|
|
1565
|
+
expect(res.statusCode).to.equal(200);
|
|
1566
|
+
});
|
|
1567
|
+
});
|
|
1568
|
+
});
|