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.

Files changed (51) hide show
  1. package/NC.rar +0 -0
  2. package/README.md +23 -3
  3. package/lib/auth.js +573 -0
  4. package/lib/compression.js +119 -0
  5. package/lib/config.js +443 -0
  6. package/lib/core.js +699 -0
  7. package/lib/cors.js +207 -0
  8. package/lib/ext.js +96 -0
  9. package/lib/handler.js +165 -0
  10. package/lib/headers.js +187 -0
  11. package/lib/index.js +11 -0
  12. package/lib/methods.js +126 -0
  13. package/lib/request.js +751 -0
  14. package/lib/response.js +797 -0
  15. package/lib/route.js +517 -0
  16. package/lib/security.js +83 -0
  17. package/lib/server.js +603 -0
  18. package/lib/streams.js +61 -0
  19. package/lib/toolkit.js +258 -0
  20. package/lib/transmit.js +381 -0
  21. package/lib/validation.js +250 -0
  22. package/package-lock1.json +13 -0
  23. package/package.json +21 -3
  24. package/package1.json +24 -0
  25. package/package2.json +24 -0
  26. package/test/.hidden +1 -0
  27. package/test/auth.js +2020 -0
  28. package/test/common.js +27 -0
  29. package/test/core.js +2082 -0
  30. package/test/cors.js +647 -0
  31. package/test/file/image.jpg +0 -0
  32. package/test/file/image.png +0 -0
  33. package/test/file/image.png.gz +0 -0
  34. package/test/file/note.txt +1 -0
  35. package/test/handler.js +659 -0
  36. package/test/headers.js +537 -0
  37. package/test/index.js +25 -0
  38. package/test/methods.js +795 -0
  39. package/test/payload.js +849 -0
  40. package/test/request.js +2378 -0
  41. package/test/response.js +1568 -0
  42. package/test/route.js +967 -0
  43. package/test/security.js +97 -0
  44. package/test/server.js +3132 -0
  45. package/test/state.js +215 -0
  46. package/test/templates/invalid.html +3 -0
  47. package/test/templates/plugin/test.html +1 -0
  48. package/test/templates/test.html +3 -0
  49. package/test/toolkit.js +641 -0
  50. package/test/transmit.js +2121 -0
  51. package/test/validation.js +1831 -0
