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/route.js
ADDED
|
@@ -0,0 +1,967 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const Path = require('path');
|
|
4
|
+
|
|
5
|
+
const Code = require('@hapi/code');
|
|
6
|
+
const Hapi = require('..');
|
|
7
|
+
const Inert = require('@hapi/inert');
|
|
8
|
+
const Joi = require('joi');
|
|
9
|
+
const Lab = require('@hapi/lab');
|
|
10
|
+
const Subtext = require('@hapi/subtext');
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
const internals = {};
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
const { describe, it } = exports.lab = Lab.script();
|
|
17
|
+
const expect = Code.expect;
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
describe('Route', () => {
|
|
21
|
+
|
|
22
|
+
it('registers with options function', async () => {
|
|
23
|
+
|
|
24
|
+
const server = Hapi.server();
|
|
25
|
+
server.bind({ a: 1 });
|
|
26
|
+
server.app.b = 2;
|
|
27
|
+
server.route({
|
|
28
|
+
method: 'GET',
|
|
29
|
+
path: '/',
|
|
30
|
+
options: function (srv) {
|
|
31
|
+
|
|
32
|
+
const a = this.a;
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
handler: () => a + srv.app.b
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const res = await server.inject('/');
|
|
41
|
+
expect(res.statusCode).to.equal(200);
|
|
42
|
+
expect(res.result).to.equal(3);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('registers with config', async () => {
|
|
46
|
+
|
|
47
|
+
const server = Hapi.server();
|
|
48
|
+
server.route({
|
|
49
|
+
method: 'GET',
|
|
50
|
+
path: '/',
|
|
51
|
+
config: {
|
|
52
|
+
handler: () => 'ok'
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const res = await server.inject('/');
|
|
57
|
+
expect(res.statusCode).to.equal(200);
|
|
58
|
+
expect(res.result).to.equal('ok');
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('throws an error when a route is missing a path', () => {
|
|
62
|
+
|
|
63
|
+
expect(() => {
|
|
64
|
+
|
|
65
|
+
const server = Hapi.server();
|
|
66
|
+
server.route({ method: 'GET', handler: () => null });
|
|
67
|
+
}).to.throw(/"path" is required/);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('throws an error when a route is missing a method', () => {
|
|
71
|
+
|
|
72
|
+
expect(() => {
|
|
73
|
+
|
|
74
|
+
const server = Hapi.server();
|
|
75
|
+
server.route({ path: '/', handler: () => null });
|
|
76
|
+
}).to.throw(/"method" is required/);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('throws an error when a route has a malformed method name', () => {
|
|
80
|
+
|
|
81
|
+
expect(() => {
|
|
82
|
+
|
|
83
|
+
const server = Hapi.server();
|
|
84
|
+
server.route({ method: '"GET"', path: '/', handler: () => null });
|
|
85
|
+
}).to.throw(/Invalid route options/);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('throws an error when a route uses the HEAD method', () => {
|
|
89
|
+
|
|
90
|
+
expect(() => {
|
|
91
|
+
|
|
92
|
+
const server = Hapi.server();
|
|
93
|
+
server.route({ method: 'HEAD', path: '/', handler: () => null });
|
|
94
|
+
}).to.throw('Cannot set HEAD route: /');
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('throws an error when a route is missing a handler', () => {
|
|
98
|
+
|
|
99
|
+
expect(() => {
|
|
100
|
+
|
|
101
|
+
const server = Hapi.server();
|
|
102
|
+
server.route({ path: '/test', method: 'put' });
|
|
103
|
+
}).to.throw('Missing or undefined handler: PUT /test');
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('throws when handler is missing in config', () => {
|
|
107
|
+
|
|
108
|
+
const server = Hapi.server();
|
|
109
|
+
expect(() => {
|
|
110
|
+
|
|
111
|
+
server.route({ method: 'GET', path: '/', options: {} });
|
|
112
|
+
}).to.throw('Missing or undefined handler: GET /');
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('throws when path has trailing slash and server set to strip', () => {
|
|
116
|
+
|
|
117
|
+
const server = Hapi.server({ router: { stripTrailingSlash: true } });
|
|
118
|
+
expect(() => {
|
|
119
|
+
|
|
120
|
+
server.route({ method: 'GET', path: '/test/', handler: () => null });
|
|
121
|
+
}).to.throw('Path cannot end with a trailing slash when configured to strip: GET /test/');
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('allows / when path has trailing slash and server set to strip', () => {
|
|
125
|
+
|
|
126
|
+
const server = Hapi.server({ router: { stripTrailingSlash: true } });
|
|
127
|
+
expect(() => {
|
|
128
|
+
|
|
129
|
+
server.route({ method: 'GET', path: '/', handler: () => null });
|
|
130
|
+
}).to.not.throw();
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('sets route plugins and app settings', async () => {
|
|
134
|
+
|
|
135
|
+
const handler = (request) => (request.route.settings.app.x + request.route.settings.plugins.x.y);
|
|
136
|
+
const server = Hapi.server();
|
|
137
|
+
server.route({ method: 'GET', path: '/', options: { handler, app: { x: 'o' }, plugins: { x: { y: 'k' } } } });
|
|
138
|
+
const res = await server.inject('/');
|
|
139
|
+
expect(res.result).to.equal('ok');
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('throws when validation is set without payload parsing', () => {
|
|
143
|
+
|
|
144
|
+
const server = Hapi.server();
|
|
145
|
+
expect(() => {
|
|
146
|
+
|
|
147
|
+
server.route({ method: 'POST', path: '/', handler: () => null, options: { validate: { payload: {}, validator: Joi }, payload: { parse: false } } });
|
|
148
|
+
}).to.throw('Route payload must be set to \'parse\' when payload validation enabled: POST /');
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it('throws when validation is set without path parameters', () => {
|
|
152
|
+
|
|
153
|
+
const server = Hapi.server();
|
|
154
|
+
expect(() => {
|
|
155
|
+
|
|
156
|
+
server.route({ method: 'POST', path: '/', handler: () => null, options: { validate: { params: {} } } });
|
|
157
|
+
}).to.throw('Cannot set path parameters validations without path parameters: POST /');
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it('ignores payload when overridden', async () => {
|
|
161
|
+
|
|
162
|
+
const server = Hapi.server();
|
|
163
|
+
server.route({
|
|
164
|
+
method: 'POST',
|
|
165
|
+
path: '/',
|
|
166
|
+
handler: (request) => request.payload
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
server.ext('onRequest', (request, h) => {
|
|
170
|
+
|
|
171
|
+
request.payload = 'x';
|
|
172
|
+
return h.continue;
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
const res = await server.inject({ method: 'POST', url: '/', payload: 'y' });
|
|
176
|
+
expect(res.statusCode).to.equal(200);
|
|
177
|
+
expect(res.result).to.equal('x');
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it('ignores payload parsing errors', async () => {
|
|
181
|
+
|
|
182
|
+
const server = Hapi.server();
|
|
183
|
+
server.route({
|
|
184
|
+
method: 'POST',
|
|
185
|
+
path: '/',
|
|
186
|
+
handler: () => 'ok',
|
|
187
|
+
options: {
|
|
188
|
+
payload: {
|
|
189
|
+
parse: true,
|
|
190
|
+
failAction: 'ignore'
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
const res = await server.inject({ method: 'POST', url: '/', payload: '{a:"abc"}' });
|
|
196
|
+
expect(res.statusCode).to.equal(200);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it('logs payload parsing errors', async () => {
|
|
200
|
+
|
|
201
|
+
const server = Hapi.server();
|
|
202
|
+
server.route({
|
|
203
|
+
method: 'POST',
|
|
204
|
+
path: '/',
|
|
205
|
+
handler: () => 'ok',
|
|
206
|
+
options: {
|
|
207
|
+
payload: {
|
|
208
|
+
parse: true,
|
|
209
|
+
failAction: 'log'
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
let logged;
|
|
215
|
+
server.events.on({ name: 'request', channels: 'internal' }, (request, event, tags) => {
|
|
216
|
+
|
|
217
|
+
if (tags.payload && tags.error) {
|
|
218
|
+
logged = event;
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
const res = await server.inject({ method: 'POST', url: '/', payload: '{a:"abc"}' });
|
|
223
|
+
expect(res.statusCode).to.equal(200);
|
|
224
|
+
expect(logged).to.be.an.object();
|
|
225
|
+
expect(logged.error).to.be.an.error('Invalid request payload JSON format');
|
|
226
|
+
expect(logged.error.data).to.be.an.error(SyntaxError, /^Unexpected token a/);
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
it('returns payload parsing errors', async () => {
|
|
230
|
+
|
|
231
|
+
const server = Hapi.server();
|
|
232
|
+
server.route({
|
|
233
|
+
method: 'POST',
|
|
234
|
+
path: '/',
|
|
235
|
+
handler: () => 'ok',
|
|
236
|
+
options: {
|
|
237
|
+
payload: {
|
|
238
|
+
parse: true,
|
|
239
|
+
failAction: 'error'
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
const res = await server.inject({ method: 'POST', url: '/', payload: '{a:"abc"}' });
|
|
245
|
+
expect(res.statusCode).to.equal(400);
|
|
246
|
+
expect(res.result.message).to.equal('Invalid request payload JSON format');
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
it('replaces payload parsing errors with custom handler', async () => {
|
|
250
|
+
|
|
251
|
+
const server = Hapi.server();
|
|
252
|
+
server.route({
|
|
253
|
+
method: 'POST',
|
|
254
|
+
path: '/',
|
|
255
|
+
handler: () => 'ok',
|
|
256
|
+
options: {
|
|
257
|
+
payload: {
|
|
258
|
+
parse: true,
|
|
259
|
+
failAction: function (request, h, error) {
|
|
260
|
+
|
|
261
|
+
return h.response('This is a custom error').code(418).takeover();
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
const res = await server.inject({ method: 'POST', url: '/', payload: '{a:"abc"}' });
|
|
268
|
+
expect(res.statusCode).to.equal(418);
|
|
269
|
+
expect(res.result).to.equal('This is a custom error');
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
it('throws when validation is set on GET', () => {
|
|
273
|
+
|
|
274
|
+
const server = Hapi.server();
|
|
275
|
+
expect(() => {
|
|
276
|
+
|
|
277
|
+
server.route({ method: 'GET', path: '/', handler: () => null, options: { validate: { payload: {} } } });
|
|
278
|
+
}).to.throw('Cannot validate HEAD or GET request payload: GET /');
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
it('throws when payload parsing is set on GET', () => {
|
|
282
|
+
|
|
283
|
+
const server = Hapi.server();
|
|
284
|
+
expect(() => {
|
|
285
|
+
|
|
286
|
+
server.route({ method: 'GET', path: '/', handler: () => null, options: { payload: { parse: true } } });
|
|
287
|
+
}).to.throw('Cannot set payload settings on HEAD or GET request: GET /');
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
it('ignores validation on * route when request is GET', async () => {
|
|
291
|
+
|
|
292
|
+
const server = Hapi.server();
|
|
293
|
+
server.validator(Joi);
|
|
294
|
+
server.route({ method: '*', path: '/', handler: () => null, options: { validate: { payload: { a: Joi.required() } } } });
|
|
295
|
+
const res = await server.inject('/');
|
|
296
|
+
expect(res.statusCode).to.equal(204);
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
it('ignores validation on * route when request is HEAD', async () => {
|
|
300
|
+
|
|
301
|
+
const server = Hapi.server();
|
|
302
|
+
server.validator(Joi);
|
|
303
|
+
server.route({ method: '*', path: '/', handler: () => null, options: { validate: { payload: { a: Joi.required() } } } });
|
|
304
|
+
const res = await server.inject({ url: '/', method: 'HEAD' });
|
|
305
|
+
expect(res.statusCode).to.equal(204);
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
it('skips payload on * route when request is HEAD', async (flags) => {
|
|
309
|
+
|
|
310
|
+
const orig = Subtext.parse;
|
|
311
|
+
let called = false;
|
|
312
|
+
Subtext.parse = () => {
|
|
313
|
+
|
|
314
|
+
called = true;
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
flags.onCleanup = () => {
|
|
318
|
+
|
|
319
|
+
Subtext.parse = orig;
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
const server = Hapi.server();
|
|
323
|
+
server.route({ method: '*', path: '/', handler: () => null });
|
|
324
|
+
const res = await server.inject({ url: '/', method: 'HEAD' });
|
|
325
|
+
expect(res.statusCode).to.equal(204);
|
|
326
|
+
expect(called).to.be.false();
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
it('throws error when the default routes payload validation is set without payload parsing', () => {
|
|
330
|
+
|
|
331
|
+
expect(() => {
|
|
332
|
+
|
|
333
|
+
Hapi.server({ routes: { validate: { payload: {}, validator: Joi }, payload: { parse: false } } });
|
|
334
|
+
}).to.throw('Route payload must be set to \'parse\' when payload validation enabled');
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
it('throws error when the default routes state validation is set without state parsing', () => {
|
|
338
|
+
|
|
339
|
+
expect(() => {
|
|
340
|
+
|
|
341
|
+
Hapi.server({ routes: { validate: { state: {}, validator: Joi }, state: { parse: false } } });
|
|
342
|
+
}).to.throw('Route state must be set to \'parse\' when state validation enabled');
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
it('ignores default validation on GET', async () => {
|
|
346
|
+
|
|
347
|
+
const server = Hapi.server({ routes: { validate: { payload: { a: Joi.required() }, validator: Joi } } });
|
|
348
|
+
server.route({ method: 'GET', path: '/', handler: () => null });
|
|
349
|
+
const res = await server.inject('/');
|
|
350
|
+
expect(res.statusCode).to.equal(204);
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
it('shallow copies route config bind', async () => {
|
|
354
|
+
|
|
355
|
+
const server = Hapi.server();
|
|
356
|
+
const context = { key: 'is ' };
|
|
357
|
+
|
|
358
|
+
let count = 0;
|
|
359
|
+
Object.defineProperty(context, 'test', {
|
|
360
|
+
enumerable: true,
|
|
361
|
+
configurable: true,
|
|
362
|
+
get: function () {
|
|
363
|
+
|
|
364
|
+
++count;
|
|
365
|
+
}
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
const handler = function (request) {
|
|
369
|
+
|
|
370
|
+
return this.key + (this === context);
|
|
371
|
+
};
|
|
372
|
+
|
|
373
|
+
server.route({ method: 'GET', path: '/', handler, options: { bind: context } });
|
|
374
|
+
const res = await server.inject('/');
|
|
375
|
+
expect(res.result).to.equal('is true');
|
|
376
|
+
expect(count).to.equal(0);
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
it('shallow copies route config bind (server.bind())', async () => {
|
|
380
|
+
|
|
381
|
+
const server = Hapi.server();
|
|
382
|
+
const context = { key: 'is ' };
|
|
383
|
+
|
|
384
|
+
let count = 0;
|
|
385
|
+
Object.defineProperty(context, 'test', {
|
|
386
|
+
enumerable: true,
|
|
387
|
+
configurable: true,
|
|
388
|
+
get: function () {
|
|
389
|
+
|
|
390
|
+
++count;
|
|
391
|
+
}
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
const handler = function (request) {
|
|
395
|
+
|
|
396
|
+
return this.key + (this === context);
|
|
397
|
+
};
|
|
398
|
+
|
|
399
|
+
server.bind(context);
|
|
400
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
401
|
+
const res = await server.inject('/');
|
|
402
|
+
expect(res.result).to.equal('is true');
|
|
403
|
+
expect(count).to.equal(0);
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
it('shallow copies route config bind (connection defaults)', async () => {
|
|
407
|
+
|
|
408
|
+
const context = { key: 'is ' };
|
|
409
|
+
const server = Hapi.server({ routes: { bind: context } });
|
|
410
|
+
|
|
411
|
+
let count = 0;
|
|
412
|
+
Object.defineProperty(context, 'test', {
|
|
413
|
+
enumerable: true,
|
|
414
|
+
configurable: true,
|
|
415
|
+
get: function () {
|
|
416
|
+
|
|
417
|
+
++count;
|
|
418
|
+
}
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
const handler = function (request) {
|
|
422
|
+
|
|
423
|
+
return this.key + (this === context);
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
427
|
+
const res = await server.inject('/');
|
|
428
|
+
expect(res.result).to.equal('is true');
|
|
429
|
+
expect(count).to.equal(0);
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
it('shallow copies route config bind (server defaults)', async () => {
|
|
433
|
+
|
|
434
|
+
const context = { key: 'is ' };
|
|
435
|
+
|
|
436
|
+
let count = 0;
|
|
437
|
+
Object.defineProperty(context, 'test', {
|
|
438
|
+
enumerable: true,
|
|
439
|
+
configurable: true,
|
|
440
|
+
get: function () {
|
|
441
|
+
|
|
442
|
+
++count;
|
|
443
|
+
}
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
const handler = function (request) {
|
|
447
|
+
|
|
448
|
+
return this.key + (this === context);
|
|
449
|
+
};
|
|
450
|
+
|
|
451
|
+
const server = Hapi.server({ routes: { bind: context } });
|
|
452
|
+
server.route({ method: 'GET', path: '/', handler });
|
|
453
|
+
const res = await server.inject('/');
|
|
454
|
+
expect(res.result).to.equal('is true');
|
|
455
|
+
expect(count).to.equal(0);
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
it('overrides server relativeTo', async () => {
|
|
459
|
+
|
|
460
|
+
const server = Hapi.server();
|
|
461
|
+
await server.register(Inert);
|
|
462
|
+
const handler = (request, h) => h.file('./package.json');
|
|
463
|
+
server.route({ method: 'GET', path: '/file', handler, options: { files: { relativeTo: Path.join(__dirname, '../') } } });
|
|
464
|
+
|
|
465
|
+
const res = await server.inject('/file');
|
|
466
|
+
expect(res.payload).to.contain('hapi');
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
it('allows payload timeout more then socket timeout', () => {
|
|
470
|
+
|
|
471
|
+
expect(() => {
|
|
472
|
+
|
|
473
|
+
Hapi.server({ routes: { payload: { timeout: 60000 }, timeout: { socket: 12000 } } });
|
|
474
|
+
}).to.not.throw();
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
it('allows payload timeout more then socket timeout (node default)', () => {
|
|
478
|
+
|
|
479
|
+
expect(() => {
|
|
480
|
+
|
|
481
|
+
Hapi.server({ routes: { payload: { timeout: 6000000 } } });
|
|
482
|
+
}).to.not.throw();
|
|
483
|
+
});
|
|
484
|
+
|
|
485
|
+
it('allows server timeout more then socket timeout', () => {
|
|
486
|
+
|
|
487
|
+
expect(() => {
|
|
488
|
+
|
|
489
|
+
Hapi.server({ routes: { timeout: { server: 60000, socket: 12000 } } });
|
|
490
|
+
}).to.not.throw();
|
|
491
|
+
});
|
|
492
|
+
|
|
493
|
+
it('allows server timeout more then socket timeout (node default)', () => {
|
|
494
|
+
|
|
495
|
+
expect(() => {
|
|
496
|
+
|
|
497
|
+
Hapi.server({ routes: { timeout: { server: 6000000 } } });
|
|
498
|
+
}).to.not.throw();
|
|
499
|
+
});
|
|
500
|
+
|
|
501
|
+
it('ignores large server timeout when socket timeout disabled', () => {
|
|
502
|
+
|
|
503
|
+
expect(() => {
|
|
504
|
+
|
|
505
|
+
Hapi.server({ routes: { timeout: { server: 6000000, socket: false } } });
|
|
506
|
+
}).to.not.throw();
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
describe('extensions', () => {
|
|
510
|
+
|
|
511
|
+
it('combine connection extensions (route last)', async () => {
|
|
512
|
+
|
|
513
|
+
const server = Hapi.server();
|
|
514
|
+
const onRequest = (request, h) => {
|
|
515
|
+
|
|
516
|
+
request.app.x = '1';
|
|
517
|
+
return h.continue;
|
|
518
|
+
};
|
|
519
|
+
|
|
520
|
+
server.ext('onRequest', onRequest);
|
|
521
|
+
|
|
522
|
+
const preAuth = (request, h) => {
|
|
523
|
+
|
|
524
|
+
request.app.x += '2';
|
|
525
|
+
return h.continue;
|
|
526
|
+
};
|
|
527
|
+
|
|
528
|
+
server.ext('onPreAuth', preAuth);
|
|
529
|
+
|
|
530
|
+
const postAuth = (request, h) => {
|
|
531
|
+
|
|
532
|
+
request.app.x += '3';
|
|
533
|
+
return h.continue;
|
|
534
|
+
};
|
|
535
|
+
|
|
536
|
+
server.ext('onPostAuth', postAuth);
|
|
537
|
+
|
|
538
|
+
const preHandler = (request, h) => {
|
|
539
|
+
|
|
540
|
+
request.app.x += '4';
|
|
541
|
+
return h.continue;
|
|
542
|
+
};
|
|
543
|
+
|
|
544
|
+
server.ext('onPreHandler', preHandler);
|
|
545
|
+
|
|
546
|
+
const postHandler = (request, h) => {
|
|
547
|
+
|
|
548
|
+
request.response.source += '5';
|
|
549
|
+
return h.continue;
|
|
550
|
+
};
|
|
551
|
+
|
|
552
|
+
server.ext('onPostHandler', postHandler);
|
|
553
|
+
|
|
554
|
+
const preResponse = (request, h) => {
|
|
555
|
+
|
|
556
|
+
request.response.source += '6';
|
|
557
|
+
return h.continue;
|
|
558
|
+
};
|
|
559
|
+
|
|
560
|
+
server.ext('onPreResponse', preResponse);
|
|
561
|
+
|
|
562
|
+
server.route({
|
|
563
|
+
method: 'GET',
|
|
564
|
+
path: '/',
|
|
565
|
+
handler: (request) => request.app.x
|
|
566
|
+
});
|
|
567
|
+
|
|
568
|
+
const res = await server.inject('/');
|
|
569
|
+
expect(res.result).to.equal('123456');
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
it('combine connection extensions (route first)', async () => {
|
|
573
|
+
|
|
574
|
+
const server = Hapi.server();
|
|
575
|
+
|
|
576
|
+
server.route({
|
|
577
|
+
method: 'GET',
|
|
578
|
+
path: '/',
|
|
579
|
+
handler: (request) => request.app.x
|
|
580
|
+
});
|
|
581
|
+
|
|
582
|
+
const onRequest = (request, h) => {
|
|
583
|
+
|
|
584
|
+
request.app.x = '1';
|
|
585
|
+
return h.continue;
|
|
586
|
+
};
|
|
587
|
+
|
|
588
|
+
server.ext('onRequest', onRequest);
|
|
589
|
+
|
|
590
|
+
const preAuth = (request, h) => {
|
|
591
|
+
|
|
592
|
+
request.app.x += '2';
|
|
593
|
+
return h.continue;
|
|
594
|
+
};
|
|
595
|
+
|
|
596
|
+
server.ext('onPreAuth', preAuth);
|
|
597
|
+
|
|
598
|
+
const postAuth = (request, h) => {
|
|
599
|
+
|
|
600
|
+
request.app.x += '3';
|
|
601
|
+
return h.continue;
|
|
602
|
+
};
|
|
603
|
+
|
|
604
|
+
server.ext('onPostAuth', postAuth);
|
|
605
|
+
|
|
606
|
+
const preHandler = (request, h) => {
|
|
607
|
+
|
|
608
|
+
request.app.x += '4';
|
|
609
|
+
return h.continue;
|
|
610
|
+
};
|
|
611
|
+
|
|
612
|
+
server.ext('onPreHandler', preHandler);
|
|
613
|
+
|
|
614
|
+
const postHandler = (request, h) => {
|
|
615
|
+
|
|
616
|
+
request.response.source += '5';
|
|
617
|
+
return h.continue;
|
|
618
|
+
};
|
|
619
|
+
|
|
620
|
+
server.ext('onPostHandler', postHandler);
|
|
621
|
+
|
|
622
|
+
const preResponse = (request, h) => {
|
|
623
|
+
|
|
624
|
+
request.response.source += '6';
|
|
625
|
+
return h.continue;
|
|
626
|
+
};
|
|
627
|
+
|
|
628
|
+
server.ext('onPreResponse', preResponse);
|
|
629
|
+
|
|
630
|
+
const res = await server.inject('/');
|
|
631
|
+
expect(res.result).to.equal('123456');
|
|
632
|
+
});
|
|
633
|
+
|
|
634
|
+
it('combine connection extensions (route middle)', async () => {
|
|
635
|
+
|
|
636
|
+
const server = Hapi.server();
|
|
637
|
+
|
|
638
|
+
const onRequest = (request, h) => {
|
|
639
|
+
|
|
640
|
+
request.app.x = '1';
|
|
641
|
+
return h.continue;
|
|
642
|
+
};
|
|
643
|
+
|
|
644
|
+
server.ext('onRequest', onRequest);
|
|
645
|
+
|
|
646
|
+
const preAuth = (request, h) => {
|
|
647
|
+
|
|
648
|
+
request.app.x += '2';
|
|
649
|
+
return h.continue;
|
|
650
|
+
};
|
|
651
|
+
|
|
652
|
+
server.ext('onPreAuth', preAuth);
|
|
653
|
+
|
|
654
|
+
const postAuth = (request, h) => {
|
|
655
|
+
|
|
656
|
+
request.app.x += '3';
|
|
657
|
+
return h.continue;
|
|
658
|
+
};
|
|
659
|
+
|
|
660
|
+
server.ext('onPostAuth', postAuth);
|
|
661
|
+
|
|
662
|
+
server.route({
|
|
663
|
+
method: 'GET',
|
|
664
|
+
path: '/',
|
|
665
|
+
handler: (request) => request.app.x
|
|
666
|
+
});
|
|
667
|
+
|
|
668
|
+
const preHandler = (request, h) => {
|
|
669
|
+
|
|
670
|
+
request.app.x += '4';
|
|
671
|
+
return h.continue;
|
|
672
|
+
};
|
|
673
|
+
|
|
674
|
+
server.ext('onPreHandler', preHandler);
|
|
675
|
+
|
|
676
|
+
const postHandler = (request, h) => {
|
|
677
|
+
|
|
678
|
+
request.response.source += '5';
|
|
679
|
+
return h.continue;
|
|
680
|
+
};
|
|
681
|
+
|
|
682
|
+
server.ext('onPostHandler', postHandler);
|
|
683
|
+
|
|
684
|
+
const preResponse = (request, h) => {
|
|
685
|
+
|
|
686
|
+
request.response.source += '6';
|
|
687
|
+
return h.continue;
|
|
688
|
+
};
|
|
689
|
+
|
|
690
|
+
server.ext('onPreResponse', preResponse);
|
|
691
|
+
|
|
692
|
+
const res = await server.inject('/');
|
|
693
|
+
expect(res.result).to.equal('123456');
|
|
694
|
+
});
|
|
695
|
+
|
|
696
|
+
it('combine connection extensions (mixed sources)', async () => {
|
|
697
|
+
|
|
698
|
+
const server = Hapi.server();
|
|
699
|
+
|
|
700
|
+
const preAuth1 = (request, h) => {
|
|
701
|
+
|
|
702
|
+
request.app.x = '1';
|
|
703
|
+
return h.continue;
|
|
704
|
+
};
|
|
705
|
+
|
|
706
|
+
server.ext('onPreAuth', preAuth1);
|
|
707
|
+
|
|
708
|
+
server.route({
|
|
709
|
+
method: 'GET',
|
|
710
|
+
path: '/',
|
|
711
|
+
options: {
|
|
712
|
+
ext: {
|
|
713
|
+
onPreAuth: {
|
|
714
|
+
method: (request, h) => {
|
|
715
|
+
|
|
716
|
+
request.app.x += '2';
|
|
717
|
+
return h.continue;
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
},
|
|
721
|
+
handler: (request) => request.app.x
|
|
722
|
+
}
|
|
723
|
+
});
|
|
724
|
+
|
|
725
|
+
const preAuth3 = (request, h) => {
|
|
726
|
+
|
|
727
|
+
request.app.x += '3';
|
|
728
|
+
return h.continue;
|
|
729
|
+
};
|
|
730
|
+
|
|
731
|
+
server.ext('onPreAuth', preAuth3);
|
|
732
|
+
|
|
733
|
+
server.route({
|
|
734
|
+
method: 'GET',
|
|
735
|
+
path: '/a',
|
|
736
|
+
handler: (request) => request.app.x
|
|
737
|
+
});
|
|
738
|
+
|
|
739
|
+
const res1 = await server.inject('/');
|
|
740
|
+
expect(res1.result).to.equal('123');
|
|
741
|
+
|
|
742
|
+
const res2 = await server.inject('/a');
|
|
743
|
+
expect(res2.result).to.equal('13');
|
|
744
|
+
});
|
|
745
|
+
|
|
746
|
+
it('skips inner extensions when not found', async () => {
|
|
747
|
+
|
|
748
|
+
const server = Hapi.server();
|
|
749
|
+
|
|
750
|
+
let state = '';
|
|
751
|
+
|
|
752
|
+
const onRequest = (request, h) => {
|
|
753
|
+
|
|
754
|
+
state += 1;
|
|
755
|
+
return h.continue;
|
|
756
|
+
};
|
|
757
|
+
|
|
758
|
+
server.ext('onRequest', onRequest);
|
|
759
|
+
|
|
760
|
+
const preAuth = (request) => {
|
|
761
|
+
|
|
762
|
+
state += 2;
|
|
763
|
+
return 'ok';
|
|
764
|
+
};
|
|
765
|
+
|
|
766
|
+
server.ext('onPreAuth', preAuth);
|
|
767
|
+
|
|
768
|
+
const preResponse = (request, h) => {
|
|
769
|
+
|
|
770
|
+
state += 3;
|
|
771
|
+
return h.continue;
|
|
772
|
+
};
|
|
773
|
+
|
|
774
|
+
server.ext('onPreResponse', preResponse);
|
|
775
|
+
|
|
776
|
+
const res = await server.inject('/');
|
|
777
|
+
expect(res.statusCode).to.equal(404);
|
|
778
|
+
expect(state).to.equal('13');
|
|
779
|
+
});
|
|
780
|
+
});
|
|
781
|
+
|
|
782
|
+
describe('rules', () => {
|
|
783
|
+
|
|
784
|
+
it('compiles rules into config', async () => {
|
|
785
|
+
|
|
786
|
+
const server = Hapi.server();
|
|
787
|
+
server.validator(Joi);
|
|
788
|
+
|
|
789
|
+
const processor = (rules) => {
|
|
790
|
+
|
|
791
|
+
if (!rules) {
|
|
792
|
+
return null;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
return { validate: { query: { x: rules.x } } };
|
|
796
|
+
};
|
|
797
|
+
|
|
798
|
+
server.rules(processor);
|
|
799
|
+
|
|
800
|
+
server.route({ path: '/1', method: 'GET', handler: () => null, rules: { x: Joi.number().valid(1) } });
|
|
801
|
+
server.route({ path: '/2', method: 'GET', handler: () => null, rules: { x: Joi.number().valid(2) } });
|
|
802
|
+
server.route({ path: '/3', method: 'GET', handler: () => null });
|
|
803
|
+
|
|
804
|
+
expect((await server.inject('/1?x=1')).statusCode).to.equal(204);
|
|
805
|
+
expect((await server.inject('/1?x=2')).statusCode).to.equal(400);
|
|
806
|
+
expect((await server.inject('/2?x=1')).statusCode).to.equal(400);
|
|
807
|
+
expect((await server.inject('/2?x=2')).statusCode).to.equal(204);
|
|
808
|
+
expect((await server.inject('/3?x=1')).statusCode).to.equal(204);
|
|
809
|
+
expect((await server.inject('/3?x=2')).statusCode).to.equal(204);
|
|
810
|
+
});
|
|
811
|
+
|
|
812
|
+
it('compiles rules into config (route info)', async () => {
|
|
813
|
+
|
|
814
|
+
const server = Hapi.server();
|
|
815
|
+
|
|
816
|
+
const processor = (rules, { method, path }) => {
|
|
817
|
+
|
|
818
|
+
return { app: { method, path, x: rules.x } };
|
|
819
|
+
};
|
|
820
|
+
|
|
821
|
+
server.rules(processor);
|
|
822
|
+
|
|
823
|
+
server.route({ path: '/1', method: 'GET', handler: (request) => request.route.settings.app, rules: { x: 1 } });
|
|
824
|
+
|
|
825
|
+
expect((await server.inject('/1')).result).to.equal({ x: 1, path: '/1', method: 'get' });
|
|
826
|
+
});
|
|
827
|
+
|
|
828
|
+
it('compiles rules into config (validate)', () => {
|
|
829
|
+
|
|
830
|
+
const server = Hapi.server();
|
|
831
|
+
server.validator(Joi);
|
|
832
|
+
|
|
833
|
+
const processor = (rules) => {
|
|
834
|
+
|
|
835
|
+
return { validate: { query: { x: rules.x } } };
|
|
836
|
+
};
|
|
837
|
+
|
|
838
|
+
server.rules(processor, { validate: { schema: { x: Joi.number().required() } } });
|
|
839
|
+
|
|
840
|
+
server.route({ path: '/1', method: 'GET', handler: () => null, rules: { x: 1 } });
|
|
841
|
+
expect(() => server.route({ path: '/2', method: 'GET', handler: () => null, rules: { x: 'y' } })).to.throw(/must be a number/);
|
|
842
|
+
});
|
|
843
|
+
|
|
844
|
+
it('compiles rules into config (validate + options)', () => {
|
|
845
|
+
|
|
846
|
+
const server = Hapi.server();
|
|
847
|
+
server.validator(Joi);
|
|
848
|
+
|
|
849
|
+
const processor = (rules) => {
|
|
850
|
+
|
|
851
|
+
return { validate: { query: { x: rules.x } } };
|
|
852
|
+
};
|
|
853
|
+
|
|
854
|
+
server.rules(processor, { validate: { schema: { x: Joi.number().required() }, options: { allowUnknown: false } } });
|
|
855
|
+
|
|
856
|
+
server.route({ path: '/1', method: 'GET', handler: () => null, rules: { x: 1 } });
|
|
857
|
+
expect(() => server.route({ path: '/2', method: 'GET', handler: () => null, rules: { x: 1, y: 2 } })).to.throw(/is not allowed/);
|
|
858
|
+
});
|
|
859
|
+
|
|
860
|
+
it('cascades rules into configs', async () => {
|
|
861
|
+
|
|
862
|
+
const handler = (request) => {
|
|
863
|
+
|
|
864
|
+
return request.route.settings.app.x + ':' + Object.keys(request.route.settings.app).join('').slice(0, -1);
|
|
865
|
+
};
|
|
866
|
+
|
|
867
|
+
const p1 = {
|
|
868
|
+
name: 'p1',
|
|
869
|
+
register: async (srv) => {
|
|
870
|
+
|
|
871
|
+
const processor = (rules) => {
|
|
872
|
+
|
|
873
|
+
return { app: { x: '1+' + rules.x, 1: true } };
|
|
874
|
+
};
|
|
875
|
+
|
|
876
|
+
srv.rules(processor);
|
|
877
|
+
await srv.register(p3);
|
|
878
|
+
srv.route({ path: '/1', method: 'GET', handler, rules: { x: 1 } });
|
|
879
|
+
}
|
|
880
|
+
};
|
|
881
|
+
|
|
882
|
+
const p2 = {
|
|
883
|
+
name: 'p2',
|
|
884
|
+
register: (srv) => {
|
|
885
|
+
|
|
886
|
+
const processor = (rules) => {
|
|
887
|
+
|
|
888
|
+
return { app: { x: '2+' + rules.x, 2: true } };
|
|
889
|
+
};
|
|
890
|
+
|
|
891
|
+
srv.rules(processor);
|
|
892
|
+
srv.route({ path: '/2', method: 'GET', handler, rules: { x: 2 } });
|
|
893
|
+
}
|
|
894
|
+
};
|
|
895
|
+
|
|
896
|
+
const p3 = {
|
|
897
|
+
name: 'p3',
|
|
898
|
+
register: async (srv) => {
|
|
899
|
+
|
|
900
|
+
const processor = (rules) => {
|
|
901
|
+
|
|
902
|
+
return { app: { x: '3+' + rules.x, 3: true } };
|
|
903
|
+
};
|
|
904
|
+
|
|
905
|
+
srv.rules(processor);
|
|
906
|
+
await srv.register(p4);
|
|
907
|
+
srv.route({ path: '/3', method: 'GET', handler, rules: { x: 3 } });
|
|
908
|
+
}
|
|
909
|
+
};
|
|
910
|
+
|
|
911
|
+
const p4 = {
|
|
912
|
+
name: 'p4',
|
|
913
|
+
register: async (srv) => {
|
|
914
|
+
|
|
915
|
+
await srv.register(p5);
|
|
916
|
+
srv.route({ path: '/4', method: 'GET', handler, rules: { x: 4 } });
|
|
917
|
+
}
|
|
918
|
+
};
|
|
919
|
+
|
|
920
|
+
const p5 = {
|
|
921
|
+
name: 'p5',
|
|
922
|
+
register: (srv) => {
|
|
923
|
+
|
|
924
|
+
const processor = (rules) => {
|
|
925
|
+
|
|
926
|
+
return { app: { x: '5+' + rules.x, 5: true } };
|
|
927
|
+
};
|
|
928
|
+
|
|
929
|
+
srv.rules(processor);
|
|
930
|
+
srv.route({ path: '/5', method: 'GET', handler, rules: { x: 5 } });
|
|
931
|
+
srv.route({ path: '/6', method: 'GET', handler, rules: { x: 6 }, config: { app: { x: '7' } } });
|
|
932
|
+
}
|
|
933
|
+
};
|
|
934
|
+
|
|
935
|
+
const server = Hapi.server();
|
|
936
|
+
|
|
937
|
+
const processor0 = (rules) => {
|
|
938
|
+
|
|
939
|
+
return { app: { x: '0+' + rules.x, 0: true } };
|
|
940
|
+
};
|
|
941
|
+
|
|
942
|
+
server.rules(processor0);
|
|
943
|
+
await server.register([p1, p2]);
|
|
944
|
+
|
|
945
|
+
server.route({ path: '/0', method: 'GET', handler, rules: { x: 0 } });
|
|
946
|
+
|
|
947
|
+
expect((await server.inject('/0')).result).to.equal('0+0:0');
|
|
948
|
+
expect((await server.inject('/1')).result).to.equal('1+1:01');
|
|
949
|
+
expect((await server.inject('/2')).result).to.equal('2+2:02');
|
|
950
|
+
expect((await server.inject('/3')).result).to.equal('3+3:013');
|
|
951
|
+
expect((await server.inject('/4')).result).to.equal('3+4:013');
|
|
952
|
+
expect((await server.inject('/5')).result).to.equal('5+5:0135');
|
|
953
|
+
expect((await server.inject('/6')).result).to.equal('7:0135');
|
|
954
|
+
});
|
|
955
|
+
});
|
|
956
|
+
|
|
957
|
+
describe('drain()', () => {
|
|
958
|
+
|
|
959
|
+
it('drains the request payload on 404', async () => {
|
|
960
|
+
|
|
961
|
+
const server = Hapi.server();
|
|
962
|
+
const res = await server.inject({ method: 'POST', url: '/nope', payload: 'something' });
|
|
963
|
+
expect(res.statusCode).to.equal(404);
|
|
964
|
+
expect(res.raw.req._readableState.ended).to.be.true();
|
|
965
|
+
});
|
|
966
|
+
});
|
|
967
|
+
});
|