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/lib/request.js ADDED
@@ -0,0 +1,751 @@
1
+ 'use strict';
2
+
3
+ const Querystring = require('querystring');
4
+ const Url = require('url');
5
+
6
+ const Boom = require('@hapi/boom');
7
+ const Bounce = require('@hapi/bounce');
8
+ const Hoek = require('@hapi/hoek');
9
+ const Podium = require('@hapi/podium');
10
+
11
+ const Cors = require('./cors');
12
+ const Toolkit = require('./toolkit');
13
+ const Transmit = require('./transmit');
14
+
15
+
16
+ const internals = {
17
+ events: Podium.validate(['finish', { name: 'peek', spread: true }, 'disconnect']),
18
+ reserved: ['server', 'url', 'query', 'path', 'method', 'mime', 'setUrl', 'setMethod', 'headers', 'id', 'app', 'plugins', 'route', 'auth', 'pre', 'preResponses', 'info', 'isInjected', 'orig', 'params', 'paramsArray', 'payload', 'state', 'jsonp', 'response', 'raw', 'domain', 'log', 'logs', 'generateResponse']
19
+ };
20
+
21
+
22
+ exports = module.exports = internals.Request = class {
23
+
24
+ constructor(server, req, res, options) {
25
+
26
+ this._allowInternals = !!options.allowInternals;
27
+ this._closed = false; // true once the response has closed (esp. early) and will not emit any more events
28
+ this._core = server._core;
29
+ this._entity = null; // Entity information set via h.entity()
30
+ this._eventContext = { request: this };
31
+ this._events = null; // Assigned an emitter when request.events is accessed
32
+ this._expectContinue = !!options.expectContinue;
33
+ this._isInjected = !!options.isInjected;
34
+ this._isPayloadPending = !!(req.headers['content-length'] || req.headers['transfer-encoding']); // Changes to false when incoming payload fully processed
35
+ this._isReplied = false; // true when response processing started
36
+ this._route = this._core.router.specials.notFound.route; // Used prior to routing (only settings are used, not the handler)
37
+ this._serverTimeoutId = null;
38
+ this._states = {};
39
+ this._url = null;
40
+ this._urlError = null;
41
+
42
+ this.app = options.app ? Object.assign({}, options.app) : {}; // Place for application-specific state without conflicts with hapi, should not be used by plugins (shallow cloned)
43
+ this.headers = req.headers;
44
+ this.jsonp = null;
45
+ this.logs = [];
46
+ this.method = req.method.toLowerCase();
47
+ this.mime = null;
48
+ this.orig = {};
49
+ this.params = null;
50
+ this.paramsArray = null; // Array of path parameters in path order
51
+ this.path = null;
52
+ this.payload = undefined;
53
+ this.plugins = options.plugins ? Object.assign({}, options.plugins) : {}; // Place for plugins to store state without conflicts with hapi, should be namespaced using plugin name (shallow cloned)
54
+ this.pre = {}; // Pre raw values
55
+ this.preResponses = {}; // Pre response values
56
+ this.raw = { req, res };
57
+ this.response = null;
58
+ this.route = this._route.public;
59
+ this.query = null;
60
+ this.server = server;
61
+ this.state = null;
62
+
63
+ this.info = new internals.Info(this);
64
+
65
+ this.auth = {
66
+ isAuthenticated: false,
67
+ isAuthorized: false,
68
+ isInjected: options.auth ? true : false,
69
+ [internals.Request.symbols.authPayload]: options.auth && options.auth.payload !== undefined ? options.auth.payload : true,
70
+ credentials: options.auth ? options.auth.credentials : null, // Special keys: 'app', 'user', 'scope'
71
+ artifacts: options.auth && options.auth.artifacts || null, // Scheme-specific artifacts
72
+ strategy: options.auth ? options.auth.strategy : null,
73
+ mode: null,
74
+ error: null
75
+ };
76
+
77
+ // Parse request url
78
+
79
+ this._initializeUrl();
80
+ }
81
+
82
+ static generate(server, req, res, options) {
83
+
84
+ const request = new server._core.Request(server, req, res, options);
85
+
86
+ // Decorate
87
+
88
+ if (server._core.decorations.requestApply) {
89
+ for (const [property, assignment] of server._core.decorations.requestApply.entries()) {
90
+ request[property] = assignment(request);
91
+ }
92
+ }
93
+
94
+ request._listen();
95
+ return request;
96
+ }
97
+
98
+ get events() {
99
+
100
+ if (!this._events) {
101
+ this._events = new Podium(internals.events);
102
+ }
103
+
104
+ return this._events;
105
+ }
106
+
107
+ get isInjected() {
108
+
109
+ return this._isInjected;
110
+ }
111
+
112
+ get url() {
113
+
114
+ if (this._urlError) {
115
+ return null;
116
+ }
117
+
118
+ if (this._url) {
119
+ return this._url;
120
+ }
121
+
122
+ return this._parseUrl(this.raw.req.url, this._core.settings.router);
123
+ }
124
+
125
+ _initializeUrl() {
126
+
127
+ try {
128
+ this._setUrl(this.raw.req.url, this._core.settings.router.stripTrailingSlash, { fast: true });
129
+ }
130
+ catch (err) {
131
+ this.path = this.raw.req.url;
132
+ this.query = {};
133
+
134
+ this._urlError = Boom.boomify(err, { statusCode: 400, override: false });
135
+ }
136
+ }
137
+
138
+ setUrl(url, stripTrailingSlash) {
139
+
140
+ Hoek.assert(this.params === null, 'Cannot change request URL after routing');
141
+
142
+ if (url instanceof Url.URL) {
143
+ url = url.href;
144
+ }
145
+
146
+ Hoek.assert(typeof url === 'string', 'Url must be a string or URL object');
147
+
148
+ this._setUrl(url, stripTrailingSlash, { fast: false });
149
+ }
150
+
151
+ _setUrl(source, stripTrailingSlash, { fast }) {
152
+
153
+ const url = this._parseUrl(source, { stripTrailingSlash, _fast: fast });
154
+ this.query = this._parseQuery(url.searchParams);
155
+ this.path = url.pathname;
156
+ }
157
+
158
+ _parseUrl(source, options) {
159
+
160
+ if (source[0] === '/') {
161
+
162
+ // Relative URL
163
+
164
+ if (options._fast) {
165
+ const url = {
166
+ pathname: source,
167
+ searchParams: ''
168
+ };
169
+
170
+ const q = source.indexOf('?');
171
+ const h = source.indexOf('#');
172
+
173
+ if (q !== -1 &&
174
+ (h === -1 || q < h)) {
175
+
176
+ url.pathname = source.slice(0, q);
177
+ const query = h === -1 ? source.slice(q + 1) : source.slice(q + 1, h);
178
+ url.searchParams = Querystring.parse(query);
179
+ }
180
+ else {
181
+ url.pathname = h === -1 ? source : source.slice(0, h);
182
+ }
183
+
184
+ this._normalizePath(url, options);
185
+ return url;
186
+ }
187
+
188
+ this._url = new Url.URL(`${this._core.info.protocol}://${this.info.host || `${this._core.info.host}:${this._core.info.port}`}${source}`);
189
+ }
190
+ else {
191
+
192
+ // Absolute URI (proxied)
193
+
194
+ this._url = new Url.URL(source);
195
+ this.info.hostname = this._url.hostname;
196
+ this.info.host = this._url.host;
197
+ }
198
+
199
+ this._normalizePath(this._url, options);
200
+ this._urlError = null;
201
+
202
+ return this._url;
203
+ }
204
+
205
+ _normalizePath(url, options) {
206
+
207
+ let path = this._core.router.normalize(url.pathname);
208
+
209
+ if (options.stripTrailingSlash &&
210
+ path.length > 1 &&
211
+ path[path.length - 1] === '/') {
212
+
213
+ path = path.slice(0, -1);
214
+ }
215
+
216
+ url.pathname = path;
217
+ }
218
+
219
+ _parseQuery(searchParams) {
220
+
221
+ let query = Object.create(null);
222
+
223
+ // Flatten map
224
+
225
+ if (searchParams instanceof Url.URLSearchParams) {
226
+ for (let [key, value] of searchParams) {
227
+ const entry = query[key];
228
+ if (entry !== undefined) {
229
+ value = [].concat(entry, value);
230
+ }
231
+
232
+ query[key] = value;
233
+ }
234
+ }
235
+ else {
236
+ query = Object.assign(query, searchParams);
237
+ }
238
+
239
+ // Custom parser
240
+
241
+ const parser = this._core.settings.query.parser;
242
+ if (parser) {
243
+ query = parser(query);
244
+ if (!query ||
245
+ typeof query !== 'object') {
246
+
247
+ throw Boom.badImplementation('Parsed query must be an object');
248
+ }
249
+ }
250
+
251
+ return query;
252
+ }
253
+
254
+ setMethod(method) {
255
+
256
+ Hoek.assert(this.params === null, 'Cannot change request method after routing');
257
+ Hoek.assert(method && typeof method === 'string', 'Missing method');
258
+
259
+ this.method = method.toLowerCase();
260
+ }
261
+
262
+ active() {
263
+
264
+ return !!this._eventContext.request;
265
+ }
266
+
267
+ async _execute() {
268
+
269
+ this.info.acceptEncoding = this._core.compression.accept(this);
270
+
271
+ try {
272
+ await this._onRequest();
273
+ }
274
+ catch (err) {
275
+ Bounce.rethrow(err, 'system');
276
+ return this._reply(err);
277
+ }
278
+
279
+ this._lookup();
280
+ this._setTimeouts();
281
+ await this._lifecycle();
282
+ this._reply();
283
+ }
284
+
285
+ async _onRequest() {
286
+
287
+ // onRequest (can change request method and url)
288
+
289
+ if (this._core.extensions.route.onRequest.nodes) {
290
+ const response = await this._invoke(this._core.extensions.route.onRequest);
291
+ if (response) {
292
+ if (!internals.skip(response)) {
293
+ throw Boom.badImplementation('onRequest extension methods must return an error, a takeover response, or a continue signal');
294
+ }
295
+
296
+ throw response;
297
+ }
298
+ }
299
+
300
+ // Validate path
301
+
302
+ if (this._urlError) {
303
+ throw this._urlError;
304
+ }
305
+ }
306
+
307
+ _listen() {
308
+
309
+ if (this._isPayloadPending) {
310
+ this.raw.req.on('end', internals.event.bind(this.raw.req, this._eventContext, 'end'));
311
+ }
312
+
313
+ this.raw.res.on('close', internals.event.bind(this.raw.res, this._eventContext, 'close'));
314
+ this.raw.req.on('error', internals.event.bind(this.raw.req, this._eventContext, 'error'));
315
+ this.raw.req.on('aborted', internals.event.bind(this.raw.req, this._eventContext, 'abort'));
316
+ this.raw.res.once('close', internals.closed.bind(this.raw.res, this));
317
+ }
318
+
319
+ _lookup() {
320
+
321
+ const match = this._core.router.route(this.method, this.path, this.info.hostname);
322
+ if (!match.route.settings.isInternal ||
323
+ this._allowInternals) {
324
+
325
+ this._route = match.route;
326
+ this.route = this._route.public;
327
+ }
328
+
329
+ this.params = match.params || {};
330
+ this.paramsArray = match.paramsArray || [];
331
+
332
+ if (this.route.settings.cors) {
333
+ this.info.cors = {
334
+ isOriginMatch: Cors.matchOrigin(this.headers.origin, this.route.settings.cors)
335
+ };
336
+ }
337
+ }
338
+
339
+ _setTimeouts() {
340
+
341
+ if (this.raw.req.socket &&
342
+ this.route.settings.timeout.socket !== undefined) {
343
+
344
+ this.raw.req.socket.setTimeout(this.route.settings.timeout.socket || 0); // Value can be false or positive
345
+ }
346
+
347
+ let serverTimeout = this.route.settings.timeout.server;
348
+ if (!serverTimeout) {
349
+ return;
350
+ }
351
+
352
+ const elapsed = Date.now() - this.info.received;
353
+ serverTimeout = Math.floor(serverTimeout - elapsed); // Calculate the timeout from when the request was constructed
354
+
355
+ if (serverTimeout <= 0) {
356
+ internals.timeoutReply(this, serverTimeout);
357
+ return;
358
+ }
359
+
360
+ this._serverTimeoutId = setTimeout(internals.timeoutReply, serverTimeout, this, serverTimeout);
361
+ }
362
+
363
+ async _lifecycle() {
364
+
365
+ for (const func of this._route._cycle) {
366
+ if (this._isReplied) {
367
+ return;
368
+ }
369
+
370
+ try {
371
+ var response = await (typeof func === 'function' ? func(this) : this._invoke(func));
372
+ }
373
+ catch (err) {
374
+ Bounce.rethrow(err, 'system');
375
+ response = this._core.Response.wrap(err, this);
376
+ }
377
+
378
+ if (!response ||
379
+ response === Toolkit.symbols.continue) { // Continue
380
+
381
+ continue;
382
+ }
383
+
384
+ if (!internals.skip(response)) {
385
+ response = Boom.badImplementation('Lifecycle methods called before the handler can only return an error, a takeover response, or a continue signal');
386
+ }
387
+
388
+ this._setResponse(response);
389
+ return;
390
+ }
391
+ }
392
+
393
+ async _invoke(event, options = {}) {
394
+
395
+ for (const ext of event.nodes) {
396
+ const realm = ext.realm;
397
+ const bind = ext.bind || realm.settings.bind;
398
+ const response = await this._core.toolkit.execute(ext.func, this, { bind, realm, timeout: ext.timeout, name: event.type, ignoreResponse: options.ignoreResponse });
399
+
400
+ if (options.ignoreResponse) {
401
+ if (Boom.isBoom(response)) {
402
+ this._log(['ext', 'error'], response);
403
+ }
404
+
405
+ continue;
406
+ }
407
+
408
+ if (response === Toolkit.symbols.continue) {
409
+ continue;
410
+ }
411
+
412
+ if (internals.skip(response) ||
413
+ this.response === null) {
414
+
415
+ return response;
416
+ }
417
+
418
+ this._setResponse(response);
419
+ }
420
+ }
421
+
422
+ async _reply(exit) {
423
+
424
+ if (this._isReplied) { // Prevent any future responses to this request
425
+ return;
426
+ }
427
+
428
+ this._isReplied = true;
429
+
430
+ if (this._serverTimeoutId) {
431
+ clearTimeout(this._serverTimeoutId);
432
+ }
433
+
434
+ if (exit) { // Can be a valid response or error (if returned from an ext, already handled because this.response is also set)
435
+ this._setResponse(this._core.Response.wrap(exit, this)); // Wrap to ensure any object thrown is always a valid Boom or Response object
436
+ }
437
+
438
+ if (!this._eventContext.request) {
439
+ this._finalize();
440
+ return;
441
+ }
442
+
443
+ if (typeof this.response === 'symbol') { // close or abandon
444
+ this._abort();
445
+ return;
446
+ }
447
+
448
+ await this._postCycle();
449
+
450
+ if (!this._eventContext.request ||
451
+ typeof this.response === 'symbol') { // close or abandon
452
+
453
+ this._abort();
454
+ return;
455
+ }
456
+
457
+ await Transmit.send(this);
458
+ this._finalize();
459
+ }
460
+
461
+ async _postCycle() {
462
+
463
+ for (const func of this._route._postCycle) {
464
+ if (!this._eventContext.request) {
465
+ return;
466
+ }
467
+
468
+ try {
469
+ var response = await (typeof func === 'function' ? func(this) : this._invoke(func));
470
+ }
471
+ catch (err) {
472
+ Bounce.rethrow(err, 'system');
473
+ response = this._core.Response.wrap(err, this);
474
+ }
475
+
476
+ if (response &&
477
+ response !== Toolkit.symbols.continue) { // Continue
478
+
479
+ this._setResponse(response);
480
+ }
481
+ }
482
+ }
483
+
484
+ _abort() {
485
+
486
+ if (this.response === Toolkit.symbols.close) {
487
+ this.raw.res.end(); // End the response in case it wasn't already closed
488
+ }
489
+
490
+ this._finalize();
491
+ }
492
+
493
+ _finalize() {
494
+
495
+ this._eventContext.request = null; // Disable req events
496
+
497
+ if (!Boom.isBoom(this.response)) {
498
+ if (this.response.statusCode === 500 &&
499
+ this.response._error) {
500
+
501
+ const tags = this.response._error.isDeveloperError ? ['internal', 'implementation', 'error'] : ['internal', 'error'];
502
+ this._log(tags, this.response._error, 'error');
503
+ }
504
+
505
+ if (this.response._close) {
506
+ this.response._close();
507
+ }
508
+ }
509
+
510
+ this.info.completed = Date.now();
511
+
512
+ this._core.events.emit('response', this);
513
+
514
+ if (this._route._extensions.onPostResponse.nodes) {
515
+ this._invoke(this._route._extensions.onPostResponse, { ignoreResponse: true });
516
+ }
517
+ }
518
+
519
+ _setResponse(response) {
520
+
521
+ if (this.response &&
522
+ !this.response.isBoom &&
523
+ this.response !== response &&
524
+ this.response.source !== response.source) {
525
+
526
+ this.response._close();
527
+ }
528
+
529
+ if (this.info.completed) {
530
+ if (response._close) {
531
+ response._close();
532
+ }
533
+
534
+ return;
535
+ }
536
+
537
+ this.response = response;
538
+ }
539
+
540
+ _setState(name, value, options) {
541
+
542
+ const state = { name, value };
543
+ if (options) {
544
+ Hoek.assert(!options.autoValue, 'Cannot set autoValue directly in a response');
545
+ state.options = Hoek.clone(options);
546
+ }
547
+
548
+ this._states[name] = state;
549
+ }
550
+
551
+ _clearState(name, options = {}) {
552
+
553
+ const state = { name };
554
+
555
+ state.options = Hoek.clone(options);
556
+ state.options.ttl = 0;
557
+
558
+ this._states[name] = state;
559
+ }
560
+
561
+ _tap() {
562
+
563
+ if (!this._events) {
564
+ return null;
565
+ }
566
+
567
+ if (this._events.hasListeners('peek') ||
568
+ this._events.hasListeners('finish')) {
569
+
570
+ return new this._core.Response.Peek(this._events);
571
+ }
572
+
573
+ return null;
574
+ }
575
+
576
+ log(tags, data) {
577
+
578
+ return this._log(tags, data, 'app');
579
+ }
580
+
581
+ _log(tags, data, channel = 'internal') {
582
+
583
+ if (!this._core.events.hasListeners('request') &&
584
+ !this.route.settings.log.collect) {
585
+
586
+ return;
587
+ }
588
+
589
+ if (!Array.isArray(tags)) {
590
+ tags = [tags];
591
+ }
592
+
593
+ const timestamp = Date.now();
594
+ const field = data instanceof Error ? 'error' : 'data';
595
+
596
+ let event = [this, { request: this.info.id, timestamp, tags, [field]: data, channel }];
597
+ if (typeof data === 'function') {
598
+ event = () => [this, { request: this.info.id, timestamp, tags, data: data(), channel }];
599
+ }
600
+
601
+ if (this.route.settings.log.collect) {
602
+ if (typeof data === 'function') {
603
+ event = event();
604
+ }
605
+
606
+ this.logs.push(event[1]);
607
+ }
608
+
609
+ this._core.events.emit({ name: 'request', channel, tags }, event);
610
+ }
611
+
612
+ generateResponse(source, options) {
613
+
614
+ return new this._core.Response(source, this, options);
615
+ }
616
+ };
617
+
618
+
619
+ internals.Request.reserved = internals.reserved;
620
+
621
+ internals.Request.symbols = {
622
+ authPayload: Symbol('auth.payload')
623
+ };
624
+
625
+ internals.Info = class {
626
+
627
+ constructor(request) {
628
+
629
+ this._request = request;
630
+
631
+ const req = request.raw.req;
632
+ const host = req.headers.host ? req.headers.host.trim() : '';
633
+ const received = Date.now();
634
+
635
+ this.received = received;
636
+ this.referrer = req.headers.referrer || req.headers.referer || '';
637
+ this.host = host;
638
+ this.hostname = host.split(':')[0];
639
+ this.id = `${received}:${request._core.info.id}:${request._core._counter()}`;
640
+
641
+ this._remoteAddress = null;
642
+ this._remotePort = null;
643
+
644
+ // Assigned later
645
+
646
+ this.acceptEncoding = null;
647
+ this.cors = null;
648
+ this.responded = 0;
649
+ this.completed = 0;
650
+
651
+ if (request._core.settings.info.remote) {
652
+ this.remoteAddress;
653
+ this.remotePort;
654
+ }
655
+ }
656
+
657
+ get remoteAddress() {
658
+
659
+ if (!this._remoteAddress) {
660
+ this._remoteAddress = this._request.raw.req.connection.remoteAddress;
661
+ }
662
+
663
+ return this._remoteAddress;
664
+ }
665
+
666
+ get remotePort() {
667
+
668
+ if (this._remotePort === null) {
669
+ this._remotePort = this._request.raw.req.connection.remotePort || '';
670
+ }
671
+
672
+ return this._remotePort;
673
+ }
674
+
675
+ toJSON() {
676
+
677
+ return {
678
+ acceptEncoding: this.acceptEncoding,
679
+ completed: this.completed,
680
+ cors: this.cors,
681
+ host: this.host,
682
+ hostname: this.hostname,
683
+ id: this.id,
684
+ received: this.received,
685
+ referrer: this.referrer,
686
+ remoteAddress: this.remoteAddress,
687
+ remotePort: this.remotePort,
688
+ responded: this.responded
689
+ };
690
+ }
691
+ };
692
+
693
+
694
+ internals.closed = function (request) {
695
+
696
+ request._closed = true;
697
+ };
698
+
699
+ internals.event = function ({ request }, event, err) {
700
+
701
+ if (!request) {
702
+ return;
703
+ }
704
+
705
+ request._isPayloadPending = false;
706
+
707
+ if (event === 'close' &&
708
+ request.raw.res.finished) {
709
+
710
+ return;
711
+ }
712
+
713
+ if (event === 'end') {
714
+ return;
715
+ }
716
+
717
+ request._log(err ? ['request', 'error'] : ['request', 'error', event], err);
718
+
719
+ if (event === 'error') {
720
+ return;
721
+ }
722
+
723
+ request._eventContext.request = null;
724
+
725
+ if (event === 'abort') {
726
+
727
+ // Calling _reply() means that the abort is applied immediately, unless the response has already
728
+ // called _reply(), in which case this call is ignored and the transmit logic is responsible for
729
+ // handling the abort.
730
+
731
+ request._reply(new Boom.Boom('Request aborted', { statusCode: request.route.settings.response.disconnectStatusCode, data: request.response }));
732
+
733
+ if (request._events) {
734
+ request._events.emit('disconnect');
735
+ }
736
+ }
737
+ };
738
+
739
+
740
+ internals.timeoutReply = function (request, timeout) {
741
+
742
+ const elapsed = Date.now() - request.info.received;
743
+ request._log(['request', 'server', 'timeout', 'error'], { timeout, elapsed });
744
+ request._reply(Boom.serverUnavailable());
745
+ };
746
+
747
+
748
+ internals.skip = function (response) {
749
+
750
+ return response.isBoom || response._takeover || typeof response === 'symbol';
751
+ };