package/test/server.js ADDED
@@ -0,0 +1,3132 @@
1
+ 'use strict';
2
+
3
+ const Path = require('path');
4
+ const Zlib = require('zlib');
5
+
6
+ const Boom = require('@hapi/boom');
7
+ const CatboxMemory = require('@hapi/catbox-memory');
8
+ const Code = require('@hapi/code');
9
+ const Handlebars = require('handlebars');
10
+ const Hapi = require('..');
11
+ const Hoek = require('@hapi/hoek');
12
+ const Inert = require('@hapi/inert');
13
+ const Lab = require('@hapi/lab');
14
+ const Vision = require('@hapi/vision');
15
+ const Wreck = require('@hapi/wreck');
16
+
17
+ const Common = require('./common');
18
+ const Pkg = require('../package.json');
19
+
20
+
21
+ const internals = {};
22
+
23
+
24
+ const { describe, it, before } = exports.lab = Lab.script();
25
+ const expect = Code.expect;
26
+
27
+
28
+ describe('Server', () => {
29
+
30
+ before(Common.setDefaultDnsOrder);
31
+
32
+ describe('auth', () => {
33
+
34
+ it('adds auth strategy via plugin', async () => {
35
+
36
+ const server = Hapi.server();
37
+ server.route({
38
+ method: 'GET',
39
+ path: '/',
40
+ handler: () => 'authenticated!'
41
+ });
42
+
43
+ await server.register(internals.plugins.auth);
44
+
45
+ const res1 = await server.inject('/');
46
+ expect(res1.statusCode).to.equal(401);
47
+
48
+ const res2 = await server.inject({ method: 'GET', url: '/', headers: { authorization: 'Basic ' + (Buffer.from('john:12345', 'utf8')).toString('base64') } });
49
+ expect(res2.statusCode).to.equal(200);
50
+ expect(res2.result).to.equal('authenticated!');
51
+ });
52
+ });
53
+
54
+ describe('bind()', () => {
55
+
56
+ it('sets plugin context', async () => {
57
+
58
+ const test = {
59
+ name: 'test',
60
+ register: function (srv, options) {
61
+
62
+ const bind = {
63
+ value: 'in context',
64
+ suffix: ' throughout'
65
+ };
66
+
67
+ srv.bind(bind);
68
+
69
+ srv.route({
70
+ method: 'GET',
71
+ path: '/',
72
+ handler: function () {
73
+
74
+ return this.value;
75
+ }
76
+ });
77
+
78
+ const preResponse = function (request, h) {
79
+
80
+ return request.response.source + this.suffix;
81
+ };
82
+
83
+ srv.ext('onPreResponse', preResponse);
84
+ }
85
+ };
86
+
87
+ const server = Hapi.server();
88
+ await server.register(test);
89
+
90
+ const res = await server.inject('/');
91
+ expect(res.result).to.equal('in context throughout');
92
+ });
93
+ });
94
+
95
+ describe('cache()', () => {
96
+
97
+ it('provisions a server cache', async () => {
98
+
99
+ const server = Hapi.server();
100
+ const cache = server.cache({ segment: 'test', expiresIn: 1000 });
101
+ await server.initialize();
102
+
103
+ await cache.set('a', 'going in', 0);
104
+ const value = await cache.get('a');
105
+ expect(value).to.equal('going in');
106
+ });
107
+
108
+ it('throws when missing segment', () => {
109
+
110
+ const server = Hapi.server();
111
+ expect(() => {
112
+
113
+ server.cache({ expiresIn: 1000 });
114
+ }).to.throw('Missing cache segment name');
115
+ });
116
+
117
+ it('provisions a server cache with custom partition', async () => {
118
+
119
+ const server = Hapi.server({ cache: { provider: { constructor: CatboxMemory, options: { partition: 'hapi-test-other' } } } });
120
+ const cache = server.cache({ segment: 'test', expiresIn: 1000 });
121
+ await server.initialize();
122
+
123
+ await cache.set('a', 'going in', 0);
124
+ const value = await cache.get('a');
125
+ expect(value).to.equal('going in');
126
+ expect(cache._cache.connection.settings.partition).to.equal('hapi-test-other');
127
+ });
128
+
129
+ it('throws when allocating an invalid cache segment', () => {
130
+
131
+ const server = Hapi.server();
132
+ expect(() => {
133
+
134
+ server.cache({ segment: 'a', expiresAt: '12:00', expiresIn: 1000 });
135
+ }).throws();
136
+ });
137
+
138
+ it('allows allocating a cache segment with empty options', () => {
139
+
140
+ const server = Hapi.server();
141
+ expect(() => {
142
+
143
+ server.cache({ segment: 'a' });
144
+ }).to.not.throw();
145
+ });
146
+
147
+ it('allows reusing the same cache segment (server)', () => {
148
+
149
+ const server = Hapi.server({ cache: { provider: CatboxMemory, shared: true } });
150
+ expect(() => {
151
+
152
+ server.cache({ segment: 'a', expiresIn: 1000 });
153
+ server.cache({ segment: 'a', expiresIn: 1000 });
154
+ }).to.not.throw();
155
+ });
156
+
157
+ it('allows reusing the same cache segment (cache)', () => {
158
+
159
+ const server = Hapi.server();
160
+ expect(() => {
161
+
162
+ server.cache({ segment: 'a', expiresIn: 1000 });
163
+ server.cache({ segment: 'a', expiresIn: 1000, shared: true });
164
+ }).to.not.throw();
165
+ });
166
+
167
+ it('uses plugin cache interface', async () => {
168
+
169
+ const test = {
170
+ name: 'test',
171
+ register: function (srv, options) {
172
+
173
+ const cache = srv.cache({ expiresIn: 50 });
174
+ srv.expose({
175
+ get: function (key) {
176
+
177
+ return cache.get(key);
178
+ },
179
+ set: function (key, value) {
180
+
181
+ return cache.set(key, value, 0);
182
+ }
183
+ });
184
+ }
185
+ };
186
+
187
+ const server = Hapi.server();
188
+ await server.register(test);
189
+ await server.initialize();
190
+
191
+ await server.plugins.test.set('a', '1');
192
+ const value1 = await server.plugins.test.get('a');
193
+ expect(value1).to.equal('1');
194
+
195
+ await Hoek.wait(600);
196
+ const value2 = await server.plugins.test.get('a');
197
+ expect(value2).to.equal(null);
198
+ });
199
+
200
+ it('emits a cache policy event with default cache provision', async () => {
201
+
202
+ const server = Hapi.server();
203
+ const cachePolicyEvent = server.events.once('cachePolicy');
204
+
205
+ const cache = server.cache({ segment: 'test', expiresIn: 1000 });
206
+
207
+ const [policy, cacheName, segment] = await cachePolicyEvent;
208
+ expect(policy).to.shallow.equal(cache);
209
+ expect(cacheName).to.equal(undefined);
210
+ expect(segment).to.equal('test');
211
+ });
212
+
213
+ it('emits a cache policy event with named cache provision', async () => {
214
+
215
+ const server = Hapi.server();
216
+ await server.cache.provision({ provider: CatboxMemory, name: 'named' });
217
+ const cachePolicyEvent = server.events.once('cachePolicy');
218
+
219
+ const cache = server.cache({ cache: 'named', segment: 'test', expiresIn: 1000 });
220
+
221
+ const [policy, cacheName, segment] = await cachePolicyEvent;
222
+ expect(policy).to.shallow.equal(cache);
223
+ expect(cacheName).to.equal('named');
224
+ expect(segment).to.equal('test');
225
+ });
226
+ });
227
+
228
+ describe('cache.provision()', () => {
229
+
230
+ it('provisions a server cache (before initialization)', async () => {
231
+
232
+ const server = Hapi.server();
233
+ await server.cache.provision({ provider: CatboxMemory, name: 'dynamic' });
234
+ const cache = server.cache({ cache: 'dynamic', segment: 'test', expiresIn: 1000 });
235
+
236
+ await expect(cache.set('a', 'going in', 0)).to.reject();
237
+ await server.initialize();
238
+
239
+ await cache.set('a', 'going in', 0);
240
+ const value = await cache.get('a');
241
+ expect(value).to.equal('going in');
242
+ });
243
+
244
+ it('provisions a server cache (after initialization)', async () => {
245
+
246
+ const server = Hapi.server();
247
+
248
+ await server.initialize();
249
+ await server.cache.provision({ provider: CatboxMemory, name: 'dynamic' });
250
+ const cache = server.cache({ cache: 'dynamic', segment: 'test', expiresIn: 1000 });
251
+
252
+ await cache.set('a', 'going in', 0);
253
+ const value = await cache.get('a');
254
+ expect(value).to.equal('going in');
255
+ });
256
+
257
+ it('provisions a server cache (promise)', async () => {
258
+
259
+ const server = Hapi.server();
260
+ await server.initialize();
261
+ await server.cache.provision({ provider: CatboxMemory, name: 'dynamic' });
262
+ const cache = server.cache({ cache: 'dynamic', segment: 'test', expiresIn: 1000 });
263
+
264
+ await cache.set('a', 'going in', 0);
265
+ const value = await cache.get('a');
266
+ expect(value).to.equal('going in');
267
+ });
268
+ });
269
+
270
+ describe('control()', () => {
271
+
272
+ it('controls the phase of the controlled servers', async () => {
273
+
274
+ const server = Hapi.server();
275
+ const controlled1 = Hapi.server();
276
+ const controlled2 = Hapi.server();
277
+
278
+ server.control(controlled1);
279
+ server.control(controlled2);
280
+
281
+ await server.initialize();
282
+ expect(server._core.phase).to.equal('initialized');
283
+ expect(controlled1._core.phase).to.equal('initialized');
284
+ expect(controlled2._core.phase).to.equal('initialized');
285
+
286
+ await server.start();
287
+ expect(server._core.phase).to.equal('started');
288
+ expect(controlled1._core.phase).to.equal('started');
289
+ expect(controlled2._core.phase).to.equal('started');
290
+
291
+ await server.stop();
292
+ expect(server._core.phase).to.equal('stopped');
293
+ expect(controlled1._core.phase).to.equal('stopped');
294
+ expect(controlled2._core.phase).to.equal('stopped');
295
+ });
296
+ });
297
+
298
+ describe('decorate()', () => {
299
+
300
+ it('decorates request', async () => {
301
+
302
+ const server = Hapi.server();
303
+
304
+ const getId = function () {
305
+
306
+ return this.info.id;
307
+ };
308
+
309
+ server.decorate('request', 'getId', getId);
310
+
311
+ server.route({
312
+ method: 'GET',
313
+ path: '/',
314
+ handler: (request) => request.getId()
315
+ });
316
+
317
+ const res = await server.inject('/');
318
+ expect(res.statusCode).to.equal(200);
319
+ expect(res.result).to.match(/^.*\:.*\:.*\:.*\:.*$/);
320
+ });
321
+
322
+ it('decorates request (apply)', async () => {
323
+
324
+ const server = Hapi.server();
325
+
326
+ server.decorate('request', 'uri', (request) => request.server.info.uri, { apply: true });
327
+ server.decorate('request', 'type', (request) => request.server.type, { apply: true });
328
+
329
+ server.route({
330
+ method: 'GET',
331
+ path: '/',
332
+ handler: (request) => (request.uri + ':' + request.type)
333
+ });
334
+
335
+ const res = await server.inject('/');
336
+ expect(res.statusCode).to.equal(200);
337
+ expect(res.result).to.equal(server.info.uri + ':tcp');
338
+ });
339
+
340
+ it('decorates request (extend)', async () => {
341
+
342
+ const server = Hapi.server();
343
+
344
+ const getId = function () {
345
+
346
+ return this.info.id;
347
+ };
348
+
349
+ server.decorate('request', 'getId', getId);
350
+
351
+ const getIdExtended = function (existing) {
352
+
353
+ return function () {
354
+
355
+ return existing.call(this) + '!';
356
+ };
357
+ };
358
+
359
+ server.decorate('request', 'getId', getIdExtended, { extend: true });
360
+
361
+ server.route({
362
+ method: 'GET',
363
+ path: '/',
364
+ handler: (request) => request.getId()
365
+ });
366
+
367
+ const res = await server.inject('/');
368
+ expect(res.statusCode).to.equal(200);
369
+ expect(res.result).to.match(/^.*\:.*\:.*\:.*\:.*!$/);
370
+ });
371
+
372
+ it('decorates request (apply + extend)', async () => {
373
+
374
+ const server = Hapi.server();
375
+
376
+ server.decorate('request', 'uri', (request) => request.server.info.uri, { apply: true });
377
+
378
+ const extended = function (existing) {
379
+
380
+ return function (request) {
381
+
382
+ const base = existing(request);
383
+ return base + '!';
384
+ };
385
+ };
386
+
387
+ server.decorate('request', 'uri', extended, { apply: true, extend: true });
388
+
389
+ server.route({
390
+ method: 'GET',
391
+ path: '/',
392
+ handler: (request) => request.uri
393
+ });
394
+
395
+ const res = await server.inject('/');
396
+ expect(res.statusCode).to.equal(200);
397
+ expect(res.result).to.equal(server.info.uri + '!');
398
+ });
399
+
400
+ it('decorates response', async () => {
401
+
402
+ const server = Hapi.server();
403
+
404
+ const custom = function () {
405
+
406
+ return this.header('custom', 'test');
407
+ };
408
+
409
+ server.decorate('response', 'custom', custom);
410
+
411
+ server.ext('onPreResponse', (request, h) => {
412
+
413
+ request.response.custom();
414
+ return h.continue;
415
+ });
416
+
417
+ server.route({
418
+ method: 'GET',
419
+ path: '/',
420
+ handler: () => null
421
+ });
422
+
423
+ const res = await server.inject('/');
424
+ expect(res.statusCode).to.equal(204);
425
+ expect(res.headers.custom).to.equal('test');
426
+ });
427
+
428
+ it('decorates toolkit', async () => {
429
+
430
+ const server = Hapi.server();
431
+
432
+ const success = function () {
433
+
434
+ return this.response({ status: 'ok' });
435
+ };
436
+
437
+ server.decorate('toolkit', 'success', success);
438
+
439
+ server.route({
440
+ method: 'GET',
441
+ path: '/',
442
+ handler: (request, h) => h.success()
443
+ });
444
+
445
+ const res = await server.inject('/');
446
+ expect(res.statusCode).to.equal(200);
447
+ expect(res.result.status).to.equal('ok');
448
+ });
449
+
450
+ it('add new handler', async () => {
451
+
452
+ const test = {
453
+ name: 'test',
454
+ register: function (srv, options1) {
455
+
456
+ const handler = function (route, options2) {
457
+
458
+ return (request) => 'success';
459
+ };
460
+
461
+ srv.decorate('handler', 'bar', handler);
462
+ }
463
+ };
464
+
465
+ const server = Hapi.server();
466
+ await server.register(test);
467
+
468
+ server.route({
469
+ method: 'GET',
470
+ path: '/',
471
+ handler: {
472
+ bar: {}
473
+ }
474
+ });
475
+
476
+ const res = await server.inject('/');
477
+ expect(res.payload).to.equal('success');
478
+ });
479
+
480
+ it('errors on duplicate handler', async () => {
481
+
482
+ const server = Hapi.server();
483
+ await server.register(Inert);
484
+
485
+ expect(() => {
486
+
487
+ server.decorate('handler', 'file', () => { });
488
+ }).to.throw('Handler decoration already defined: file');
489
+ });
490
+
491
+ it('errors on unknown handler', () => {
492
+
493
+ const server = Hapi.server();
494
+
495
+ expect(() => {
496
+
497
+ server.route({ method: 'GET', path: '/', handler: { test: {} } });
498
+ }).to.throw('Unknown handler: test');
499
+ });
500
+
501
+ it('errors on non-string name', () => {
502
+
503
+ const server = Hapi.server();
504
+
505
+ expect(() => {
506
+
507
+ server.decorate('handler', null);
508
+ }).to.throw('Missing decoration property name');
509
+ });
510
+
511
+ it('errors on non-function handler', () => {
512
+
513
+ const server = Hapi.server();
514
+
515
+ expect(() => {
516
+
517
+ server.decorate('handler', 'foo', 'bar');
518
+ }).to.throw('Handler must be a function: foo');
519
+ });
520
+
521
+ it('throws on double toolkit decoration', () => {
522
+
523
+ const server = Hapi.server();
524
+
525
+ server.decorate('toolkit', 'success', () => {
526
+
527
+ return this.response({ status: 'ok' });
528
+ });
529
+
530
+ expect(() => server.decorate('toolkit', 'success', () => { })).to.throw('Toolkit decoration already defined: success');
531
+ });
532
+
533
+ it('throws on internal conflict', () => {
534
+
535
+ const server = Hapi.server();
536
+
537
+ expect(() => {
538
+
539
+ server.decorate('toolkit', 'redirect', () => { });
540
+ }).to.throw('Cannot override built-in toolkit decoration: redirect');
541
+ });
542
+
543
+ it('decorates server', async () => {
544
+
545
+ const server = Hapi.server();
546
+
547
+ const ok = function (path) {
548
+
549
+ server.route({
550
+ method: 'GET',
551
+ path,
552
+ handler: () => 'ok'
553
+ });
554
+ };
555
+
556
+ server.decorate('server', 'ok', ok);
557
+
558
+ server.ok('/');
559
+
560
+ const res = await server.inject('/');
561
+ expect(res.statusCode).to.equal(200);
562
+ expect(res.result).to.equal('ok');
563
+ });
564
+
565
+ it('throws on double server decoration', () => {
566
+
567
+ const server = Hapi.server();
568
+
569
+ const ok = function (path) {
570
+
571
+ server.route({
572
+ method: 'GET',
573
+ path,
574
+ handler: () => 'ok'
575
+ });
576
+ };
577
+
578
+ server.decorate('server', 'ok', ok);
579
+
580
+ expect(() => {
581
+
582
+ server.decorate('server', 'ok', () => { });
583
+ }).to.throw('Server decoration already defined: ok');
584
+ });
585
+
586
+ it('throws on server decoration root conflict', () => {
587
+
588
+ const server = Hapi.server();
589
+
590
+ expect(() => {
591
+
592
+ server.decorate('server', 'start', () => { });
593
+ }).to.throw('Cannot override the built-in server interface method: start');
594
+ });
595
+
596
+ it('throws on server decoration plugin conflict', () => {
597
+
598
+ const server = Hapi.server();
599
+
600
+ expect(() => {
601
+
602
+ server.decorate('server', 'ext', () => { });
603
+ }).to.throw('Cannot override the built-in server interface method: ext');
604
+ });
605
+
606
+ it('throws on invalid decoration name', () => {
607
+
608
+ const server = Hapi.server();
609
+
610
+ expect(() => {
611
+
612
+ server.decorate('server', '_special', () => { });
613
+ }).to.throw('Property name cannot begin with an underscore: _special');
614
+ });
615
+ });
616
+
617
+ describe('decorations ()', () => {
618
+
619
+ it('shows decorations on request (empty array)', () => {
620
+
621
+ const server = Hapi.server();
622
+
623
+ expect(server.decorations.request).to.be.empty();
624
+ });
625
+
626
+ it('shows decorations on request (single)', () => {
627
+
628
+ const server = Hapi.server();
629
+
630
+ server.decorate('request', 'a', () => { });
631
+
632
+ expect(server.decorations.request).to.equal(['a']);
633
+ });
634
+
635
+ it('shows decorations on request (many)', () => {
636
+
637
+ const server = Hapi.server();
638
+ const symbol = Symbol('b');
639
+
640
+ server.decorate('request', 'a', () => { });
641
+ server.decorate('request', symbol, () => { });
642
+
643
+ expect(server.decorations.request).to.equal(['a', symbol]);
644
+ });
645
+
646
+ it('shows decorations on toolkit (empty array)', () => {
647
+
648
+ const server = Hapi.server();
649
+
650
+ expect(server.decorations.toolkit).to.be.empty();
651
+ });
652
+
653
+ it('shows decorations on toolkit (single)', () => {
654
+
655
+ const server = Hapi.server();
656
+
657
+ server.decorate('toolkit', 'a', () => { });
658
+
659
+ expect(server.decorations.toolkit).to.equal(['a']);
660
+ });
661
+
662
+ it('shows decorations on toolkit (many)', () => {
663
+
664
+ const server = Hapi.server();
665
+ const symbol = Symbol('b');
666
+
667
+ server.decorate('toolkit', 'a', () => { });
668
+ server.decorate('toolkit', symbol, () => { });
669
+
670
+ expect(server.decorations.toolkit).to.equal(['a', symbol]);
671
+ });
672
+
673
+ it('shows decorations on server (empty array)', () => {
674
+
675
+ const server = Hapi.server();
676
+
677
+ expect(server.decorations.server).to.be.empty();
678
+ });
679
+
680
+ it('shows decorations on server (single)', () => {
681
+
682
+ const server = Hapi.server();
683
+
684
+ server.decorate('server', 'a', () => { });
685
+
686
+ expect(server.decorations.server).to.equal(['a']);
687
+ });
688
+
689
+ it('shows decorations on server (many)', () => {
690
+
691
+ const server = Hapi.server();
692
+ const symbol = Symbol('b');
693
+
694
+ server.decorate('server', 'a', () => { });
695
+ server.decorate('server', symbol, () => { });
696
+
697
+ expect(server.decorations.server).to.equal(['a', symbol]);
698
+ });
699
+ });
700
+
701
+ describe('dependency()', () => {
702
+
703
+ it('fails to register single plugin with dependencies', async () => {
704
+
705
+ const test = {
706
+ name: 'test',
707
+ register: function (srv, options) {
708
+
709
+ srv.dependency('none');
710
+ }
711
+ };
712
+
713
+ const server = Hapi.server();
714
+ await server.register(test);
715
+ await expect(server.initialize()).to.reject('Plugin test missing dependency none');
716
+ });
717
+
718
+ it('fails to register single plugin with dependencies (plugin)', async () => {
719
+
720
+ const test = {
721
+ name: 'test',
722
+ dependencies: 'none',
723
+ register: Hoek.ignore
724
+ };
725
+
726
+ const server = Hapi.server();
727
+ await server.register(test);
728
+ await expect(server.initialize()).to.reject('Plugin test missing dependency none');
729
+ });
730
+
731
+ it('fails to register multiple plugins with dependencies', async () => {
732
+
733
+ const server = Hapi.server({ port: 80, host: 'localhost' });
734
+ await server.register([internals.plugins.deps1, internals.plugins.deps3]);
735
+ await expect(server.initialize()).to.reject('Plugin deps1 missing dependency deps2');
736
+ });
737
+
738
+ it('recognizes dependencies from peer plugins', async () => {
739
+
740
+ const b = {
741
+ name: 'b',
742
+ register: Hoek.ignore
743
+ };
744
+
745
+ const a = {
746
+ name: 'a',
747
+ register: function (srv, options) {
748
+
749
+ return srv.register(b);
750
+ }
751
+ };
752
+
753
+ const c = {
754
+ name: 'c',
755
+ register: function (srv, options) {
756
+
757
+ srv.dependency('b');
758
+ }
759
+ };
760
+
761
+ const server = Hapi.server();
762
+ await server.register([a, c]);
763
+ });
764
+
765
+ it('errors when missing inner dependencies', async () => {
766
+
767
+ const b = {
768
+ name: 'b',
769
+ register: function (srv, options) {
770
+
771
+ srv.dependency('c');
772
+ }
773
+ };
774
+
775
+ const a = {
776
+ name: 'a',
777
+ register: function (srv, options) {
778
+
779
+ return srv.register(b);
780
+ }
781
+ };
782
+
783
+ const server = Hapi.server({ port: 80, host: 'localhost' });
784
+ await server.register(a);
785
+ await expect(server.initialize()).to.reject('Plugin b missing dependency c');
786
+ });
787
+
788
+ it('errors when missing inner dependencies (plugin)', async () => {
789
+
790
+ const b = {
791
+ name: 'b',
792
+ dependencies: 'c',
793
+ register: Hoek.ignore
794
+ };
795
+
796
+ const a = {
797
+ name: 'a',
798
+ register: function (srv, options) {
799
+
800
+ return srv.register(b);
801
+ }
802
+ };
803
+
804
+ const server = Hapi.server({ port: 80, host: 'localhost' });
805
+ await server.register(a);
806
+ await expect(server.initialize()).to.reject('Plugin b missing dependency c');
807
+ });
808
+ });
809
+
810
+ describe('encoder()', () => {
811
+
812
+ it('adds custom encoder with higher priority than built in encoders', async () => {
813
+
814
+ const data = '{"test":"true"}';
815
+
816
+ const server = Hapi.server({ compression: { minBytes: 1 }, routes: { compression: { test: { some: 'option' } } } });
817
+
818
+ const encoder = (options) => {
819
+
820
+ expect(options).to.equal({ some: 'option' });
821
+ return Zlib.createGzip();
822
+ };
823
+
824
+ server.encoder('test', encoder);
825
+ server.route({ method: 'POST', path: '/', handler: (request) => request.payload });
826
+ await server.start();
827
+
828
+ const uri = 'http://localhost:' + server.info.port;
829
+ const zipped = await new Promise((resolve) => Zlib.gzip(Buffer.from(data), (ignoreErr, compressed) => resolve(compressed)));
830
+ const { res, payload } = await Wreck.post(uri, { headers: { 'accept-encoding': 'gzip, deflate, test' }, payload: data });
831
+ expect(res.headers['content-encoding']).to.equal('test');
832
+ expect(payload.toString()).to.equal(zipped.toString());
833
+ await server.stop();
834
+ });
835
+ });
836
+
837
+ describe('events', () => {
838
+
839
+ it('extends server events', async () => {
840
+
841
+ const server = Hapi.server();
842
+
843
+ const updates = [];
844
+ server.event({ name: 'test', channels: ['x', 'y'] });
845
+
846
+ server.events.on({ name: 'test', channels: 'x' }, (update) => updates.push({ id: 'server', channel: 'x', update }));
847
+
848
+ let plugin;
849
+ const test = {
850
+ name: 'test',
851
+ register: function (srv, options) {
852
+
853
+ srv.events.on({ name: 'test', channels: 'y' }, (update) => updates.push({ id: 'plugin', channel: 'y', update }));
854
+ plugin = srv;
855
+ }
856
+ };
857
+
858
+ server.events.on('test', (update) => updates.push({ id: 'server', update }));
859
+
860
+ await server.register(test);
861
+
862
+ server.events.emit('test', 1);
863
+ server.events.emit({ name: 'test', channel: 'x' }, 2);
864
+ await plugin.events.emit({ name: 'test', channel: 'y' }, 3);
865
+
866
+ expect(updates).to.equal([
867
+ { id: 'server', update: 1 },
868
+ { id: 'server', channel: 'x', update: 2 },
869
+ { id: 'server', update: 2 },
870
+ { id: 'server', update: 3 },
871
+ { id: 'plugin', channel: 'y', update: 3 }
872
+ ]);
873
+ });
874
+
875
+ it('filters log by tags', async () => {
876
+
877
+ const server = Hapi.server();
878
+ const log = server.events.once({ name: 'log', filter: ['x'] });
879
+ server.log('a');
880
+ server.log(['b']);
881
+ server.log(['c', 'x'], 'test 1');
882
+ server.log(['d', 'x'], 'test 2');
883
+
884
+ const [event] = await log;
885
+ expect(event.data).to.equal('test 1');
886
+ });
887
+ });
888
+
889
+ describe('expose()', () => {
890
+
891
+ it('exposes an api', async () => {
892
+
893
+ const server = Hapi.server();
894
+
895
+ await server.register(internals.plugins.test1);
896
+ expect(internals.routesList(server)).to.equal(['/test1']);
897
+ expect(server.plugins.test1.add(1, 3)).to.equal(4);
898
+ expect(server.plugins.test1.glue('1', '3')).to.equal('13');
899
+ });
900
+
901
+ it('exposes an api (scope without scope)', async () => {
902
+
903
+ const server = Hapi.server();
904
+
905
+ const plugin = {
906
+ name: 'test1',
907
+ version: '1.0.0',
908
+ register: function (srv, options) {
909
+
910
+ srv.expose('x', { y: 1 }, { scope: true });
911
+ }
912
+ };
913
+
914
+ await server.register(plugin);
915
+ expect(server.plugins.test1.x.y).to.equal(1);
916
+ expect(server.registrations).to.equal({ test1: { version: '1.0.0', name: 'test1', options: undefined } });
917
+ });
918
+
919
+ it('exposes an api (drops scope by default)', async () => {
920
+
921
+ const server = Hapi.server();
922
+
923
+ const plugin = {
924
+ name: '@hapi/test1',
925
+ version: '1.0.0',
926
+ register: function (srv, options) {
927
+
928
+ srv.expose('x', { y: 1 });
929
+ }
930
+ };
931
+
932
+ await server.register(plugin);
933
+ expect(server.plugins.test1.x.y).to.equal(1);
934
+ expect(server.registrations).to.equal({ '@hapi/test1': { version: '1.0.0', name: '@hapi/test1', options: undefined } });
935
+ });
936
+
937
+ it('exposes an api (keeps scope)', async () => {
938
+
939
+ const server = Hapi.server();
940
+
941
+ const plugin = {
942
+ name: '@hapi/test1',
943
+ version: '1.0.0',
944
+ register: function (srv, options) {
945
+
946
+ srv.expose('x', { y: 1 }, { scope: true });
947
+ }
948
+ };
949
+
950
+ await server.register(plugin);
951
+ expect(server.plugins['@hapi/test1'].x.y).to.equal(1);
952
+ expect(server.registrations).to.equal({ '@hapi/test1': { version: '1.0.0', name: '@hapi/test1', options: undefined } });
953
+ });
954
+
955
+ it('exposes an api (rewrites scope)', async () => {
956
+
957
+ const server = Hapi.server();
958
+
959
+ const plugin = {
960
+ name: '@hapi/test1',
961
+ version: '1.0.0',
962
+ register: function (srv, options) {
963
+
964
+ srv.expose('x', { y: 1 }, { scope: 'underscore' });
965
+ }
966
+ };
967
+
968
+ await server.register(plugin);
969
+ expect(server.plugins.hapi__test1.x.y).to.equal(1);
970
+ expect(server.registrations).to.equal({ '@hapi/test1': { version: '1.0.0', name: '@hapi/test1', options: undefined } });
971
+ });
972
+ });
973
+
974
+ describe('ext()', () => {
975
+
976
+ it('extends onRequest point', async () => {
977
+
978
+ const test = {
979
+ name: 'test',
980
+ register: function (srv, options) {
981
+
982
+ srv.route({
983
+ method: 'GET',
984
+ path: '/b',
985
+ handler: () => 'b'
986
+ });
987
+
988
+ const onRequest = (request, h) => {
989
+
990
+ request.setUrl('/b');
991
+ return h.continue;
992
+ };
993
+
994
+ srv.ext('onRequest', onRequest);
995
+ }
996
+ };
997
+
998
+ const server = Hapi.server();
999
+ await server.register(test);
1000
+
1001
+ expect(internals.routesList(server)).to.equal(['/b']);
1002
+ const res = await server.inject('/a');
1003
+ expect(res.result).to.equal('b');
1004
+ });
1005
+
1006
+ it('returns promise on empty ext handler', async () => {
1007
+
1008
+ const server = Hapi.server();
1009
+ const ext = server.ext('onRequest');
1010
+ server.route({ path: '/', method: 'GET', handler: () => 'ok' });
1011
+ const res = await server.inject('/');
1012
+ expect(res.result).to.equal('ok');
1013
+ const request = await ext;
1014
+ expect(request.response.source).to.equal('ok');
1015
+ });
1016
+
1017
+ it('adds multiple ext functions with complex dependencies', async () => {
1018
+
1019
+ // Generate a plugin with a specific index and ext dependencies.
1020
+
1021
+ const pluginCurrier = function (num, deps) {
1022
+
1023
+ const plugin = {
1024
+ name: 'deps' + num,
1025
+ register: function (server, options) {
1026
+
1027
+ const onRequest = (request, h) => {
1028
+
1029
+ request.app.complexDeps = request.app.complexDeps || '|';
1030
+ request.app.complexDeps += num + '|';
1031
+ return h.continue;
1032
+ };
1033
+
1034
+ server.ext('onRequest', onRequest, deps);
1035
+ }
1036
+ };
1037
+
1038
+ return plugin;
1039
+ };
1040
+
1041
+ const server = Hapi.server();
1042
+ server.route({ method: 'GET', path: '/', handler: (request) => request.app.complexDeps });
1043
+
1044
+ await server.register([
1045
+ pluginCurrier(1, { after: 'deps2' }),
1046
+ pluginCurrier(2),
1047
+ pluginCurrier(3, { before: ['deps1', 'deps2'] })
1048
+ ]);
1049
+
1050
+ await server.initialize();
1051
+
1052
+ const res = await server.inject('/');
1053
+ expect(res.result).to.equal('|3|2|1|');
1054
+ });
1055
+
1056
+ it('binds server ext to context (options)', async () => {
1057
+
1058
+ const server = Hapi.server();
1059
+
1060
+ const bind = {
1061
+ state: false
1062
+ };
1063
+
1064
+ const preStart = function (srv) {
1065
+
1066
+ this.state = true;
1067
+ };
1068
+
1069
+ server.ext('onPreStart', preStart, { bind });
1070
+
1071
+ await server.initialize();
1072
+ expect(bind.state).to.be.true();
1073
+ });
1074
+
1075
+ it('binds server ext to context (argument)', async () => {
1076
+
1077
+ const server = Hapi.server();
1078
+
1079
+ const bind = {
1080
+ state: false
1081
+ };
1082
+
1083
+ const preStart = (srv, context) => {
1084
+
1085
+ context.state = true;
1086
+ };
1087
+
1088
+ server.ext('onPreStart', preStart, { bind });
1089
+
1090
+ await server.initialize();
1091
+ expect(bind.state).to.be.true();
1092
+ });
1093
+
1094
+ it('binds server ext to context (realm)', async () => {
1095
+
1096
+ const server = Hapi.server();
1097
+
1098
+ const bind = {
1099
+ state: false
1100
+ };
1101
+
1102
+ server.bind(bind);
1103
+ const preStart = function (srv) {
1104
+
1105
+ this.state = true;
1106
+ };
1107
+
1108
+ server.ext('onPreStart', preStart);
1109
+
1110
+ await server.initialize();
1111
+ expect(bind.state).to.be.true();
1112
+ });
1113
+
1114
+ it('extends server actions', async () => {
1115
+
1116
+ const server = Hapi.server();
1117
+
1118
+ let result = '';
1119
+ const preStart = function (srv) {
1120
+
1121
+ result += '1';
1122
+ };
1123
+
1124
+ server.ext('onPreStart', preStart);
1125
+
1126
+ const postStart = function (srv) {
1127
+
1128
+ result += '2';
1129
+ };
1130
+
1131
+ server.ext('onPostStart', postStart);
1132
+
1133
+ const preStop = function (srv) {
1134
+
1135
+ result += '3';
1136
+ };
1137
+
1138
+ server.ext('onPreStop', preStop);
1139
+
1140
+ const postStop = function (srv) {
1141
+
1142
+ result += '4';
1143
+ };
1144
+
1145
+ server.ext('onPostStop', postStop);
1146
+
1147
+ await server.start();
1148
+ expect(result).to.equal('12');
1149
+
1150
+ await server.stop();
1151
+ expect(result).to.equal('1234');
1152
+ });
1153
+
1154
+ it('extends server actions (single call)', async () => {
1155
+
1156
+ const server = Hapi.server();
1157
+
1158
+ let result = '';
1159
+ server.ext([
1160
+ {
1161
+ type: 'onPreStart',
1162
+ method: function (srv) {
1163
+
1164
+ result += '1';
1165
+ }
1166
+ },
1167
+ {
1168
+ type: 'onPostStart',
1169
+ method: function (srv) {
1170
+
1171
+ result += '2';
1172
+ }
1173
+ },
1174
+ {
1175
+ type: 'onPreStop',
1176
+ method: function (srv) {
1177
+
1178
+ result += '3';
1179
+ }
1180
+ },
1181
+ {
1182
+ type: 'onPreStop',
1183
+ method: function (srv) {
1184
+
1185
+ result += '4';
1186
+ }
1187
+ }
1188
+ ]);
1189
+
1190
+ await server.start();
1191
+ expect(result).to.equal('12');
1192
+
1193
+ await server.stop();
1194
+ expect(result).to.equal('1234');
1195
+ });
1196
+
1197
+ it('combine route extensions', async () => {
1198
+
1199
+ const server = Hapi.server();
1200
+
1201
+ const preAuth = (request, h) => {
1202
+
1203
+ request.app.x = '1';
1204
+ return h.continue;
1205
+ };
1206
+
1207
+ server.ext('onPreAuth', preAuth);
1208
+
1209
+ const plugin = {
1210
+ name: 'test',
1211
+ register: function (srv, options) {
1212
+
1213
+ srv.route({
1214
+ method: 'GET',
1215
+ path: '/',
1216
+ options: {
1217
+ ext: {
1218
+ onPreAuth: {
1219
+ method: (request, h) => {
1220
+
1221
+ request.app.x += '2';
1222
+ return h.continue;
1223
+ }
1224
+ }
1225
+ },
1226
+ handler: (request) => request.app.x
1227
+ }
1228
+ });
1229
+
1230
+ const preAuthSandbox = (request, h) => {
1231
+
1232
+ request.app.x += '3';
1233
+ return h.continue;
1234
+ };
1235
+
1236
+ srv.ext('onPreAuth', preAuthSandbox, { sandbox: 'plugin' });
1237
+ }
1238
+ };
1239
+
1240
+ await server.register(plugin);
1241
+
1242
+ server.route({
1243
+ method: 'GET',
1244
+ path: '/a',
1245
+ handler: (request) => request.app.x
1246
+ });
1247
+
1248
+ const res1 = await server.inject('/');
1249
+ expect(res1.result).to.equal('123');
1250
+
1251
+ const res2 = await server.inject('/a');
1252
+ expect(res2.result).to.equal('1');
1253
+ });
1254
+
1255
+ it('calls method after plugin', async () => {
1256
+
1257
+ const x = {
1258
+ name: 'x',
1259
+ register: function (srv, options) {
1260
+
1261
+ srv.expose('a', 'b');
1262
+ }
1263
+ };
1264
+
1265
+ const server = Hapi.server();
1266
+
1267
+ expect(server.plugins.x).to.not.exist();
1268
+
1269
+ let called = false;
1270
+ const preStart = function (srv) {
1271
+
1272
+ expect(srv.plugins.x.a).to.equal('b');
1273
+ called = true;
1274
+ };
1275
+
1276
+ server.ext('onPreStart', preStart, { after: 'x' });
1277
+
1278
+ await server.register(x);
1279
+ await server.initialize();
1280
+ expect(called).to.be.true();
1281
+ });
1282
+
1283
+ it('calls method before start', async () => {
1284
+
1285
+ const server = Hapi.server();
1286
+
1287
+ let called = false;
1288
+ const preStart = function (srv) {
1289
+
1290
+ called = true;
1291
+ };
1292
+
1293
+ server.ext('onPreStart', preStart);
1294
+
1295
+ await server.initialize();
1296
+ expect(called).to.be.true();
1297
+ });
1298
+
1299
+ it('calls method before start even if plugin not registered', async () => {
1300
+
1301
+ const server = Hapi.server();
1302
+
1303
+ let called = false;
1304
+ const preStart = function (srv) {
1305
+
1306
+ called = true;
1307
+ };
1308
+
1309
+ server.ext('onPreStart', preStart, { after: 'x' });
1310
+
1311
+ await server.initialize();
1312
+ expect(called).to.be.true();
1313
+ });
1314
+
1315
+ it('fails to start server when after method fails', async () => {
1316
+
1317
+ const test = {
1318
+ name: 'test',
1319
+ register: function (srv, options) {
1320
+
1321
+ const preStart1 = function (inner) { };
1322
+
1323
+ srv.ext('onPreStart', preStart1);
1324
+
1325
+ const preStart2 = function (inner) {
1326
+
1327
+ throw new Error('Not in the mood');
1328
+ };
1329
+
1330
+ srv.ext('onPreStart', preStart2);
1331
+ }
1332
+ };
1333
+
1334
+ const server = Hapi.server();
1335
+ await server.register(test);
1336
+ await expect(server.initialize()).to.reject('Not in the mood');
1337
+ });
1338
+
1339
+ it('errors when added after initialization', async () => {
1340
+
1341
+ const server = Hapi.server();
1342
+
1343
+ await server.initialize();
1344
+ expect(() => {
1345
+
1346
+ server.ext('onPreStart', () => { });
1347
+ }).to.throw('Cannot add onPreStart (after) extension after the server was initialized');
1348
+ });
1349
+ });
1350
+
1351
+ describe('log()', () => {
1352
+
1353
+ it('emits a log event', async () => {
1354
+
1355
+ const server = Hapi.server();
1356
+
1357
+ let count = 0;
1358
+ server.events.once('log', (event, tags) => {
1359
+
1360
+ ++count;
1361
+ expect(event.data).to.equal('log event 1');
1362
+ });
1363
+
1364
+ server.events.once('log', (event, tags) => {
1365
+
1366
+ ++count;
1367
+ expect(event.data).to.equal('log event 1');
1368
+ });
1369
+
1370
+ server.log('1', 'log event 1');
1371
+
1372
+ server.events.once('log', (event, tags) => {
1373
+
1374
+ ++count;
1375
+ expect(event.data).to.equal('log event 2');
1376
+ });
1377
+
1378
+ server.log(['2'], 'log event 2');
1379
+ await Hoek.wait(10);
1380
+ expect(count).to.equal(3);
1381
+ });
1382
+
1383
+ it('emits a log event (function data)', async () => {
1384
+
1385
+ const server = Hapi.server();
1386
+ const log = server.events.once('log');
1387
+ server.log('test', () => 123);
1388
+ const [event] = await log;
1389
+ expect(event.data).to.equal(123);
1390
+ });
1391
+
1392
+ it('emits a log event and print to console', async () => {
1393
+
1394
+ const server = Hapi.server({ debug: { log: 'implementation' } });
1395
+
1396
+ server.events.once('log', (event, tags) => {
1397
+
1398
+ expect(event.data).to.equal('log event 1');
1399
+ });
1400
+
1401
+ const log = new Promise((resolve) => {
1402
+
1403
+ const orig = console.error;
1404
+ console.error = function (...args) {
1405
+
1406
+ console.error = orig;
1407
+ expect(args[0]).to.equal('Debug:');
1408
+ expect(args[1]).to.equal('internal, implementation, error');
1409
+
1410
+ resolve();
1411
+ };
1412
+ });
1413
+
1414
+ server.log(['internal', 'implementation', 'error'], 'log event 1');
1415
+ await log;
1416
+ });
1417
+
1418
+ it('outputs log data to debug console', async () => {
1419
+
1420
+ const server = Hapi.server({ debug: { log: '*' } });
1421
+
1422
+ const log = new Promise((resolve) => {
1423
+
1424
+ const orig = console.error;
1425
+ console.error = function (...args) {
1426
+
1427
+ console.error = orig;
1428
+ expect(args[0]).to.equal('Debug:');
1429
+ expect(args[1]).to.equal('implementation');
1430
+ expect(args[2]).to.equal('\n {"data":1}');
1431
+
1432
+ resolve();
1433
+ };
1434
+ });
1435
+
1436
+ server.log(['implementation'], { data: 1 });
1437
+ await log;
1438
+ });
1439
+
1440
+ it('outputs log error data to debug console', async () => {
1441
+
1442
+ const server = Hapi.server({ debug: { log: '*' } });
1443
+
1444
+ const log = new Promise((resolve) => {
1445
+
1446
+ const orig = console.error;
1447
+ console.error = function (...args) {
1448
+
1449
+ console.error = orig;
1450
+ expect(args[0]).to.equal('Debug:');
1451
+ expect(args[1]).to.equal('implementation');
1452
+ expect(args[2]).to.contain('\n Error: test\n at');
1453
+ resolve();
1454
+ };
1455
+ });
1456
+
1457
+ server.log(['implementation'], new Error('test'));
1458
+ await log;
1459
+ });
1460
+
1461
+ it('outputs log data to debug console without data', async () => {
1462
+
1463
+ const server = Hapi.server({ debug: { log: '*' } });
1464
+
1465
+ const log = new Promise((resolve) => {
1466
+
1467
+ const orig = console.error;
1468
+ console.error = function (...args) {
1469
+
1470
+ console.error = orig;
1471
+ expect(args[0]).to.equal('Debug:');
1472
+ expect(args[1]).to.equal('implementation');
1473
+ expect(args[2]).to.equal('');
1474
+ resolve();
1475
+ };
1476
+ });
1477
+
1478
+ server.log(['implementation']);
1479
+ await log;
1480
+ });
1481
+
1482
+ it('does not output events when debug disabled', () => {
1483
+
1484
+ const server = Hapi.server({ debug: false });
1485
+
1486
+ let i = 0;
1487
+ const orig = console.error;
1488
+ console.error = function () {
1489
+
1490
+ ++i;
1491
+ };
1492
+
1493
+ server.log(['implementation']);
1494
+ console.error('nothing');
1495
+ expect(i).to.equal(1);
1496
+ console.error = orig;
1497
+ });
1498
+
1499
+ it('does not output events when debug.log disabled', () => {
1500
+
1501
+ const server = Hapi.server({ debug: { log: false } });
1502
+
1503
+ let i = 0;
1504
+ const orig = console.error;
1505
+ console.error = function () {
1506
+
1507
+ ++i;
1508
+ };
1509
+
1510
+ server.log(['implementation']);
1511
+ console.error('nothing');
1512
+ expect(i).to.equal(1);
1513
+ console.error = orig;
1514
+ });
1515
+
1516
+ it('does not output non-implementation events by default', () => {
1517
+
1518
+ const server = Hapi.server();
1519
+
1520
+ let i = 0;
1521
+ const orig = console.error;
1522
+ console.error = function () {
1523
+
1524
+ ++i;
1525
+ };
1526
+
1527
+ server.log(['xyz']);
1528
+ console.error('nothing');
1529
+ expect(i).to.equal(1);
1530
+ console.error = orig;
1531
+ });
1532
+
1533
+ it('emits server log events once', async () => {
1534
+
1535
+ let pc = 0;
1536
+ const test = {
1537
+ name: 'test',
1538
+ register: function (srv, options) {
1539
+
1540
+ srv.events.on('log', (event, tags) => ++pc);
1541
+ }
1542
+ };
1543
+
1544
+ const server = Hapi.server();
1545
+
1546
+ let sc = 0;
1547
+ server.events.on('log', (event, tags) => ++sc);
1548
+
1549
+ await server.register(test);
1550
+ server.log('test');
1551
+ expect(sc).to.equal(1);
1552
+ expect(pc).to.equal(1);
1553
+ });
1554
+
1555
+ it('emits log events after handler error when server is started', async () => {
1556
+
1557
+ const server = Hapi.server({ debug: false });
1558
+
1559
+ const updates = [];
1560
+ const test = {
1561
+ name: 'test',
1562
+ register: function (srv, options) {
1563
+
1564
+ srv.events.on('log', (event, tags) => updates.push(event.tags));
1565
+ srv.events.on('response', (request) => updates.push('response'));
1566
+ srv.events.on({ name: 'request', channels: 'error' }, (request, err) => updates.push({ name: 'request', channels: 'error' }));
1567
+ }
1568
+ };
1569
+
1570
+ server.route({
1571
+ method: 'GET',
1572
+ path: '/',
1573
+ handler: (request) => {
1574
+
1575
+ request.server.log('1');
1576
+ throw new Error('2');
1577
+ }
1578
+ });
1579
+
1580
+ await server.register(test);
1581
+ await server.start();
1582
+
1583
+ const res = await server.inject('/');
1584
+ expect(res.statusCode).to.equal(500);
1585
+ await Hoek.wait(10);
1586
+ expect(updates).to.equal([['1'], { name: 'request', channels: 'error' }, 'response']);
1587
+ await server.stop();
1588
+ });
1589
+
1590
+ it('outputs logs for all server log events with a wildcard', async () => {
1591
+
1592
+ const server = Hapi.server({ debug: { log: '*' } });
1593
+
1594
+ const log = new Promise((resolve) => {
1595
+
1596
+ const orig = console.error;
1597
+ console.error = function (...args) {
1598
+
1599
+ console.error = orig;
1600
+ expect(args[0]).to.equal('Debug:');
1601
+ expect(args[1]).to.equal('foobar');
1602
+ expect(args[2]).to.equal('\n {"data":1}');
1603
+ resolve();
1604
+ };
1605
+ });
1606
+
1607
+ server.log(['foobar'], { data: 1 });
1608
+ await log;
1609
+ });
1610
+
1611
+ it('outputs logs for all request log events with a wildcard', async () => {
1612
+
1613
+ const server = Hapi.server({ debug: { request: '*' } });
1614
+
1615
+ const expectedLogs = [
1616
+ ['Debug:', 'handler, error']
1617
+ ];
1618
+
1619
+ const log = new Promise((resolve) => {
1620
+
1621
+ const orig = console.error;
1622
+ console.error = function (...args) {
1623
+
1624
+ expect(args).to.contain(expectedLogs.shift());
1625
+ if (expectedLogs.length === 0) {
1626
+ console.error = orig;
1627
+ resolve();
1628
+ }
1629
+ };
1630
+ });
1631
+
1632
+ server.inject('/', () => { });
1633
+ await log;
1634
+ });
1635
+ });
1636
+
1637
+ describe('lookup()', () => {
1638
+
1639
+ it('returns route based on id', () => {
1640
+
1641
+ const server = Hapi.server();
1642
+ server.route({
1643
+ method: 'GET',
1644
+ path: '/',
1645
+ options: {
1646
+ handler: () => null,
1647
+ id: 'root',
1648
+ app: { test: 123 }
1649
+ }
1650
+ });
1651
+
1652
+ const root = server.lookup('root');
1653
+ expect(root.path).to.equal('/');
1654
+ expect(root.settings.app.test).to.equal(123);
1655
+ });
1656
+
1657
+ it('returns null on unknown route', () => {
1658
+
1659
+ const server = Hapi.server();
1660
+ const root = server.lookup('root');
1661
+ expect(root).to.be.null();
1662
+ });
1663
+
1664
+ it('throws on missing id', () => {
1665
+
1666
+ const server = Hapi.server();
1667
+ expect(() => {
1668
+
1669
+ server.lookup();
1670
+ }).to.throw('Invalid route id: ');
1671
+ });
1672
+ });
1673
+
1674
+ describe('match()', () => {
1675
+
1676
+ it('returns route based on path', () => {
1677
+
1678
+ const server = Hapi.server();
1679
+
1680
+ server.route({
1681
+ method: 'GET',
1682
+ path: '/',
1683
+ options: {
1684
+ handler: () => null,
1685
+ id: 'root'
1686
+ }
1687
+ });
1688
+
1689
+ server.route({
1690
+ method: 'GET',
1691
+ path: '/abc',
1692
+ options: {
1693
+ handler: () => null,
1694
+ id: 'abc'
1695
+ }
1696
+ });
1697
+
1698
+ server.route({
1699
+ method: 'POST',
1700
+ path: '/abc',
1701
+ options: {
1702
+ handler: () => null,
1703
+ id: 'post'
1704
+ }
1705
+ });
1706
+
1707
+ server.route({
1708
+ method: 'GET',
1709
+ path: '/{p}/{x}',
1710
+ options: {
1711
+ handler: () => null,
1712
+ id: 'params'
1713
+ }
1714
+ });
1715
+
1716
+ server.route({
1717
+ method: 'GET',
1718
+ path: '/abc',
1719
+ vhost: 'example.com',
1720
+ options: {
1721
+ handler: () => null,
1722
+ id: 'vhost'
1723
+ }
1724
+ });
1725
+
1726
+ expect(server.match('GET', '/').settings.id).to.equal('root');
1727
+ expect(server.match('GET', '/none')).to.equal(null);
1728
+ expect(server.match('GET', '/abc').settings.id).to.equal('abc');
1729
+ expect(server.match('get', '/').settings.id).to.equal('root');
1730
+ expect(server.match('post', '/abc').settings.id).to.equal('post');
1731
+ expect(server.match('get', '/a/b').settings.id).to.equal('params');
1732
+ expect(server.match('GET', '/abc', 'example.com').settings.id).to.equal('vhost');
1733
+ });
1734
+
1735
+ it('throws on missing method', () => {
1736
+
1737
+ const server = Hapi.server();
1738
+ expect(() => {
1739
+
1740
+ server.match();
1741
+ }).to.throw('Invalid method: ');
1742
+ });
1743
+
1744
+ it('throws on invalid method', () => {
1745
+
1746
+ const server = Hapi.server();
1747
+ expect(() => {
1748
+
1749
+ server.match(5);
1750
+ }).to.throw('Invalid method: 5');
1751
+ });
1752
+
1753
+ it('throws on missing path', () => {
1754
+
1755
+ const server = Hapi.server();
1756
+ expect(() => {
1757
+
1758
+ server.match('get');
1759
+ }).to.throw('Invalid path: ');
1760
+ });
1761
+
1762
+ it('throws on invalid path type', () => {
1763
+
1764
+ const server = Hapi.server();
1765
+ expect(() => {
1766
+
1767
+ server.match('get', 5);
1768
+ }).to.throw('Invalid path: 5');
1769
+ });
1770
+
1771
+ it('throws on invalid path prefix', () => {
1772
+
1773
+ const server = Hapi.server();
1774
+ expect(() => {
1775
+
1776
+ server.match('get', '5');
1777
+ }).to.throw('Invalid path: 5');
1778
+ });
1779
+
1780
+ it('throws on invalid path', () => {
1781
+
1782
+ const server = Hapi.server();
1783
+ server.route({
1784
+ method: 'GET',
1785
+ path: '/{p}',
1786
+ handler: () => null
1787
+ });
1788
+
1789
+ expect(() => {
1790
+
1791
+ server.match('GET', '/%p');
1792
+ }).to.throw('Invalid path: /%p');
1793
+ });
1794
+
1795
+ it('throws on invalid host type', () => {
1796
+
1797
+ const server = Hapi.server();
1798
+ expect(() => {
1799
+
1800
+ server.match('get', '/a', 5);
1801
+ }).to.throw('Invalid host: 5');
1802
+ });
1803
+ });
1804
+
1805
+ describe('method()', () => {
1806
+
1807
+ it('adds server method using arguments', async () => {
1808
+
1809
+ const server = Hapi.server();
1810
+
1811
+ const test = {
1812
+ name: 'test',
1813
+ register: function (srv, options) {
1814
+
1815
+ const method = function (methodNext) {
1816
+
1817
+ return methodNext(null);
1818
+ };
1819
+
1820
+ srv.method('log', method);
1821
+ }
1822
+ };
1823
+
1824
+ await server.register(test);
1825
+ });
1826
+
1827
+ it('adds server method with plugin bind', async () => {
1828
+
1829
+ const server = Hapi.server();
1830
+
1831
+ const test = {
1832
+ name: 'test',
1833
+ register: function (srv, options) {
1834
+
1835
+ srv.bind({ x: 1 });
1836
+ const method = function () {
1837
+
1838
+ return this.x;
1839
+ };
1840
+
1841
+ srv.method('log', method);
1842
+ }
1843
+ };
1844
+
1845
+ await server.register(test);
1846
+ const result = server.methods.log();
1847
+ expect(result).to.equal(1);
1848
+ });
1849
+
1850
+ it('adds server method with method bind', async () => {
1851
+
1852
+ const server = Hapi.server();
1853
+
1854
+ const test = {
1855
+ name: 'test',
1856
+ register: function (srv, options) {
1857
+
1858
+ const method = function () {
1859
+
1860
+ return this.x;
1861
+ };
1862
+
1863
+ srv.method('log', method, { bind: { x: 2 } });
1864
+ }
1865
+ };
1866
+
1867
+ await server.register(test);
1868
+
1869
+ const result = server.methods.log();
1870
+ expect(result).to.equal(2);
1871
+ });
1872
+
1873
+ it('adds server method with method and ext bind', async () => {
1874
+
1875
+ const server = Hapi.server();
1876
+
1877
+ const test = {
1878
+ name: 'test',
1879
+ register: function (srv, options) {
1880
+
1881
+ srv.bind({ x: 1 });
1882
+ const method = function () {
1883
+
1884
+ return this.x;
1885
+ };
1886
+
1887
+ srv.method('log', method, { bind: { x: 2 } });
1888
+ }
1889
+ };
1890
+
1891
+ await server.register(test);
1892
+
1893
+ const result = server.methods.log();
1894
+ expect(result).to.equal(2);
1895
+ });
1896
+ });
1897
+
1898
+ describe('path()', () => {
1899
+
1900
+ it('sets local path for directory route handler', async () => {
1901
+
1902
+ const test = {
1903
+ name: 'test',
1904
+ register: function (srv, options) {
1905
+
1906
+ srv.path(Path.join(__dirname, '..'));
1907
+
1908
+ srv.route({
1909
+ method: 'GET',
1910
+ path: '/handler/{file*}',
1911
+ handler: {
1912
+ directory: {
1913
+ path: './'
1914
+ }
1915
+ }
1916
+ });
1917
+ }
1918
+ };
1919
+
1920
+ const server = Hapi.server({ routes: { files: { relativeTo: __dirname } } });
1921
+ await server.register(Inert);
1922
+ await server.register(test);
1923
+
1924
+ const res = await server.inject('/handler/package.json');
1925
+ expect(res.statusCode).to.equal(200);
1926
+ });
1927
+
1928
+ it('throws when plugin sets undefined path', async () => {
1929
+
1930
+ const test = {
1931
+ name: 'test',
1932
+ register: function (srv, options) {
1933
+
1934
+ srv.path();
1935
+ }
1936
+ };
1937
+
1938
+ const server = Hapi.server();
1939
+ await expect(server.register(test)).to.reject('relativeTo must be a non-empty string');
1940
+ });
1941
+ });
1942
+
1943
+ describe('register()', () => {
1944
+
1945
+ it('registers plugin with options', async () => {
1946
+
1947
+ const server = Hapi.server();
1948
+
1949
+ const test = {
1950
+ name: 'test',
1951
+
1952
+ register: function (srv, options) {
1953
+
1954
+ expect(options.something).to.be.true();
1955
+ expect(srv.realm.pluginOptions).to.equal(options);
1956
+ }
1957
+ };
1958
+
1959
+ await server.register({ plugin: test, options: { something: true } });
1960
+ });
1961
+
1962
+ it('registers a required plugin', async () => {
1963
+
1964
+ const server = Hapi.server();
1965
+
1966
+ const test = {
1967
+ plugin: {
1968
+ name: 'test',
1969
+ register: function (srv, options) {
1970
+
1971
+ expect(options.something).to.be.true();
1972
+ }
1973
+ }
1974
+ };
1975
+
1976
+ await server.register({ plugin: test, options: { something: true } });
1977
+ });
1978
+
1979
+ it('rejects on bad plugin (missing name)', async () => {
1980
+
1981
+ const plugin = {
1982
+ register: Hoek.ignore
1983
+ };
1984
+
1985
+ const server = Hapi.server();
1986
+ await expect(server.register(plugin)).to.reject();
1987
+ });
1988
+
1989
+ it('rejects on bad plugin (empty pkg)', async () => {
1990
+
1991
+ const plugin = {
1992
+ pkg: {},
1993
+ register: Hoek.ignore
1994
+ };
1995
+
1996
+ const server = Hapi.server();
1997
+ await expect(server.register(plugin)).to.reject();
1998
+ });
1999
+
2000
+ it('returns plugin error', async () => {
2001
+
2002
+ const test = {
2003
+ name: 'test',
2004
+ register: function (srv, options) {
2005
+
2006
+ throw new Error('from plugin');
2007
+ }
2008
+ };
2009
+
2010
+ const server = Hapi.server();
2011
+ await expect(server.register(test)).to.reject('from plugin');
2012
+ });
2013
+
2014
+ it('sets version to 0.0.0 if missing', async () => {
2015
+
2016
+ const test = {
2017
+ pkg: {
2018
+ name: 'steve'
2019
+ },
2020
+ register: function (srv, options) {
2021
+
2022
+ srv.route({
2023
+ method: 'GET',
2024
+ path: '/',
2025
+ handler: () => srv.version
2026
+ });
2027
+ }
2028
+ };
2029
+
2030
+ const server = Hapi.server();
2031
+ await server.register(test);
2032
+ expect(server.registrations.steve.version).to.equal('0.0.0');
2033
+
2034
+ const res = await server.inject('/');
2035
+ expect(res.result).to.equal(require('../package.json').version);
2036
+ });
2037
+
2038
+ it('exposes plugin registration information', async () => {
2039
+
2040
+ const test = {
2041
+ multiple: true,
2042
+ pkg: {
2043
+ name: 'bob',
2044
+ version: '1.2.3'
2045
+ },
2046
+ register: function (srv, options) {
2047
+
2048
+ srv.route({ method: 'GET', path: '/', handler: () => srv.version });
2049
+ }
2050
+ };
2051
+
2052
+ const server = Hapi.server();
2053
+
2054
+ await server.register({ plugin: test, options: { foo: 'bar' } });
2055
+ const bob = server.registrations.bob;
2056
+ expect(bob).to.exist();
2057
+ expect(bob).to.be.an.object();
2058
+ expect(bob.version).to.equal('1.2.3');
2059
+ expect(bob.options.foo).to.equal('bar');
2060
+
2061
+ const res = await server.inject('/');
2062
+ expect(res.result).to.equal(require('../package.json').version);
2063
+ });
2064
+
2065
+ it('prevents plugin from multiple registrations', async () => {
2066
+
2067
+ const test = {
2068
+ name: 'test',
2069
+ register: function (srv, options) {
2070
+
2071
+ srv.route({ method: 'GET', path: '/a', handler: () => 'a' });
2072
+ }
2073
+ };
2074
+
2075
+ const server = Hapi.server({ host: 'example.com' });
2076
+ await server.register(test);
2077
+ await expect(server.register(test)).to.reject('Plugin test already registered');
2078
+ });
2079
+
2080
+ it('allows plugin multiple registrations (plugin)', async () => {
2081
+
2082
+ const test = {
2083
+ name: 'test',
2084
+ multiple: true,
2085
+ register: function (srv, options) {
2086
+
2087
+ srv.app.x = srv.app.x ? srv.app.x + 1 : 1;
2088
+ }
2089
+ };
2090
+
2091
+ const server = Hapi.server();
2092
+ await server.register(test);
2093
+ await server.register(test);
2094
+ expect(server.app.x).to.equal(2);
2095
+ });
2096
+
2097
+ it('registers multiple plugins', async () => {
2098
+
2099
+ const server = Hapi.server();
2100
+ let log = null;
2101
+ server.events.once('log', (event, tags) => {
2102
+
2103
+ log = [event, tags];
2104
+ });
2105
+
2106
+ await server.register([internals.plugins.test1, internals.plugins.test2]);
2107
+ expect(internals.routesList(server)).to.equal(['/test1', '/test2']);
2108
+ expect(log[1].test).to.equal(true);
2109
+ expect(log[0].data).to.equal('abc');
2110
+ });
2111
+
2112
+ it('registers multiple plugins (verbose)', async () => {
2113
+
2114
+ const server = Hapi.server();
2115
+ let log = null;
2116
+ server.events.once('log', (event, tags) => {
2117
+
2118
+ log = [event, tags];
2119
+ });
2120
+
2121
+ await server.register([{ plugin: internals.plugins.test1 }, { plugin: internals.plugins.test2 }]);
2122
+ expect(internals.routesList(server)).to.equal(['/test1', '/test2']);
2123
+ expect(log[1].test).to.equal(true);
2124
+ expect(log[0].data).to.equal('abc');
2125
+ });
2126
+
2127
+ it('registers a child plugin', async () => {
2128
+
2129
+ const server = Hapi.server();
2130
+ await server.register(internals.plugins.child);
2131
+ const res = await server.inject('/test1');
2132
+ expect(res.result).to.equal('testing123');
2133
+ });
2134
+
2135
+ it('registers a plugin with routes path prefix', async () => {
2136
+
2137
+ const server = Hapi.server();
2138
+ await server.register(internals.plugins.test1, { routes: { prefix: '/xyz' } });
2139
+
2140
+ expect(server.plugins.test1.prefix).to.equal('/xyz');
2141
+ const res = await server.inject('/xyz/test1');
2142
+ expect(res.result).to.equal('testing123');
2143
+ });
2144
+
2145
+ it('registers a plugin with routes path prefix (plugin options)', async () => {
2146
+
2147
+ const server = Hapi.server();
2148
+ await server.register({ plugin: internals.plugins.test1, routes: { prefix: '/abc' } }, { routes: { prefix: '/xyz' } });
2149
+
2150
+ expect(server.plugins.test1.prefix).to.equal('/abc');
2151
+ const res = await server.inject('/abc/test1');
2152
+ expect(res.result).to.equal('testing123');
2153
+ });
2154
+
2155
+ it('register a plugin once (plugin options)', async () => {
2156
+
2157
+ let count = 0;
2158
+ const b = {
2159
+ name: 'b',
2160
+ register: function (srv, options) {
2161
+
2162
+ ++count;
2163
+ }
2164
+ };
2165
+
2166
+ const a = {
2167
+ name: 'a',
2168
+ register: async function (srv, options) {
2169
+
2170
+ await srv.register({ plugin: b, once: true });
2171
+ }
2172
+ };
2173
+
2174
+ const server = Hapi.server();
2175
+ await server.register(b);
2176
+ await server.register(a);
2177
+ await server.initialize();
2178
+ expect(count).to.equal(1);
2179
+ });
2180
+
2181
+ it('registers plugins and adds options to realm that routes can access', async () => {
2182
+
2183
+ const server = Hapi.server();
2184
+
2185
+ const foo = {
2186
+ name: 'foo',
2187
+ register: function (srv, options) {
2188
+
2189
+ expect(options.something).to.be.true();
2190
+ expect(srv.realm.pluginOptions).to.equal(options);
2191
+
2192
+ srv.route({
2193
+ method: 'GET', path: '/foo', handler: (request, h) => {
2194
+
2195
+ expect(request.route.realm.pluginOptions).to.equal(options);
2196
+ expect(h.realm.pluginOptions).to.equal(options);
2197
+ return 'foo';
2198
+ }
2199
+ });
2200
+ }
2201
+ };
2202
+
2203
+ const bar = {
2204
+ name: 'bar',
2205
+ register: function (srv, options) {
2206
+
2207
+ expect(options.something).to.be.false();
2208
+ expect(srv.realm.pluginOptions).to.equal(options);
2209
+
2210
+ srv.route({
2211
+ method: 'GET', path: '/bar', handler: (request, h) => {
2212
+
2213
+ expect(request.route.realm.pluginOptions).to.equal(options);
2214
+ expect(h.realm.pluginOptions).to.equal(options);
2215
+ return 'bar';
2216
+ }
2217
+ });
2218
+ }
2219
+ };
2220
+
2221
+ const plugins = [
2222
+ { plugin: foo, options: { something: true } },
2223
+ { plugin: bar, options: { something: false } }
2224
+ ];
2225
+
2226
+ await server.register(plugins);
2227
+
2228
+ const res1 = await server.inject('/foo');
2229
+ expect(res1.result).to.equal('foo');
2230
+
2231
+ const res2 = await server.inject('/bar');
2232
+ expect(res2.result).to.equal('bar');
2233
+ });
2234
+
2235
+ it('registers a plugin with routes path prefix and plugin root route', async () => {
2236
+
2237
+ const test = {
2238
+ name: 'test',
2239
+ register: function (srv, options) {
2240
+
2241
+ srv.route({
2242
+ method: 'GET',
2243
+ path: '/',
2244
+ handler: () => 'ok'
2245
+ });
2246
+ }
2247
+ };
2248
+
2249
+ const server = Hapi.server();
2250
+ await server.register(test, { routes: { prefix: '/xyz' } });
2251
+
2252
+ const res = await server.inject('/xyz');
2253
+ expect(res.result).to.equal('ok');
2254
+ });
2255
+
2256
+ it('ignores the type of the plugin value', async () => {
2257
+
2258
+ const a = function () { };
2259
+ a.plugin = {
2260
+ name: 'a',
2261
+ register: function (srv, options) {
2262
+
2263
+ srv.route({
2264
+ method: 'GET',
2265
+ path: '/',
2266
+ handler: () => 'ok'
2267
+ });
2268
+ }
2269
+ };
2270
+
2271
+ const server = Hapi.server();
2272
+ await server.register(a, { routes: { prefix: '/xyz' } });
2273
+
2274
+ const res = await server.inject('/xyz');
2275
+ expect(res.result).to.equal('ok');
2276
+ });
2277
+
2278
+ it('ignores unknown plugin properties', async () => {
2279
+
2280
+ const a = {
2281
+ name: 'a',
2282
+ register: function (srv, options) {
2283
+
2284
+ srv.route({
2285
+ method: 'GET',
2286
+ path: '/',
2287
+ handler: () => 'ok'
2288
+ });
2289
+ },
2290
+ other: {}
2291
+ };
2292
+
2293
+ const server = Hapi.server();
2294
+ await server.register(a);
2295
+ });
2296
+
2297
+ it('ignores unknown plugin properties (with options)', async () => {
2298
+
2299
+ const a = {
2300
+ name: 'a',
2301
+ register: function (srv, options) {
2302
+
2303
+ srv.route({
2304
+ method: 'GET',
2305
+ path: '/',
2306
+ handler: () => 'ok'
2307
+ });
2308
+ },
2309
+ other: {}
2310
+ };
2311
+
2312
+ const server = Hapi.server();
2313
+ await server.register({ plugin: a });
2314
+ });
2315
+
2316
+ it('registers a child plugin with parent routes path prefix', async () => {
2317
+
2318
+ const server = Hapi.server();
2319
+ await server.register(internals.plugins.child, { routes: { prefix: '/xyz' } });
2320
+
2321
+ const res = await server.inject('/xyz/test1');
2322
+ expect(res.result).to.equal('testing123');
2323
+ });
2324
+
2325
+ it('registers a child plugin with parent routes vhost prefix', async () => {
2326
+
2327
+ const server = Hapi.server();
2328
+ await server.register(internals.plugins.child, { routes: { vhost: 'example.com' } });
2329
+
2330
+ const res = await server.inject({ url: '/test1', headers: { host: 'example.com' } });
2331
+ expect(res.result).to.equal('testing123');
2332
+ });
2333
+
2334
+ it('registers a child plugin with parent routes path prefix and inner register prefix', async () => {
2335
+
2336
+ const server = Hapi.server();
2337
+ await server.register({ plugin: internals.plugins.child, options: { routes: { prefix: '/inner' } } }, { routes: { prefix: '/xyz' } });
2338
+
2339
+ const res = await server.inject('/xyz/inner/test1');
2340
+ expect(res.result).to.equal('testing123');
2341
+ });
2342
+
2343
+ it('registers a child plugin with parent routes vhost prefix and inner register vhost', async () => {
2344
+
2345
+ const server = Hapi.server();
2346
+ await server.register({ plugin: internals.plugins.child, options: { routes: { vhost: 'example.net' } } }, { routes: { vhost: 'example.com' } });
2347
+
2348
+ const res = await server.inject({ url: '/test1', headers: { host: 'example.com' } });
2349
+ expect(res.result).to.equal('testing123');
2350
+ });
2351
+
2352
+ it('registers a plugin with routes vhost', async () => {
2353
+
2354
+ const server = Hapi.server();
2355
+ await server.register(internals.plugins.test1, { routes: { vhost: 'example.com' } });
2356
+
2357
+ const res1 = await server.inject('/test1');
2358
+ expect(res1.statusCode).to.equal(404);
2359
+
2360
+ const res2 = await server.inject({ url: '/test1', headers: { host: 'example.com' } });
2361
+ expect(res2.result).to.equal('testing123');
2362
+ });
2363
+
2364
+ it('registers a plugin with routes vhost (plugin options)', async () => {
2365
+
2366
+ const server = Hapi.server();
2367
+ await server.register({ plugin: internals.plugins.test1, routes: { vhost: 'example.org' } }, { routes: { vhost: 'example.com' } });
2368
+
2369
+ const res1 = await server.inject('/test1');
2370
+ expect(res1.statusCode).to.equal(404);
2371
+
2372
+ const res2 = await server.inject({ url: '/test1', headers: { host: 'example.org' } });
2373
+ expect(res2.result).to.equal('testing123');
2374
+ });
2375
+
2376
+ it('sets multiple dependencies in one statement', async () => {
2377
+
2378
+ const a = {
2379
+ name: 'a',
2380
+ register: function (srv, options) {
2381
+
2382
+ srv.dependency(['b', 'c']);
2383
+ }
2384
+ };
2385
+
2386
+ const b = {
2387
+ name: 'b',
2388
+ register: Hoek.ignore
2389
+ };
2390
+
2391
+ const c = {
2392
+ name: 'c',
2393
+ register: Hoek.ignore
2394
+ };
2395
+
2396
+ const server = Hapi.server();
2397
+ await server.register(b);
2398
+ await server.register(c);
2399
+ await server.register(a);
2400
+ await server.initialize();
2401
+ });
2402
+
2403
+ it('sets multiple dependencies in one statement (versioned)', async () => {
2404
+
2405
+ const a = {
2406
+ name: 'a',
2407
+ version: '0.1.2',
2408
+ register: function (srv, options) {
2409
+
2410
+ srv.dependency({
2411
+ b: '1.x.x',
2412
+ c: '2.x.x'
2413
+ });
2414
+ }
2415
+ };
2416
+
2417
+ const b = {
2418
+ name: 'b',
2419
+ version: '1.2.3',
2420
+ register: Hoek.ignore
2421
+ };
2422
+
2423
+ const c = {
2424
+ name: 'c',
2425
+ version: '2.3.4',
2426
+ register: Hoek.ignore
2427
+ };
2428
+
2429
+ const server = Hapi.server();
2430
+ await server.register(b);
2431
+ await server.register(c);
2432
+ await server.register(a);
2433
+ await server.initialize();
2434
+ });
2435
+
2436
+ it('sets multiple dependencies in plugin (versioned)', async () => {
2437
+
2438
+ const a = {
2439
+ name: 'a',
2440
+ version: '0.1.2',
2441
+ dependencies: {
2442
+ b: '1.x.x',
2443
+ c: '2.x.x'
2444
+ },
2445
+ register: Hoek.ignore
2446
+ };
2447
+
2448
+ const b = {
2449
+ name: 'b',
2450
+ version: '1.2.3',
2451
+ register: Hoek.ignore
2452
+ };
2453
+
2454
+ const c = {
2455
+ name: 'c',
2456
+ version: '2.3.4',
2457
+ register: Hoek.ignore
2458
+ };
2459
+
2460
+ const server = Hapi.server();
2461
+ await server.register(b);
2462
+ await server.register(c);
2463
+ await server.register(a);
2464
+ await server.initialize();
2465
+ });
2466
+
2467
+ it('sets multiple dependencies in plugin', async () => {
2468
+
2469
+ const a = {
2470
+ name: 'a',
2471
+ dependencies: ['b', 'c'],
2472
+ register: Hoek.ignore
2473
+ };
2474
+
2475
+ const b = {
2476
+ name: 'b',
2477
+ register: Hoek.ignore
2478
+ };
2479
+
2480
+ const c = {
2481
+ name: 'c',
2482
+ register: Hoek.ignore
2483
+ };
2484
+
2485
+ const server = Hapi.server();
2486
+ await server.register(b);
2487
+ await server.register(c);
2488
+ await server.register(a);
2489
+ await server.initialize();
2490
+ });
2491
+
2492
+ it('sets multiple dependencies in multiple statements', async () => {
2493
+
2494
+ const a = {
2495
+ name: 'a',
2496
+ register: function (srv, options) {
2497
+
2498
+ srv.dependency('b');
2499
+ srv.dependency('c');
2500
+ }
2501
+ };
2502
+
2503
+ const b = {
2504
+ name: 'b',
2505
+ register: Hoek.ignore
2506
+ };
2507
+
2508
+ const c = {
2509
+ name: 'c',
2510
+ register: Hoek.ignore
2511
+ };
2512
+
2513
+ const server = Hapi.server();
2514
+ await server.register(b);
2515
+ await server.register(c);
2516
+ await server.register(a);
2517
+ await server.initialize();
2518
+ });
2519
+
2520
+ it('sets multiple dependencies in multiple locations', async () => {
2521
+
2522
+ const a = {
2523
+ name: 'a',
2524
+ dependencies: 'c',
2525
+ register: function (srv, options) {
2526
+
2527
+ srv.dependency('b');
2528
+ }
2529
+ };
2530
+
2531
+ const b = {
2532
+ name: 'b',
2533
+ register: Hoek.ignore
2534
+ };
2535
+
2536
+ const c = {
2537
+ name: 'c',
2538
+ register: Hoek.ignore
2539
+ };
2540
+
2541
+ const server = Hapi.server();
2542
+ await server.register(b);
2543
+ await server.register(c);
2544
+ await server.register(a);
2545
+ await server.initialize();
2546
+ });
2547
+
2548
+ it('register a plugin once per server', async () => {
2549
+
2550
+ let count = 0;
2551
+ const b = {
2552
+ name: 'b',
2553
+ register: function (srv, options) {
2554
+
2555
+ ++count;
2556
+ }
2557
+ };
2558
+
2559
+ const a = {
2560
+ name: 'a',
2561
+ register: function (srv, options) {
2562
+
2563
+ return srv.register(b, { once: true });
2564
+ }
2565
+ };
2566
+
2567
+ const server = Hapi.server();
2568
+ await server.register(b);
2569
+ await server.register(a);
2570
+ await server.initialize();
2571
+ expect(count).to.equal(1);
2572
+ });
2573
+
2574
+ it('register a plugin once (plugin)', async () => {
2575
+
2576
+ let count = 0;
2577
+ const b = {
2578
+ name: 'b',
2579
+ once: true,
2580
+ register: function (srv, options) {
2581
+
2582
+ ++count;
2583
+ }
2584
+ };
2585
+
2586
+ const a = {
2587
+ name: 'a',
2588
+ register: function (srv, options) {
2589
+
2590
+ return srv.register(b);
2591
+ }
2592
+ };
2593
+
2594
+ const server = Hapi.server();
2595
+ await server.register(b);
2596
+ await server.register(a);
2597
+ await server.initialize();
2598
+ expect(count).to.equal(1);
2599
+ });
2600
+
2601
+ it('throws when once used with plugin options', async () => {
2602
+
2603
+ const a = {
2604
+ name: 'a',
2605
+ register: Hoek.ignore
2606
+ };
2607
+
2608
+ const server = Hapi.server();
2609
+ await expect(server.register({ plugin: a, options: {}, once: true })).to.reject();
2610
+ });
2611
+
2612
+ it('throws when once is false', async () => {
2613
+
2614
+ const b = {
2615
+ name: 'b',
2616
+ register: Hoek.ignore
2617
+ };
2618
+
2619
+ const a = {
2620
+ name: 'a',
2621
+ register: function (srv, options) {
2622
+
2623
+ return srv.register(b);
2624
+ }
2625
+ };
2626
+
2627
+ const server = Hapi.server();
2628
+ await server.register(b);
2629
+ await expect(server.register(a)).to.reject(Error, 'Plugin b already registered');
2630
+ });
2631
+
2632
+ it('throws when dependencies is an object', async () => {
2633
+
2634
+ const a = {
2635
+ name: 'a',
2636
+ dependencies: { b: true },
2637
+ register: Hoek.ignore
2638
+ };
2639
+
2640
+ const server = Hapi.server();
2641
+ await expect(server.register(a)).to.reject();
2642
+ });
2643
+
2644
+ it('throws when dependencies contain something else than a string', async () => {
2645
+
2646
+ const a = {
2647
+ name: 'a',
2648
+ dependencies: [true],
2649
+ register: Hoek.ignore
2650
+ };
2651
+
2652
+ const server = Hapi.server();
2653
+ await expect(server.register(a)).to.reject();
2654
+ });
2655
+
2656
+ it('exposes server decorations to next register', async () => {
2657
+
2658
+ const server = Hapi.server();
2659
+
2660
+ const b = {
2661
+ name: 'b',
2662
+ register: function (srv, options) {
2663
+
2664
+ if (typeof srv.a !== 'function') {
2665
+ throw new Error('Missing decoration');
2666
+ }
2667
+ }
2668
+ };
2669
+
2670
+ const a = {
2671
+ name: 'a',
2672
+ register: function (srv, options) {
2673
+
2674
+ srv.decorate('server', 'a', () => {
2675
+
2676
+ return 'a';
2677
+ });
2678
+ }
2679
+ };
2680
+
2681
+ await server.register([a, b]);
2682
+ await server.initialize();
2683
+ });
2684
+
2685
+ it('exposes server decorations to dependency (dependency first)', async () => {
2686
+
2687
+ const server = Hapi.server();
2688
+
2689
+ const a = {
2690
+ name: 'a',
2691
+ register: function (srv, options) {
2692
+
2693
+ srv.decorate('server', 'a', () => {
2694
+
2695
+ return 'a';
2696
+ });
2697
+ }
2698
+ };
2699
+
2700
+ const b = {
2701
+ name: 'b',
2702
+ register: function (srv, options) {
2703
+
2704
+ const after = function (srv2) {
2705
+
2706
+ if (typeof srv2.a !== 'function') {
2707
+ throw new Error('Missing decoration');
2708
+ }
2709
+ };
2710
+
2711
+ srv.dependency('a', after);
2712
+ }
2713
+ };
2714
+
2715
+ await server.register([a, b]);
2716
+ await server.initialize();
2717
+ });
2718
+
2719
+ it('exposes server decorations to dependency (dependency second)', async () => {
2720
+
2721
+ const server = Hapi.server();
2722
+
2723
+ const a = {
2724
+ name: 'a',
2725
+ register: function (srv, options) {
2726
+
2727
+ srv.decorate('server', 'a', () => 'a');
2728
+ }
2729
+ };
2730
+
2731
+ const b = {
2732
+ name: 'b',
2733
+ register: function (srv, options) {
2734
+
2735
+ srv.realm.x = 1;
2736
+ const after = function (srv2) {
2737
+
2738
+ expect(srv2.realm.x).to.equal(1);
2739
+ if (typeof srv2.a !== 'function') {
2740
+ throw new Error('Missing decoration');
2741
+ }
2742
+ };
2743
+
2744
+ srv.dependency('a', after);
2745
+ }
2746
+ };
2747
+
2748
+ await server.register([b, a]);
2749
+ await server.initialize();
2750
+ });
2751
+
2752
+ it('exposes server decorations to next register when nested', async () => {
2753
+
2754
+ const server = Hapi.server();
2755
+
2756
+ const a = {
2757
+ name: 'a',
2758
+ register: function (srv, options) {
2759
+
2760
+ srv.decorate('server', 'a', () => {
2761
+
2762
+ return 'a';
2763
+ });
2764
+ }
2765
+ };
2766
+
2767
+ const b = {
2768
+ name: 'b',
2769
+ register: async function (srv, options) {
2770
+
2771
+ await srv.register(a);
2772
+ if (typeof srv.a !== 'function') {
2773
+ throw new Error('Missing decoration');
2774
+ }
2775
+ }
2776
+ };
2777
+
2778
+ await server.register([b]);
2779
+ await server.initialize();
2780
+ });
2781
+
2782
+ it('validates node version', async () => {
2783
+
2784
+ const test = {
2785
+ name: 'test',
2786
+ requirements: {
2787
+ node: '>=8.x.x'
2788
+ },
2789
+ register: function (srv, options) { }
2790
+ };
2791
+
2792
+ const server = Hapi.server();
2793
+ await expect(server.register(test)).to.not.reject();
2794
+ });
2795
+
2796
+ it('errors on invalid node version', async () => {
2797
+
2798
+ const test = {
2799
+ name: 'test',
2800
+ requirements: {
2801
+ node: '4.x.x'
2802
+ },
2803
+ register: function (srv, options) { }
2804
+ };
2805
+
2806
+ const server = Hapi.server();
2807
+ await expect(server.register(test)).to.reject(`Plugin test requires node version 4.x.x but found ${process.version}`);
2808
+ });
2809
+
2810
+ it('validates hapi version', async () => {
2811
+
2812
+ const test = {
2813
+ name: 'test',
2814
+ requirements: {
2815
+ hapi: '>=17.x.x'
2816
+ },
2817
+ register: function (srv, options) { }
2818
+ };
2819
+
2820
+ const server = Hapi.server();
2821
+ await expect(server.register(test)).to.not.reject();
2822
+ });
2823
+
2824
+ it('errors on invalid hapi version', async () => {
2825
+
2826
+ const test = {
2827
+ name: 'test',
2828
+ requirements: {
2829
+ hapi: '4.x.x'
2830
+ },
2831
+ register: function (srv, options) { }
2832
+ };
2833
+
2834
+ const server = Hapi.server();
2835
+ await expect(server.register(test)).to.reject(`Plugin test requires hapi version 4.x.x but found ${Pkg.version}`);
2836
+ });
2837
+
2838
+ it('errors on invalid plugin version', async () => {
2839
+
2840
+ const a = {
2841
+ name: 'a',
2842
+ version: '0.1.2',
2843
+ dependencies: {
2844
+ b: '3.x.x',
2845
+ c: '2.x.x'
2846
+ },
2847
+ register: Hoek.ignore
2848
+ };
2849
+
2850
+ const b = {
2851
+ name: 'b',
2852
+ version: '1.2.3',
2853
+ register: Hoek.ignore
2854
+ };
2855
+
2856
+ const c = {
2857
+ name: 'c',
2858
+ version: '2.3.4',
2859
+ register: Hoek.ignore
2860
+ };
2861
+
2862
+ const server = Hapi.server();
2863
+ await server.register(b);
2864
+ await server.register(c);
2865
+ await server.register(a);
2866
+ await expect(server.initialize()).to.reject('Plugin a requires b version 3.x.x but found 1.2.3');
2867
+ });
2868
+ });
2869
+
2870
+ describe('render()', () => {
2871
+
2872
+ it('renders view', async () => {
2873
+
2874
+ const server = Hapi.server();
2875
+ await server.register(Vision);
2876
+ server.views({
2877
+ engines: { html: Handlebars },
2878
+ path: __dirname + '/templates'
2879
+ });
2880
+
2881
+ const rendered = await server.render('test', { title: 'test', message: 'hapi' });
2882
+ expect(rendered).to.exist();
2883
+ expect(rendered).to.contain('hapi');
2884
+ });
2885
+ });
2886
+
2887
+ describe('views()', () => {
2888
+
2889
+ it('requires plugin with views', async () => {
2890
+
2891
+ const test = {
2892
+ name: 'test',
2893
+ register: function (srv, options) {
2894
+
2895
+ srv.path(__dirname);
2896
+
2897
+ const views = {
2898
+ engines: { 'html': Handlebars },
2899
+ path: './templates/plugin'
2900
+ };
2901
+
2902
+ srv.views(views);
2903
+ if (Object.keys(views).length !== 2) {
2904
+ throw new Error('plugin.view() modified options');
2905
+ }
2906
+
2907
+ srv.route([
2908
+ {
2909
+ path: '/view',
2910
+ method: 'GET',
2911
+ handler: (request, h) => h.view('test', { message: options.message })
2912
+ },
2913
+ {
2914
+ path: '/file',
2915
+ method: 'GET',
2916
+ handler: { file: './templates/plugin/test.html' }
2917
+ }
2918
+ ]);
2919
+
2920
+ const onRequest = (request, h) => {
2921
+
2922
+ if (request.path === '/ext') {
2923
+ return h.view('test', { message: 'grabbed' }).takeover();
2924
+ }
2925
+
2926
+ return h.continue;
2927
+ };
2928
+
2929
+ srv.ext('onRequest', onRequest);
2930
+ }
2931
+ };
2932
+
2933
+ const server = Hapi.server();
2934
+ await server.register([Inert, Vision]);
2935
+ await server.register({ plugin: test, options: { message: 'viewing it' } });
2936
+
2937
+ const res1 = await server.inject('/view');
2938
+ expect(res1.result).to.equal('<h1>viewing it</h1>');
2939
+
2940
+ const res2 = await server.inject('/file');
2941
+ expect(res2.result).to.equal('<h1>{{message}}</h1>');
2942
+
2943
+ const res3 = await server.inject('/ext');
2944
+ expect(res3.result).to.equal('<h1>grabbed</h1>');
2945
+ });
2946
+ });
2947
+ });
2948
+
2949
+
2950
+ internals.routesList = function (server) {
2951
+
2952
+ return server.table().filter((route) => route.method === 'get').map((route) => route.path);
2953
+ };
2954
+
2955
+
2956
+ internals.plugins = {
2957
+ auth: {
2958
+ name: 'auth',
2959
+ register: function (server, options) {
2960
+
2961
+ const scheme = function (srv, authOptions) {
2962
+
2963
+ const settings = Hoek.clone(authOptions);
2964
+
2965
+ return {
2966
+ authenticate: (request, h) => {
2967
+
2968
+ const req = request.raw.req;
2969
+ const authorization = req.headers.authorization;
2970
+ if (!authorization) {
2971
+ throw Boom.unauthorized(null, 'Basic');
2972
+ }
2973
+
2974
+ const parts = authorization.split(/\s+/);
2975
+
2976
+ if (parts[0] &&
2977
+ parts[0].toLowerCase() !== 'basic') {
2978
+
2979
+ throw Boom.unauthorized(null, 'Basic');
2980
+ }
2981
+
2982
+ if (parts.length !== 2) {
2983
+ throw Boom.badRequest('Bad HTTP authentication header format', 'Basic');
2984
+ }
2985
+
2986
+ const credentialsParts = Buffer.from(parts[1], 'base64').toString().split(':');
2987
+ if (credentialsParts.length !== 2) {
2988
+ throw Boom.badRequest('Bad header internal syntax', 'Basic');
2989
+ }
2990
+
2991
+ const username = credentialsParts[0];
2992
+ const password = credentialsParts[1];
2993
+
2994
+ const { isValid, credentials } = settings.validateFunc(username, password);
2995
+ if (!isValid) {
2996
+ return h.unauthenticated(Boom.unauthorized('Bad username or password', 'Basic'), { credentials });
2997
+ }
2998
+
2999
+ return h.authenticated({ credentials });
3000
+ }
3001
+ };
3002
+ };
3003
+
3004
+ server.auth.scheme('basic', scheme);
3005
+
3006
+ const loadUser = function (username, password) {
3007
+
3008
+ if (username === 'john') {
3009
+ return { isValid: password === '12345', credentials: { user: 'john' } };
3010
+ }
3011
+
3012
+ return { isValid: false };
3013
+ };
3014
+
3015
+ server.auth.strategy('basic', 'basic', { validateFunc: loadUser });
3016
+ server.auth.default('basic');
3017
+
3018
+ server.auth.scheme('special', () => {
3019
+
3020
+ return { authenticate: function () { } };
3021
+ });
3022
+
3023
+ server.auth.strategy('special', 'special', {});
3024
+ }
3025
+ },
3026
+ child: {
3027
+ name: 'child',
3028
+ register: function (server, options) {
3029
+
3030
+ if (options.routes) {
3031
+ return server.register(internals.plugins.test1, options);
3032
+ }
3033
+
3034
+ return server.register(internals.plugins.test1);
3035
+ }
3036
+ },
3037
+ deps1: {
3038
+ name: 'deps1',
3039
+ register: function (server, options) {
3040
+
3041
+ const after = function (srv) {
3042
+
3043
+ srv.expose('breaking', srv.plugins.deps2.breaking);
3044
+ };
3045
+
3046
+ server.dependency('deps2', after);
3047
+
3048
+ const onRequest = (request, h) => {
3049
+
3050
+ request.app.deps = request.app.deps || '|';
3051
+ request.app.deps += '1|';
3052
+ return h.continue;
3053
+ };
3054
+
3055
+ server.ext('onRequest', onRequest, { after: 'deps3' });
3056
+ }
3057
+ },
3058
+ deps2: {
3059
+ name: 'deps2',
3060
+ register: function (server, options) {
3061
+
3062
+ const onRequest = (request, h) => {
3063
+
3064
+ request.app.deps = request.app.deps || '|';
3065
+ request.app.deps += '2|';
3066
+ return h.continue;
3067
+ };
3068
+
3069
+ server.ext('onRequest', onRequest, { after: 'deps3', before: 'deps1' });
3070
+ server.expose('breaking', 'bad');
3071
+ }
3072
+ },
3073
+ deps3: {
3074
+ name: 'deps3',
3075
+ register: function (server, options) {
3076
+
3077
+ const onRequest = (request, h) => {
3078
+
3079
+ request.app.deps = request.app.deps || '|';
3080
+ request.app.deps += '3|';
3081
+ return h.continue;
3082
+ };
3083
+
3084
+ server.ext('onRequest', onRequest);
3085
+ }
3086
+ },
3087
+ test1: {
3088
+ name: 'test1',
3089
+ version: '1.0.0',
3090
+ register: function (server, options) {
3091
+
3092
+ const handler = (request) => {
3093
+
3094
+ return 'testing123' + ((server.settings.app && server.settings.app.my) || '');
3095
+ };
3096
+
3097
+ server.route({ path: '/test1', method: 'GET', handler });
3098
+
3099
+ server.expose({
3100
+ add: function (a, b) {
3101
+
3102
+ return a + b;
3103
+ }
3104
+ });
3105
+
3106
+ const glue = function (a, b) {
3107
+
3108
+ return a + b;
3109
+ };
3110
+
3111
+ server.expose('glue', glue);
3112
+ server.expose('prefix', server.realm.modifiers.route.prefix);
3113
+ }
3114
+ },
3115
+ test2: {
3116
+ pkg: {
3117
+ name: 'test2',
3118
+ version: '1.0.0'
3119
+ },
3120
+ name: 'test2',
3121
+ register: function (server, options) {
3122
+
3123
+ server.route({
3124
+ path: '/test2',
3125
+ method: 'GET',
3126
+ handler: () => 'testing123'
3127
+ });
3128
+
3129
+ server.log('test', 'abc');
3130
+ }
3131
+ }
3132
+ };