@hapi/hapi
Advanced tools
Comparing version 18.3.2 to 18.4.0
@@ -80,5 +80,10 @@ 'use strict'; | ||
if (response.settings.compressed) { | ||
response.headers['content-encoding'] = response.settings.compressed; | ||
return null; | ||
} | ||
const request = response.request; | ||
if (!request._core.settings.compression || | ||
(length !== null && length < request._core.settings.compression.minBytes)) { | ||
length !== null && length < request._core.settings.compression.minBytes) { | ||
@@ -99,3 +104,3 @@ return null; | ||
return (request.info.acceptEncoding === 'identity' ? null : request.info.acceptEncoding); | ||
return request.info.acceptEncoding === 'identity' ? null : request.info.acceptEncoding; | ||
} | ||
@@ -102,0 +107,0 @@ |
@@ -80,2 +80,3 @@ 'use strict'; | ||
this.sockets = null; // Track open sockets for graceful shutdown | ||
this.actives = new WeakMap(); // Active requests being processed | ||
this.started = false; | ||
@@ -123,3 +124,3 @@ this.states = new Statehood.Definitions(this.settings.state); | ||
const data = event.error || event.data; | ||
console.error('Debug:', event.tags.join(', '), (data ? '\n ' + (data.stack || (typeof data === 'object' ? Hoek.stringify(data) : data)) : '')); | ||
console.error('Debug:', event.tags.join(', '), data ? '\n ' + (data.stack || (typeof data === 'object' ? Hoek.stringify(data) : data)) : ''); | ||
}; | ||
@@ -414,3 +415,3 @@ | ||
if (!connection._isHapiProcessing) { | ||
if (!this.actives.has(connection)) { | ||
connection.end(); | ||
@@ -468,6 +469,10 @@ } | ||
// Create request | ||
const request = Request.generate(this.root, req, res, options); | ||
// Track socket request processing state | ||
if (req.socket) { | ||
req.socket._isHapiProcessing = true; | ||
this.actives.set(req.socket, request); | ||
const env = { core: this, req }; | ||
@@ -477,6 +482,2 @@ res.on('finish', internals.onFinish.bind(res, env)); | ||
// Create request | ||
const request = Request.generate(this.root, req, res, options); | ||
// Check load | ||
@@ -510,4 +511,12 @@ | ||
if (socket.writable) { | ||
socket.end(internals.badRequestResponse); | ||
if (socket.readable) { | ||
const request = this.actives.get(socket); | ||
if (request) { | ||
const error = Boom.badRequest(); | ||
error.output.headers = { connection: 'close' }; | ||
request._reply(error); | ||
} | ||
else { | ||
socket.end(internals.badRequestResponse); | ||
} | ||
} | ||
@@ -532,3 +541,3 @@ else { | ||
this.info.port = address.port; | ||
this.info.uri = (this.settings.uri || (this.info.protocol + '://' + this.info.host + ':' + this.info.port)); | ||
this.info.uri = this.settings.uri || this.info.protocol + '://' + this.info.host + ':' + this.info.port; | ||
} | ||
@@ -589,3 +598,3 @@ | ||
const timestamp = Date.now(); | ||
const field = (data instanceof Error ? 'error' : 'data'); | ||
const field = data instanceof Error ? 'error' : 'data'; | ||
@@ -645,3 +654,3 @@ let event = { timestamp, tags, [field]: data, channel }; | ||
req.socket._isHapiProcessing = false; | ||
core.actives.delete(req.socket); | ||
if (!core.started) { | ||
@@ -648,0 +657,0 @@ req.socket.end(); |
@@ -183,4 +183,9 @@ 'use strict'; | ||
if (Response.unmodified(request, entity)) { | ||
const etag = Response.unmodified(request, entity); | ||
if (etag) { | ||
response.code(304); | ||
if (etag !== true) { // Override etag with incoming weak match | ||
response.headers.etag = etag; | ||
} | ||
} | ||
@@ -187,0 +192,0 @@ }; |
@@ -0,0 +0,0 @@ 'use strict'; |
@@ -38,3 +38,3 @@ 'use strict'; | ||
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) | ||
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) | ||
this.headers = req.headers; | ||
@@ -51,3 +51,3 @@ this.info = internals.info(this._core, req); | ||
this.payload = null; | ||
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) | ||
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) | ||
this.pre = {}; // Pre raw values | ||
@@ -137,5 +137,5 @@ this.preResponses = {}; // Pre response values | ||
const base = (url[0] === '/' ? `${this._core.info.protocol}://${this.info.host || `${this._core.info.host}:${this._core.info.port}`}` : undefined); | ||
const base = url[0] === '/' ? `${this._core.info.protocol}://${this.info.host || `${this._core.info.host}:${this._core.info.port}`}` : ''; | ||
url = new Url.URL(url, base); | ||
url = new Url.URL(base + url); | ||
@@ -502,3 +502,9 @@ // Apply path modifications | ||
return (this._events.hasListeners('finish') || this._events.hasListeners('peek') ? new Response.Peek(this._events) : null); | ||
if (this._events.hasListeners('peek') || | ||
this._events.hasListeners('finish')) { | ||
return new Response.Peek(this._events); | ||
} | ||
return null; | ||
} | ||
@@ -524,3 +530,3 @@ | ||
const timestamp = Date.now(); | ||
const field = (data instanceof Error ? 'error' : 'data'); | ||
const field = data instanceof Error ? 'error' : 'data'; | ||
@@ -527,0 +533,0 @@ let event = [this, { request: this.info.id, timestamp, tags, [field]: data, channel }]; |
@@ -41,9 +41,10 @@ 'use strict'; | ||
this.settings = { | ||
charset: 'utf-8', // '-' required by IANA | ||
compressed: null, | ||
encoding: 'utf8', | ||
charset: 'utf-8', // '-' required by IANA | ||
message: null, | ||
passThrough: true, | ||
stringify: null, // JSON.stringify options | ||
ttl: null, | ||
stringify: null, // JSON.stringify options | ||
passThrough: true, | ||
varyEtag: false, | ||
message: null | ||
varyEtag: false | ||
}; | ||
@@ -54,3 +55,2 @@ | ||
this._error = null; // The boom object when created from an error (used for logging) | ||
this._contentEncoding = null; // Set during transmit | ||
this._contentType = null; // Used if no explicit content-type is set and type is known | ||
@@ -103,3 +103,3 @@ this._takeover = false; | ||
} | ||
else if (source instanceof Stream) { | ||
else if (Streams.isStream(source)) { | ||
this.variety = 'stream'; | ||
@@ -160,3 +160,3 @@ this._contentType = 'application/octet-stream'; | ||
if ((!append && override) || | ||
if (!append && override || | ||
!this.headers[key]) { | ||
@@ -217,3 +217,3 @@ | ||
etag: (options.weak ? 'W/' : '') + '"' + tag + '"', | ||
vary: (options.vary !== false && !options.weak), // vary defaults to true | ||
vary: options.vary !== false && !options.weak, // vary defaults to true | ||
modified: options.modified | ||
@@ -223,3 +223,3 @@ }; | ||
static unmodified(request, options) { | ||
static unmodified(request, entity) { | ||
@@ -234,3 +234,3 @@ if (request.method !== 'get' && | ||
if (options.etag && | ||
if (entity.etag && | ||
request.headers['if-none-match']) { | ||
@@ -240,13 +240,22 @@ | ||
for (const etag of ifNoneMatch) { | ||
if (etag === options.etag) { | ||
// Compare tags (https://tools.ietf.org/html/rfc7232#section-2.3.2) | ||
if (etag === entity.etag) { // Strong comparison | ||
return true; | ||
} | ||
if (options.vary) { | ||
const etagBase = options.etag.slice(0, -1); | ||
const encoders = request._core.compression.encodings; | ||
for (const encoder of encoders) { | ||
if (etag === etagBase + `-${encoder}"`) { | ||
return true; | ||
} | ||
if (!entity.vary) { | ||
continue; | ||
} | ||
if (etag === `W/${entity.etag}`) { // Weak comparison | ||
return etag; | ||
} | ||
const etagBase = entity.etag.slice(0, -1); | ||
const encoders = request._core.compression.encodings; | ||
for (const encoder of encoders) { | ||
if (etag === etagBase + `-${encoder}"`) { | ||
return true; | ||
} | ||
@@ -261,3 +270,3 @@ } | ||
if (!options.modified) { | ||
if (!entity.modified) { | ||
return false; | ||
@@ -276,3 +285,3 @@ } | ||
const lastModified = internals.parseDate(options.modified); | ||
const lastModified = internals.parseDate(entity.modified); | ||
if (!lastModified) { | ||
@@ -314,2 +323,9 @@ return false; | ||
compressed(encoding) { | ||
Hoek.assert(encoding && typeof encoding === 'string', 'Invalid content-encoding'); | ||
this.settings.compressed = encoding; | ||
return this; | ||
} | ||
replacer(method) { | ||
@@ -345,3 +361,3 @@ | ||
this.settings.passThrough = (enabled !== false); // Defaults to true | ||
this.settings.passThrough = enabled !== false; // Defaults to true | ||
return this; | ||
@@ -544,3 +560,3 @@ } | ||
if (source instanceof Stream) { | ||
if (Streams.isStream(source)) { | ||
if (typeof source._read !== 'function') { | ||
@@ -560,3 +576,3 @@ throw Boom.badImplementation('Stream must have a readable interface'); | ||
const jsonify = (this.variety === 'plain' && source !== null && typeof source !== 'string'); | ||
const jsonify = this.variety === 'plain' && source !== null && typeof source !== 'string'; | ||
@@ -608,3 +624,9 @@ if (!jsonify && | ||
return (this._events.hasListeners('finish') || this._events.hasListeners('peek') ? new internals.Response.Peek(this._events) : null); | ||
if (this._events.hasListeners('peek') || | ||
this._events.hasListeners('finish')) { | ||
return new internals.Response.Peek(this._events); | ||
} | ||
return null; | ||
} | ||
@@ -625,3 +647,3 @@ | ||
const stream = this._payload || this.source; | ||
if (stream instanceof Stream) { | ||
if (Streams.isStream(stream)) { | ||
internals.Response.drain(stream); | ||
@@ -633,3 +655,3 @@ } | ||
return (this.request.method !== 'head' && this.statusCode !== 304 && this.statusCode !== 204); | ||
return this.request.method !== 'head' && this.statusCode !== 304 && this.statusCode !== 204; | ||
} | ||
@@ -636,0 +658,0 @@ |
@@ -0,0 +0,0 @@ 'use strict'; |
@@ -11,2 +11,10 @@ 'use strict'; | ||
exports.isStream = function (stream) { | ||
return stream && | ||
typeof stream === 'object' && | ||
typeof stream.pipe === 'function'; | ||
}; | ||
exports.drain = function (stream) { | ||
@@ -20,2 +28,3 @@ | ||
stream.on('end', internals.end); | ||
stream.on('close', internals.end); | ||
@@ -28,3 +37,3 @@ return team.work; | ||
this.read(); | ||
while (this.read()) { } | ||
}; | ||
@@ -38,4 +47,5 @@ | ||
this.removeListener('end', internals.end); | ||
this.removeListener('close', internals.end); | ||
this[internals.team].attend(); | ||
}; |
@@ -22,7 +22,9 @@ 'use strict'; | ||
const response = request.response; | ||
if (response.isBoom) { | ||
return internals.fail(request, response); | ||
} | ||
try { | ||
if (response.isBoom) { | ||
await internals.fail(request, response); | ||
return; | ||
} | ||
await internals.marshal(request); | ||
@@ -49,3 +51,3 @@ await internals.transmit(response); | ||
const response = internals.error(boom, request); | ||
const response = internals.error(request, boom); | ||
request.response = response; // Not using request._setResponse() to avoid double log | ||
@@ -74,3 +76,3 @@ | ||
internals.error = function (boom, request) { | ||
internals.error = function (request, boom) { | ||
@@ -94,3 +96,3 @@ const error = boom.output; | ||
const encoding = request._core.compression.encoding(response, length); | ||
const ranger = (encoding ? null : internals.range(response, length)); | ||
const ranger = encoding ? null : internals.range(response, length); | ||
const compressor = internals.encoding(response, encoding); | ||
@@ -102,3 +104,3 @@ | ||
if (!(isInjection || request._core.started) || | ||
(request._isPayloadPending && !request.raw.req._readableState.ended)) { | ||
request._isPayloadPending && !request.raw.req._readableState.ended) { | ||
@@ -300,3 +302,3 @@ response._header('connection', 'close'); | ||
err = err || new Boom(`Request ${event}`, { statusCode: request.route.settings.response.disconnectStatusCode }); | ||
const error = internals.error(Boom.boomify(err), request); | ||
const error = internals.error(request, Boom.boomify(err)); | ||
request._setResponse(error); | ||
@@ -303,0 +305,0 @@ |
@@ -13,12 +13,29 @@ 'use strict'; | ||
// false - nothing allowed | ||
if (rule === false) { | ||
return Joi.object({}).allow(null); | ||
} | ||
// Custom function | ||
if (typeof rule === 'function') { | ||
return rule; | ||
} | ||
// null, undefined, true - anything allowed | ||
// false - nothing allowed | ||
if (!rule || // false tested above | ||
rule === true) { | ||
return null; | ||
} | ||
// {...} - ... allowed | ||
return (rule === false) ? | ||
Joi.object({}).allow(null) : | ||
(typeof rule === 'function' ? | ||
rule : | ||
!rule || rule === true ? null : Joi.compile(rule)); // false tested earlier | ||
if (typeof rule.validate === 'function') { | ||
return rule; | ||
} | ||
return Joi.compile(rule); | ||
}; | ||
@@ -87,3 +104,3 @@ | ||
var value = await (typeof schema !== 'function' ? Joi.validate(request[source], schema, localOptions) : schema.call(bind, request[source], localOptions)); | ||
var value = await (typeof schema !== 'function' ? internals.validate(request[source], schema, localOptions) : schema.call(bind, request[source], localOptions)); | ||
return; | ||
@@ -179,3 +196,3 @@ } | ||
if (typeof schema !== 'function') { | ||
value = await Joi.validate(source, schema, localOptions); | ||
value = await internals.validate(source, schema, localOptions); | ||
} | ||
@@ -202,1 +219,11 @@ else { | ||
}; | ||
internals.validate = function (value, schema, options) { | ||
if (typeof schema.validateAsync === 'function') { | ||
return schema.validateAsync(value, options); | ||
} | ||
return schema.validate(value, options); | ||
}; |
@@ -0,0 +0,0 @@ Copyright (c) 2011-2019, Sideway Inc, and project contributors |
@@ -5,3 +5,3 @@ { | ||
"homepage": "https://hapijs.com", | ||
"version": "18.3.2", | ||
"version": "18.4.0", | ||
"repository": "git://github.com/hapijs/hapi", | ||
@@ -38,2 +38,3 @@ "main": "lib/index.js", | ||
"@hapi/inert": "5.x.x", | ||
"@hapi/joi-next-test": "npm:@hapi/joi@16.x.x", | ||
"@hapi/lab": "20.x.x", | ||
@@ -45,7 +46,7 @@ "@hapi/wreck": "15.x.x", | ||
"scripts": { | ||
"test": "lab -a @hapi/code -t 100 -L -m 3000", | ||
"test-tap": "lab -a @hapi/code -r tap -o tests.tap -m 3000", | ||
"test-cov-html": "lab -a @hapi/code -r html -o coverage.html -m 3000" | ||
"test": "lab -a @hapi/code -t 100 -L -m 5000", | ||
"test-tap": "lab -a @hapi/code -r tap -o tests.tap -m 5000", | ||
"test-cov-html": "lab -a @hapi/code -r html -o coverage.html -m 5000" | ||
}, | ||
"license": "BSD-3-Clause" | ||
} |
<img src="https://raw.githubusercontent.com/hapijs/assets/master/images/hapi.png" width="400px" /> | ||
### Web and services application framework | ||
# The Simple, Secure Framework Developers Trust | ||
Enterprise support plans and commercial licensing are available. Please check the | ||
[Version Support Schedule](https://github.com/hapijs/hapi/blob/master/SUPPORT.md) for more information. | ||
Build powerful, scalable applications, with minimal overhead and full out-of-the-box functionality - your code, your way. | ||
**hapi** is a simple to use configuration-centric framework with built-in support for input validation, caching, | ||
authentication, and other essential facilities for building web and services applications. **hapi** enables | ||
developers to focus on writing reusable application logic in a highly modular and prescriptive approach. | ||
Version 18.x only supports node v8.12.0 and over. For older version of node please use hapi version 16.x. | ||
Development version: **18.1.x** ([release notes](https://github.com/hapijs/hapi/issues?labels=release+notes&page=1&state=closed)) | ||
[![Build Status](https://secure.travis-ci.org/hapijs/hapi.svg?branch=master)](https://travis-ci.org/hapijs/hapi) | ||
For the latest updates, [change log](https://hapijs.com/updates), and release information visit [hapijs.com](https://hapijs.com) and follow [@hapijs](https://twitter.com/hapijs) on twitter. If you have questions, please open an issue in the | ||
[discussion forum](https://github.com/hapijs/discuss). | ||
# Sponsorship | ||
## Featured Sponsors | ||
[![Auth0](https://user-images.githubusercontent.com/56631/31878562-5c64483a-b78f-11e7-92da-5a991ebb302d.png)](https://bit.ly/auth0h-rn) | ||
## Active Supporters | ||
- **CNN Digital** | ||
- **[Contentful](https://www.contentful.com/)** | ||
- The product development team at **Creative Artists Agency** | ||
## Legacy Supporters | ||
Past major financial support for the project was provided by: | ||
- [Condé Nast Technology](https://technology.condenast.com/) | ||
- [![Lob](https://user-images.githubusercontent.com/56631/42724877-60d54714-872f-11e8-97e9-07726418f41f.png)](https://lob.com/) | ||
### Visit the [hapi.dev](https://hapi.dev) Developer Portal for tutorials, documentation, and support |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
4395
174174
7
8