Comparing version 17.8.1 to 18.0.0
'use strict'; | ||
// Load modules | ||
const Boom = require('boom'); | ||
@@ -12,4 +10,2 @@ const Bounce = require('bounce'); | ||
// Declare internals | ||
const internals = { | ||
@@ -47,3 +43,2 @@ missing: Symbol('missing') | ||
Hoek.assert(typeof options === 'object', 'options must be an object'); | ||
Hoek.assert(name !== 'bypass', 'Cannot use reserved strategy name: bypass'); | ||
Hoek.assert(!this._strategies[name], 'Authentication strategy name already exists'); | ||
@@ -104,3 +99,3 @@ Hoek.assert(scheme, 'Authentication strategy', name, 'missing scheme'); | ||
return response.data.credentials; | ||
return response.data; | ||
} | ||
@@ -120,6 +115,2 @@ | ||
if (auth.strategy === 'bypass') { | ||
return; | ||
} | ||
const strategy = this._strategies[auth.strategy]; | ||
@@ -258,3 +249,3 @@ Hoek.assert(strategy, 'Unknown authentication strategy:', auth.strategy); | ||
if (request.auth.credentials) { | ||
internals.validate(null, { credentials: request.auth.credentials, artifacts: request.auth.artifacts }, 'bypass', config, request, errors); | ||
internals.validate(null, { credentials: request.auth.credentials, artifacts: request.auth.artifacts }, request.auth.strategy, config, request, errors); | ||
return; | ||
@@ -376,5 +367,3 @@ } | ||
if (!request.auth.isAuthenticated || | ||
request.auth.strategy === 'bypass') { | ||
if (!request.auth.isAuthenticated) { | ||
return; | ||
@@ -385,2 +374,3 @@ } | ||
const strategy = auth._strategies[request.auth.strategy]; | ||
Hoek.assert(strategy, 'Unknown authentication strategy:', request.auth.strategy); | ||
@@ -413,5 +403,3 @@ if (!strategy.methods.payload) { | ||
const auth = request._core.auth; | ||
if (!request.auth.isAuthenticated || | ||
request.auth.strategy === 'bypass') { | ||
if (!request.auth.isAuthenticated) { | ||
return; | ||
@@ -421,2 +409,4 @@ } | ||
const strategy = auth._strategies[request.auth.strategy]; | ||
Hoek.assert(strategy, 'Unknown authentication strategy:', request.auth.strategy); | ||
if (!strategy.methods.response) { | ||
@@ -450,7 +440,7 @@ return; | ||
if ((!scope._parameters || !scope._parameters[type]) && | ||
if ((!scope._hasParameters || !scope._hasParameters[type]) && | ||
/{([^}]+)}/.test(clean)) { | ||
scope._parameters = scope._parameters || {}; | ||
scope._parameters[type] = true; | ||
scope._hasParameters = scope._hasParameters || {}; | ||
scope._hasParameters[type] = true; | ||
} | ||
@@ -510,3 +500,3 @@ } | ||
if (!scope._parameters) { | ||
if (!scope._hasParameters) { | ||
return scope; | ||
@@ -527,5 +517,3 @@ } | ||
if (!scope[type] || | ||
!scope._parameters[type]) { | ||
if (!scope._hasParameters[type]) { | ||
return scope[type]; | ||
@@ -532,0 +520,0 @@ } |
'use strict'; | ||
// Load modules | ||
const Zlib = require('zlib'); | ||
@@ -12,4 +10,2 @@ | ||
// Declare internals | ||
const internals = { | ||
@@ -16,0 +12,0 @@ common: ['gzip, deflate', 'deflate, gzip', 'gzip', 'deflate', 'gzip, deflate, br'] |
'use strict'; | ||
// Load modules | ||
const Os = require('os'); | ||
const Joi = require('joi'); | ||
const Hoek = require('hoek'); | ||
// Declare internals | ||
const internals = {}; | ||
@@ -19,6 +14,10 @@ | ||
exports.apply = function (type, options, message) { | ||
exports.apply = function (type, options, ...message) { | ||
const result = Joi.validate(options, internals[type]); | ||
Hoek.assert(!result.error, 'Invalid', type, 'options', message ? '(' + message + ')' : '', result.error && result.error.annotate()); | ||
if (result.error) { | ||
throw new Error(`Invalid ${type} options ${message.length ? '(' + message.join(' ') + ')' : ''} ${result.error.annotate()}`); | ||
} | ||
return result.value; | ||
@@ -162,2 +161,3 @@ }; | ||
response: Joi.object({ | ||
disconnectStatusCode: Joi.number().integer().min(400).default(499), | ||
emptyStatusCode: Joi.valid(200, 204).default(200), | ||
@@ -223,2 +223,3 @@ failAction: internals.failAction, | ||
payload: Joi.alternatives(Joi.object(), Joi.array(), Joi.func()).allow(null, false, true), | ||
state: Joi.alternatives(Joi.object(), Joi.array(), Joi.func()).allow(null, false, true), | ||
failAction: internals.failAction, | ||
@@ -268,2 +269,6 @@ errorFields: Joi.object(), | ||
.allow(null), | ||
query: Joi.object({ | ||
parser: Joi.func() | ||
}) | ||
.default(), | ||
router: Joi.object({ | ||
@@ -338,15 +343,25 @@ isCaseSensitive: Joi.boolean().default(true), | ||
internals.cacheConfig = Joi.object({ | ||
name: Joi.string().invalid('_default'), | ||
partition: Joi.string(), | ||
shared: Joi.boolean(), | ||
engine: Joi.alternatives([ | ||
Joi.object(), | ||
Joi.func() | ||
]) | ||
.required() | ||
}).unknown(); | ||
internals.cacheConfig = Joi.alternatives([ | ||
Joi.func(), | ||
Joi.object({ | ||
name: Joi.string().invalid('_default'), | ||
shared: Joi.boolean(), | ||
provider: [ | ||
Joi.func(), | ||
{ | ||
constructor: Joi.func().required(), | ||
options: Joi.object({ | ||
partition: Joi.string().default('hapi-cache') | ||
}) | ||
.unknown() // Catbox client validates other keys | ||
.default({}) | ||
} | ||
], | ||
engine: Joi.object() | ||
}) | ||
.xor('provider', 'engine') | ||
]); | ||
internals.cache = Joi.array().items(internals.cacheConfig, Joi.func()).min(1).single(); | ||
internals.cache = Joi.array().items(internals.cacheConfig).min(1).single(); | ||
@@ -359,3 +374,3 @@ | ||
}) | ||
.options({ allowUnknown: true }); // Catbox validates other keys | ||
.unknown(); // Catbox policy validates other keys | ||
@@ -362,0 +377,0 @@ |
'use strict'; | ||
// Load modules | ||
const Http = require('http'); | ||
@@ -33,4 +31,2 @@ const Https = require('https'); | ||
// Declare internals | ||
const internals = { | ||
@@ -108,3 +104,3 @@ counter: { | ||
this.Request = class extends Request {}; | ||
this.Request = class extends Request { }; | ||
@@ -150,3 +146,3 @@ this._debug(); | ||
if (!this.caches.has('_default')) { | ||
this._createCache([{ engine: CatboxMemory }]); // Defaults to memory-based | ||
this._createCache([{ provider: CatboxMemory }]); // Defaults to memory-based | ||
} | ||
@@ -175,12 +171,18 @@ } | ||
_createCache(options) { | ||
_createCache(configs) { | ||
Hoek.assert(this.phase !== 'initializing', 'Cannot provision server cache while server is initializing'); | ||
options = Config.apply('cache', options); | ||
configs = Config.apply('cache', configs); | ||
const added = []; | ||
for (let config of options) { | ||
for (let config of configs) { | ||
// <function> | ||
// { provider: <function> } | ||
// { provider: { constructor: <function>, options } } | ||
// { engine } | ||
if (typeof config === 'function') { | ||
config = { engine: config }; | ||
config = { provider: { constructor: config } }; | ||
} | ||
@@ -192,13 +194,13 @@ | ||
let client = null; | ||
if (typeof config.engine === 'object') { | ||
client = new Catbox.Client(config.engine); | ||
if (config.provider) { | ||
let provider = config.provider; | ||
if (typeof provider === 'function') { | ||
provider = { constructor: provider }; | ||
} | ||
client = new Catbox.Client(provider.constructor, provider.options || { partition: 'hapi-cache' }); | ||
} | ||
else { | ||
const settings = Hoek.clone(config); | ||
settings.partition = settings.partition || 'hapi-cache'; | ||
delete settings.name; | ||
delete settings.engine; | ||
delete settings.shared; | ||
client = new Catbox.Client(config.engine, settings); | ||
client = new Catbox.Client(config.engine); | ||
} | ||
@@ -597,3 +599,3 @@ | ||
let settings = Hoek.cloneWithShallow(options, ['listener', 'routes.bind']); | ||
let settings = Hoek.cloneWithShallow(options, ['cache', 'listener', 'routes.bind']); | ||
settings.routes = Config.enable(settings.routes); | ||
@@ -600,0 +602,0 @@ settings = Config.apply('server', settings); |
'use strict'; | ||
// Load modules | ||
const Boom = require('boom'); | ||
@@ -11,4 +9,2 @@ const Hoek = require('hoek'); | ||
// Declare internals | ||
const internals = {}; | ||
@@ -15,0 +11,0 @@ |
'use strict'; | ||
// Load modules | ||
const Hoek = require('hoek'); | ||
@@ -9,4 +7,2 @@ const Topo = require('topo'); | ||
// Declare internals | ||
const internals = {}; | ||
@@ -13,0 +9,0 @@ |
'use strict'; | ||
// Load modules | ||
const Hoek = require('hoek'); | ||
// Declare internals | ||
const internals = {}; | ||
@@ -11,0 +7,0 @@ |
'use strict'; | ||
// Load modules | ||
@@ -12,4 +11,2 @@ const Stream = require('stream'); | ||
// Declare internals | ||
const internals = {}; | ||
@@ -84,7 +81,5 @@ | ||
const response = request.response; | ||
const names = {}; | ||
const states = []; | ||
for (const stateName in request._states) { | ||
names[stateName] = true; | ||
states.push(request._states[stateName]); | ||
@@ -96,8 +91,6 @@ } | ||
const autoValue = request._core.states.cookies[name].autoValue; | ||
if (!autoValue || names[name]) { | ||
if (!autoValue || name in request._states || name in request.state) { | ||
continue; | ||
} | ||
names[name] = true; | ||
if (typeof autoValue !== 'function') { | ||
@@ -104,0 +97,0 @@ states.push({ name, value: autoValue }); |
'use strict'; | ||
// Load modules | ||
const Server = require('./server'); | ||
// Declare internals | ||
const internals = {}; | ||
@@ -11,0 +7,0 @@ |
'use strict'; | ||
// Load modules | ||
const Boom = require('boom'); | ||
@@ -11,4 +9,2 @@ const Hoek = require('hoek'); | ||
// Declare internals | ||
const internals = { | ||
@@ -112,2 +108,5 @@ methodNameRx: /^[_$a-zA-Z][$\w]*(?:\.[_$a-zA-Z][$\w]*)*$/ | ||
internals.supportedArgs = ['string', 'number', 'boolean']; | ||
internals.generateKey = function (...args) { | ||
@@ -118,6 +117,3 @@ | ||
const arg = args[i]; | ||
if (typeof arg !== 'string' && | ||
typeof arg !== 'number' && | ||
typeof arg !== 'boolean') { | ||
if (!internals.supportedArgs.includes(typeof arg)) { | ||
return null; | ||
@@ -124,0 +120,0 @@ } |
'use strict'; | ||
// Load modules | ||
const Url = require('url'); | ||
@@ -17,4 +15,2 @@ | ||
// Declare internals | ||
const internals = { | ||
@@ -41,3 +37,3 @@ events: Podium.validate(['finish', { name: 'peek', spread: true }, 'disconnect']), | ||
this._states = {}; | ||
this._transmitted = false; // Indicates whether a response has been successful sent | ||
this._urlError = null; | ||
@@ -70,5 +66,5 @@ 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) | ||
isAuthorized: false, | ||
credentials: options.credentials || null, // Special keys: 'app', 'user', 'scope' | ||
artifacts: options.artifacts || null, // Scheme-specific artifacts | ||
strategy: null, | ||
credentials: options.auth ? options.auth.credentials : null, // Special keys: 'app', 'user', 'scope' | ||
artifacts: options.auth && options.auth.artifacts || null, // Scheme-specific artifacts | ||
strategy: options.auth ? options.auth.strategy : null, | ||
mode: null, | ||
@@ -78,5 +74,9 @@ error: null | ||
if (options.auth) { | ||
this.auth.isInjected = true; | ||
} | ||
// Parse request url | ||
this.setUrl(req.url, this._core.settings.router.stripTrailingSlash); | ||
this._initializeUrl(); | ||
} | ||
@@ -110,2 +110,15 @@ | ||
_initializeUrl() { | ||
try { | ||
this._setUrl(this.raw.req.url, this._core.settings.router.stripTrailingSlash); | ||
} | ||
catch (err) { | ||
this.path = this.raw.req.url; | ||
this.query = {}; | ||
this._urlError = Boom.boomify(err, { statusCode: 400, override: false }); | ||
} | ||
} | ||
setUrl(url, stripTrailingSlash) { | ||
@@ -115,7 +128,21 @@ | ||
url = (typeof url === 'string' ? Url.parse(url, true) : Hoek.clone(url)); | ||
if (url instanceof Url.URL) { | ||
url = url.href; | ||
} | ||
Hoek.assert(typeof url === 'string', 'Url must be a string or URL object'); | ||
this._setUrl(url, stripTrailingSlash); | ||
this._urlError = null; | ||
} | ||
_setUrl(url, stripTrailingSlash) { | ||
const base = (url[0] === '/' ? `${this._core.info.protocol}://${this.info.host || `${this._core.info.host}:${this._core.info.port}`}` : undefined); | ||
url = new Url.URL(url, base); | ||
// Apply path modifications | ||
let path = this._core.router.normalize(url.pathname || ''); // pathname excludes query | ||
let path = this._core.router.normalize(url.pathname); // pathname excludes query | ||
@@ -129,20 +156,44 @@ if (stripTrailingSlash && | ||
// Update derived url properties | ||
url.pathname = path; | ||
if (path !== url.pathname) { | ||
url.pathname = path; | ||
url.path = url.search ? path + url.search : path; | ||
url.href = Url.format(url); | ||
} | ||
// Parse query (must be done before this.url is set in case query parsing throws) | ||
this.query = this._parseQuery(url.searchParams); | ||
// Store request properties | ||
this.url = url; | ||
this.query = url.query; | ||
this.path = url.pathname; | ||
this.path = path; | ||
if (url.hostname) { | ||
this.info.hostname = url.hostname; | ||
this.info.host = url.host; | ||
this.info.hostname = url.hostname; | ||
this.info.host = url.host; | ||
} | ||
_parseQuery(searchParams) { | ||
// Flatten map | ||
let query = Object.create(null); | ||
for (let [key, value] of searchParams) { | ||
const entry = query[key]; | ||
if (entry !== undefined) { | ||
value = [].concat(entry, value); | ||
} | ||
query[key] = value; | ||
} | ||
// Custom parser | ||
const parser = this._core.settings.query.parser; | ||
if (parser) { | ||
query = parser(query); | ||
if (!query || | ||
typeof query !== 'object') { | ||
throw Boom.badImplementation('Parsed query must be an object'); | ||
} | ||
} | ||
return query; | ||
} | ||
@@ -198,6 +249,4 @@ | ||
if (!this.path || | ||
this.path[0] !== '/') { | ||
throw Boom.badRequest('Invalid path'); | ||
if (this._urlError) { | ||
throw this._urlError; | ||
} | ||
@@ -271,6 +320,3 @@ } | ||
try { | ||
var response = (typeof func === 'function' ? func(this) : this._invoke(func)); | ||
if (response && typeof response.then === 'function') { // Skip await if no reason to | ||
response = await response; | ||
} | ||
var response = await (typeof func === 'function' ? func(this) : this._invoke(func)); | ||
} | ||
@@ -391,4 +437,2 @@ catch (err) { | ||
this.info.responded = Date.now(); | ||
if (this.response && | ||
@@ -412,6 +456,3 @@ this.response.statusCode === 500 && | ||
if (!this._transmitted) { | ||
this.response = null; | ||
} | ||
this.info.completed = Date.now(); | ||
this._core.events.emit('response', this); | ||
@@ -431,3 +472,3 @@ this._core.queue.release(); | ||
if (this.info.responded) { | ||
if (this.info.completed) { | ||
if (response._close) { | ||
@@ -537,3 +578,4 @@ response._close(this); | ||
cors: null, | ||
responded: 0 | ||
responded: 0, | ||
completed: 0 | ||
}; | ||
@@ -557,2 +599,8 @@ | ||
if (event === 'close' && | ||
request.raw.res.finished) { | ||
return; | ||
} | ||
if (event === 'end') { | ||
@@ -559,0 +607,0 @@ return; |
'use strict'; | ||
// Load modules | ||
const Stream = require('stream'); | ||
@@ -15,4 +13,2 @@ | ||
// Declare internals | ||
const internals = { | ||
@@ -78,3 +74,5 @@ events: Podium.validate(['finish', { name: 'peek', spread: true }]), | ||
if (result instanceof internals.Response) { | ||
if (result instanceof internals.Response || | ||
typeof result === 'symbol') { | ||
return result; | ||
@@ -107,2 +105,3 @@ } | ||
this.variety = 'stream'; | ||
this._contentType = 'application/octet-stream'; | ||
} | ||
@@ -257,19 +256,22 @@ | ||
if (!options.modified) { | ||
return false; | ||
} | ||
const ifModifiedSinceHeader = request.headers['if-modified-since']; | ||
if (!ifModifiedSinceHeader) { | ||
return false; | ||
} | ||
if (ifModifiedSinceHeader && | ||
options.modified) { | ||
const ifModifiedSince = internals.parseDate(ifModifiedSinceHeader); | ||
if (!ifModifiedSince) { | ||
return false; | ||
} | ||
const ifModifiedSince = internals.parseDate(ifModifiedSinceHeader); | ||
const lastModified = internals.parseDate(options.modified); | ||
if (ifModifiedSince && | ||
lastModified && | ||
ifModifiedSince >= lastModified) { | ||
return true; | ||
} | ||
const lastModified = internals.parseDate(options.modified); | ||
if (!lastModified) { | ||
return false; | ||
} | ||
return false; | ||
return ifModifiedSince >= lastModified; | ||
} | ||
@@ -535,4 +537,4 @@ | ||
if (source instanceof Stream) { | ||
if (typeof source._read !== 'function' || typeof source._readableState !== 'object') { | ||
throw Boom.badImplementation('Stream must have a streams2 readable interface'); | ||
if (typeof source._read !== 'function') { | ||
throw Boom.badImplementation('Stream must have a readable interface'); | ||
} | ||
@@ -539,0 +541,0 @@ |
136
lib/route.js
'use strict'; | ||
// Load modules | ||
const Boom = require('boom'); | ||
@@ -23,4 +21,2 @@ const Bounce = require('bounce'); | ||
// Declare internals | ||
const internals = {}; | ||
@@ -38,13 +34,17 @@ | ||
const display = `${route.method} ${route.path}`; | ||
Config.apply('route', route, display); | ||
Config.apply('route', route, route.method, route.path); | ||
const method = route.method.toLowerCase(); | ||
Hoek.assert(method !== 'head', 'Method name not allowed:', display); | ||
Hoek.assert(method !== 'head', 'Cannot set HEAD route:', route.path); | ||
const path = (realm.modifiers.route.prefix ? realm.modifiers.route.prefix + (route.path !== '/' ? route.path : '') : route.path); | ||
Hoek.assert(path === '/' || path[path.length - 1] !== '/' || !core.settings.router.stripTrailingSlash, 'Path cannot end with a trailing slash when configured to strip:', display); | ||
Hoek.assert(path === '/' || path[path.length - 1] !== '/' || !core.settings.router.stripTrailingSlash, 'Path cannot end with a trailing slash when configured to strip:', route.method, route.path); | ||
const vhost = (realm.modifiers.route.vhost || route.vhost); | ||
// Set identifying members (assert) | ||
this.method = method; | ||
this.path = path; | ||
// Prepare configuration | ||
@@ -59,5 +59,10 @@ | ||
// Verify route level config (as opposed to the merged settings) | ||
this._assert(method !== 'get' || !config.payload, 'Cannot set payload settings on HEAD or GET request'); | ||
this._assert(method !== 'get' || !config.validate || !config.validate.payload, 'Cannot validate HEAD or GET request payload'); | ||
// Rules | ||
Hoek.assert(!route.rules || !config.rules, 'Route rules can only appear once:', display); // XOR | ||
this._assert(!route.rules || !config.rules, 'Route rules can only appear once'); // XOR | ||
const rules = (route.rules || config.rules); | ||
@@ -69,4 +74,4 @@ const rulesConfig = internals.rules(rules, { method, path, vhost }, server); | ||
Hoek.assert(route.handler || config.handler, 'Missing or undefined handler:', display); | ||
Hoek.assert(!!route.handler ^ !!config.handler, 'Handler must only appear once:', display); // XOR | ||
this._assert(route.handler || config.handler, 'Missing or undefined handler'); | ||
this._assert(!!route.handler ^ !!config.handler, 'Handler must only appear once'); // XOR | ||
@@ -81,3 +86,3 @@ const handler = Config.apply('handler', route.handler || config.handler); | ||
const settings = internals.config([core.settings.routes, handlerDefaults, realm.settings, rulesConfig, config]); | ||
this.settings = Config.apply('routeConfig', settings, display); | ||
this.settings = Config.apply('routeConfig', settings, method, path); | ||
@@ -87,4 +92,4 @@ // Validate timeouts | ||
const socketTimeout = (this.settings.timeout.socket === undefined ? 2 * 60 * 1000 : this.settings.timeout.socket); | ||
Hoek.assert(!this.settings.timeout.server || !socketTimeout || this.settings.timeout.server < socketTimeout, 'Server timeout must be shorter than socket timeout:', display); | ||
Hoek.assert(!this.settings.payload.timeout || !socketTimeout || this.settings.payload.timeout < socketTimeout, 'Payload timeout must be shorter than socket timeout:', display); | ||
this._assert(!this.settings.timeout.server || !socketTimeout || this.settings.timeout.server < socketTimeout, 'Server timeout must be shorter than socket timeout'); | ||
this._assert(!this.settings.payload.timeout || !socketTimeout || this.settings.payload.timeout < socketTimeout, 'Payload timeout must be shorter than socket timeout'); | ||
@@ -94,4 +99,2 @@ // Route members | ||
this._core = core; | ||
this.path = path; | ||
this.method = method; | ||
this.realm = realm; | ||
@@ -124,42 +127,4 @@ | ||
const validation = this.settings.validate; | ||
if (this.method === 'get') { | ||
this._setupValidation(); | ||
// Assert on config, not on merged settings | ||
Hoek.assert(!config.payload, 'Cannot set payload settings on HEAD or GET request:', display); | ||
Hoek.assert(!config.validate || !config.validate.payload, 'Cannot validate HEAD or GET requests:', display); | ||
validation.payload = null; | ||
} | ||
Hoek.assert(!validation.params || this.params.length, 'Cannot set path parameters validations without path parameters:', display); | ||
['headers', 'params', 'query', 'payload'].forEach((type) => { | ||
validation[type] = Validation.compile(validation[type]); | ||
}); | ||
if (this.settings.response.schema !== undefined || | ||
this.settings.response.status) { | ||
this.settings.response._validate = true; | ||
const rule = this.settings.response.schema; | ||
this.settings.response.status = this.settings.response.status || {}; | ||
const statuses = Object.keys(this.settings.response.status); | ||
if (rule === true && | ||
!statuses.length) { | ||
this.settings.response._validate = false; | ||
} | ||
else { | ||
this.settings.response.schema = Validation.compile(rule); | ||
for (const code of statuses) { | ||
this.settings.response.status[code] = Validation.compile(this.settings.response.status[code]); | ||
} | ||
} | ||
} | ||
// Payload parsing | ||
@@ -174,4 +139,5 @@ | ||
Hoek.assert(!this.settings.validate.payload || this.settings.payload.parse, 'Route payload must be set to \'parse\' when payload validation enabled:', display); | ||
Hoek.assert(!this.settings.jsonp || typeof this.settings.jsonp === 'string', 'Bad route JSONP parameter name:', display); | ||
this._assert(!this.settings.validate.payload || this.settings.payload.parse, 'Route payload must be set to \'parse\' when payload validation enabled'); | ||
this._assert(!this.settings.validate.state || this.settings.state.parse, 'Route state must be set to \'parse\' when state validation enabled'); | ||
this._assert(!this.settings.jsonp || typeof this.settings.jsonp === 'string', 'Bad route JSONP parameter name'); | ||
@@ -226,2 +192,39 @@ // Authentication configuration | ||
_setupValidation() { | ||
const validation = this.settings.validate; | ||
if (this.method === 'get') { | ||
validation.payload = null; | ||
} | ||
this._assert(!validation.params || this.params.length, 'Cannot set path parameters validations without path parameters'); | ||
['headers', 'params', 'query', 'payload', 'state'].forEach((type) => { | ||
validation[type] = Validation.compile(validation[type]); | ||
}); | ||
if (this.settings.response.schema !== undefined || | ||
this.settings.response.status) { | ||
this.settings.response._validate = true; | ||
const rule = this.settings.response.schema; | ||
this.settings.response.status = this.settings.response.status || {}; | ||
const statuses = Object.keys(this.settings.response.status); | ||
if (rule === true && | ||
!statuses.length) { | ||
this.settings.response._validate = false; | ||
} | ||
else { | ||
this.settings.response.schema = Validation.compile(rule); | ||
for (const code of statuses) { | ||
this.settings.response.status[code] = Validation.compile(this.settings.response.status[code]); | ||
} | ||
} | ||
} | ||
} | ||
rebuild(event) { | ||
@@ -303,2 +306,6 @@ | ||
if (this.settings.validate.state) { | ||
this._cycle.push(Validation.state); | ||
} | ||
if (this._extensions.onPreHandler.nodes) { | ||
@@ -357,2 +364,15 @@ this._cycle.push(this._extensions.onPreHandler); | ||
} | ||
_assert(condition, message) { | ||
if (condition) { | ||
return; | ||
} | ||
if (this.method[0] === '_') { | ||
throw new Error(message); | ||
} | ||
throw new Error(`${message}: ${this.method.toUpperCase()} ${this.path}`); | ||
} | ||
}; | ||
@@ -479,3 +499,3 @@ | ||
for (const item of chain) { | ||
config = Hoek.applyToDefaultsWithShallow(config, item, ['bind', 'validate.headers', 'validate.payload', 'validate.params', 'validate.query']); | ||
config = Hoek.applyToDefaultsWithShallow(config, item, ['bind', 'validate.headers', 'validate.payload', 'validate.params', 'validate.query', 'validate.state']); | ||
} | ||
@@ -482,0 +502,0 @@ |
'use strict'; | ||
// Load modules | ||
// Declare internals | ||
const internals = {}; | ||
@@ -9,0 +4,0 @@ |
'use strict'; | ||
// Load modules | ||
const Hoek = require('hoek'); | ||
@@ -19,4 +17,2 @@ const Joi = require('joi'); | ||
// Declare internals | ||
const internals = {}; | ||
@@ -287,3 +283,3 @@ | ||
if (!settings.authority || | ||
settings.credentials || | ||
settings.auth || | ||
settings.app || | ||
@@ -294,4 +290,3 @@ settings.plugins || | ||
settings = Object.assign({}, settings); // options can be reused (shallow cloned) | ||
delete settings.credentials; | ||
delete settings.artifacts; // Cannot appear without credentials | ||
delete settings.auth; | ||
delete settings.app; | ||
@@ -304,5 +299,12 @@ delete settings.plugins; | ||
Hoek.assert(!options.credentials, 'options.credentials no longer supported (use options.auth)'); | ||
if (options.auth) { | ||
Hoek.assert(typeof options.auth === 'object', 'options.auth must be an object'); | ||
Hoek.assert(options.auth.credentials, 'options.auth.credentials is missing'); | ||
Hoek.assert(options.auth.strategy, 'options.auth.strategy is missing'); | ||
} | ||
const needle = this._core._dispatch({ | ||
credentials: options.credentials, | ||
artifacts: options.artifacts, | ||
auth: options.auth, | ||
allowInternals: options.allowInternals, | ||
@@ -309,0 +311,0 @@ app: options.app, |
'use strict'; | ||
// Load modules | ||
const Teamwork = require('teamwork'); | ||
// Declare internals | ||
const internals = { | ||
@@ -11,0 +7,0 @@ team: Symbol('team') |
'use strict'; | ||
// Load modules | ||
const Boom = require('boom'); | ||
@@ -12,4 +10,2 @@ const Bounce = require('bounce'); | ||
// Declare internals | ||
const internals = { | ||
@@ -160,3 +156,3 @@ reserved: ['abandon', 'authenticated', 'close', 'context', 'continue', 'entity', 'redirect', 'realm', 'request', 'response', 'state', 'unauthenticated', 'unstate'] | ||
Hoek.assert(options, 'Entity method missing required options'); | ||
Hoek.assert(options.etag || options.modified, 'Entity methods missing require options key'); | ||
Hoek.assert(options.etag || options.modified, 'Entity methods missing required options key'); | ||
@@ -163,0 +159,0 @@ this.request._entity = options; |
'use strict'; | ||
// Load modules | ||
const Http = require('http'); | ||
@@ -18,4 +16,2 @@ | ||
// Declare internals | ||
const internals = {}; | ||
@@ -46,6 +42,3 @@ | ||
for (const func of request._route._marshalCycle) { | ||
const result = func(request); | ||
if (result && typeof result.then === 'function') { // Skip await if no reason to | ||
await result; | ||
} | ||
await func(request); | ||
} | ||
@@ -57,7 +50,3 @@ }; | ||
const error = boom.output; | ||
const response = new Response(error.payload, request); | ||
response._error = boom; | ||
response.code(error.statusCode); | ||
response.headers = Hoek.clone(error.headers); // Prevent source from being modified | ||
const response = internals.error(boom, request); | ||
request.response = response; // Not using request._setResponse() to avoid double log | ||
@@ -74,4 +63,4 @@ | ||
const minimal = { | ||
statusCode: error.statusCode, | ||
error: Http.STATUS_CODES[error.statusCode], | ||
statusCode: response.statusCode, | ||
error: Http.STATUS_CODES[response.statusCode], | ||
message: boom.message | ||
@@ -87,2 +76,13 @@ }; | ||
internals.error = function (boom, request) { | ||
const error = boom.output; | ||
const response = new Response(error.payload, request); | ||
response._error = boom; | ||
response.code(error.statusCode); | ||
response.headers = Hoek.clone(error.headers); // Prevent source from being modified | ||
return response; | ||
}; | ||
internals.transmit = function (response) { | ||
@@ -199,3 +199,3 @@ | ||
if (ranges.length !== 1) { // Ignore requests for multiple ranges | ||
if (ranges.length !== 1) { // Ignore requests for multiple ranges | ||
return null; | ||
@@ -259,2 +259,3 @@ } | ||
request.raw.req.on('close', close); | ||
request.raw.res.on('close', close); | ||
@@ -279,3 +280,4 @@ request.raw.res.on('error', end); | ||
const { request, stream, team } = env; | ||
if (!team) { // Used instead of cleaning up emitter listeners | ||
if (!team) { // Used instead of cleaning up emitter listeners | ||
return; | ||
@@ -286,32 +288,33 @@ } | ||
if (request.raw.res.finished) { | ||
if (event !== 'aborted') { | ||
request.info.responded = Date.now(); | ||
} | ||
team.attend(); | ||
return; | ||
} | ||
if (err) { | ||
request.raw.res.destroy(); | ||
if (request.raw.res[Config.symbol]) { | ||
request.raw.res.statusCode = 500; | ||
request.raw.res[Config.symbol].result = Boom.boomify(err).output.payload; // Force injected response to error | ||
} | ||
Response.drain(stream); | ||
} | ||
if (!request.raw.res.finished && | ||
event !== 'aborted') { | ||
err = err || new Boom(`Request ${event}`, { statusCode: request.route.settings.response.disconnectStatusCode }); | ||
const error = internals.error(Boom.boomify(err), request); | ||
request._setResponse(error); | ||
request.raw.res.end(); | ||
if (request.raw.res[Config.symbol]) { | ||
request.raw.res.statusCode = error.statusCode; | ||
request.raw.res[Config.symbol].result = error.source; // Force injected response to error | ||
} | ||
if (event || | ||
err) { | ||
if (request._events) { | ||
request._events.emit('disconnect'); | ||
} | ||
request._log(event ? ['response', 'error', event] : ['response', 'error'], err); | ||
if (event) { | ||
request._log(['response', 'error', event]); | ||
} | ||
else { | ||
request._transmitted = true; | ||
request._log(['response', 'error'], err); | ||
} | ||
request.raw.res.end(); // Triggers injection promise resolve | ||
team.attend(); | ||
@@ -318,0 +321,0 @@ }; |
'use strict'; | ||
// Load modules | ||
const Boom = require('boom'); | ||
@@ -10,4 +8,2 @@ const Hoek = require('hoek'); | ||
// Declare internals | ||
const internals = {}; | ||
@@ -61,2 +57,8 @@ | ||
exports.state = function (request) { | ||
return internals.input('state', request); | ||
}; | ||
internals.input = async function (source, request) { | ||
@@ -70,2 +72,3 @@ | ||
payload: request.payload, | ||
state: request.state, | ||
auth: request.auth, | ||
@@ -161,2 +164,3 @@ app: { | ||
payload: request.payload, | ||
state: request.state, | ||
auth: request.auth, | ||
@@ -163,0 +167,0 @@ app: { |
{ | ||
"version": "17.8.1", | ||
"version": "18.0.0", | ||
"name": "hapi", | ||
@@ -21,16 +21,11 @@ "lockfileVersion": 1, | ||
}, | ||
"big-time": { | ||
"version": "2.0.1", | ||
"resolved": "https://registry.npmjs.org/big-time/-/big-time-2.0.1.tgz", | ||
"integrity": "sha512-qtwYYoocwpiAxTXC5sIpB6nH5j6ckt+n/jhD7J5OEiFHnUZEFn0Xk8STUaE5s10LdazN/87bTDMe+fSihaW7Kg==" | ||
}, | ||
"boom": { | ||
"version": "7.2.2", | ||
"resolved": "https://registry.npmjs.org/boom/-/boom-7.2.2.tgz", | ||
"integrity": "sha512-IFUbOa8PS7xqmhIjpeStwT3d09hGkNYQ6aj2iELSTxcVs2u0aKn1NzhkdUQSzsRg1FVkj3uit3I6mXQCBixw+A==" | ||
"version": "7.3.0", | ||
"resolved": "https://registry.npmjs.org/boom/-/boom-7.3.0.tgz", | ||
"integrity": "sha512-Swpoyi2t5+GhOEGw8rEsKvTxFLIDiiKoUc2gsoV6Lyr43LHBIzch3k2MvYUs8RTROrIkVJ3Al0TkaOGjnb+B6A==" | ||
}, | ||
"bounce": { | ||
"version": "1.2.2", | ||
"resolved": "https://registry.npmjs.org/bounce/-/bounce-1.2.2.tgz", | ||
"integrity": "sha512-1LPcXg3fkGVhjdA/P3DcR5cDktKEYtDpruJv9Nhmy36RoYaoxZfC82Zr2JmS3vysDJKqMtP0qJw3/P6iisTASg==" | ||
"version": "1.2.3", | ||
"resolved": "https://registry.npmjs.org/bounce/-/bounce-1.2.3.tgz", | ||
"integrity": "sha512-3G7B8CyBnip5EahCZJjnvQ1HLyArC6P5e+xcolo13BVI9ogFaDOsNMAE7FIWliHtIkYI8/nTRCvCY9tZa3Mu4g==" | ||
}, | ||
@@ -43,10 +38,10 @@ "call": { | ||
"catbox": { | ||
"version": "10.0.5", | ||
"resolved": "https://registry.npmjs.org/catbox/-/catbox-10.0.5.tgz", | ||
"integrity": "sha512-5SpI/tEP3SiLE1qkkV+/hdVW48sHVBEbzPX4jBiwl6hsZh/gkl4bqfGLkvh7mjpMK5evJ0Rm/6NRlhF/Jsy9ow==" | ||
"version": "10.0.6", | ||
"resolved": "https://registry.npmjs.org/catbox/-/catbox-10.0.6.tgz", | ||
"integrity": "sha512-gQWCnF/jbHcfwGbQ4FQxyRiAwLRipqWTTXjpq7rTqqdcsnZosFa0L3LsCZcPTF33QIeMMkS7QmFBHt6QdzGPvg==" | ||
}, | ||
"catbox-memory": { | ||
"version": "3.1.4", | ||
"resolved": "https://registry.npmjs.org/catbox-memory/-/catbox-memory-3.1.4.tgz", | ||
"integrity": "sha512-1tDnll066au0HXBSDHS/YQ34MQ2omBsmnA9g/jseyq/M3m7UPrajVtPDZK/rXgikSC1dfjo9Pa+kQ1qcyG2d3g==" | ||
"version": "4.0.1", | ||
"resolved": "https://registry.npmjs.org/catbox-memory/-/catbox-memory-4.0.1.tgz", | ||
"integrity": "sha512-ZmqNiLsYCIu9qvBJ/MQbznDV2bFH5gFiH67TgIJgSSffJFtTXArT+MM3AvJQlby9NSkLHOX4eH/uuUqnch/Ldw==" | ||
}, | ||
@@ -69,5 +64,5 @@ "content": { | ||
"hoek": { | ||
"version": "6.0.1", | ||
"resolved": "https://registry.npmjs.org/hoek/-/hoek-6.0.1.tgz", | ||
"integrity": "sha512-3PvUwBerLNVJiIVQdpkWF9F/M0ekgb2NPJWOhsE28RXSQPsY42YSnaJ8d1kZjcAz58TZ/Fk9Tw64xJsENFlJNw==" | ||
"version": "6.1.2", | ||
"resolved": "https://registry.npmjs.org/hoek/-/hoek-6.1.2.tgz", | ||
"integrity": "sha512-6qhh/wahGYZHFSFw12tBbJw5fsAhhwrrG/y3Cs0YMTv2WzMnL0oLPnQJjv1QJvEfylRSOFuP+xCu+tdx0tD16Q==" | ||
}, | ||
@@ -80,5 +75,5 @@ "iron": { | ||
"joi": { | ||
"version": "14.0.4", | ||
"resolved": "https://registry.npmjs.org/joi/-/joi-14.0.4.tgz", | ||
"integrity": "sha512-KUXRcinDUMMbtlOk7YLGHQvG73dLyf8bmgE+6sBTkdJbZpeGVGAlPXEHLiQBV7KinD/VLD5OA0EUgoTTfbRAJQ==" | ||
"version": "14.3.1", | ||
"resolved": "https://registry.npmjs.org/joi/-/joi-14.3.1.tgz", | ||
"integrity": "sha512-LQDdM+pkOrpAn4Lp+neNIFV3axv1Vna3j38bisbQhETPMANYRbFJFUyOZcOClYvM/hppMhGWuKSFEK9vjrB+bQ==" | ||
}, | ||
@@ -106,5 +101,5 @@ "mime-db": { | ||
"podium": { | ||
"version": "3.1.5", | ||
"resolved": "https://registry.npmjs.org/podium/-/podium-3.1.5.tgz", | ||
"integrity": "sha512-+fAPmAj3d5fWKx5oSjQKeBIcl46/qZnGLhzyi/dJ/HzNiOpuxyX/Y4091LiVxZQ4ALdf/LCS7siV6ai5nNLlOg==" | ||
"version": "3.2.0", | ||
"resolved": "https://registry.npmjs.org/podium/-/podium-3.2.0.tgz", | ||
"integrity": "sha512-rbwvxwVkI6gRRlxZQ1zUeafrpGxZ7QPHIheinehAvGATvGIPfWRkaTeWedc5P4YjXJXEV8ZbBxPtglNylF9hjw==" | ||
}, | ||
@@ -132,5 +127,5 @@ "shot": { | ||
"teamwork": { | ||
"version": "3.0.2", | ||
"resolved": "https://registry.npmjs.org/teamwork/-/teamwork-3.0.2.tgz", | ||
"integrity": "sha512-tpG01+9Qws/oGhMBiZN3BnB32gn5QeKY84AmLxxaCJw4mNeRzhEZ6jEj/vBhKerHD7Hgq9/vOZ58pyryYSn9gA==" | ||
"version": "3.0.3", | ||
"resolved": "https://registry.npmjs.org/teamwork/-/teamwork-3.0.3.tgz", | ||
"integrity": "sha512-OCB56z+G70iA1A1OFoT+51TPzfcgN0ks75uN3yhxA+EU66WTz2BevNDK4YzMqfaL5tuAvxy4iFUn35/u8pxMaQ==" | ||
}, | ||
@@ -143,5 +138,5 @@ "topo": { | ||
"vise": { | ||
"version": "3.0.1", | ||
"resolved": "https://registry.npmjs.org/vise/-/vise-3.0.1.tgz", | ||
"integrity": "sha512-7BJNjsv2o83+E6AHAFSnjQF324UTgypsR/Sw/iFmLvr7RgJrEXF1xNBvb5LJfi+1FvWQXjJK4X41WMuHMeunPQ==" | ||
"version": "3.0.2", | ||
"resolved": "https://registry.npmjs.org/vise/-/vise-3.0.2.tgz", | ||
"integrity": "sha512-X52VtdRQbSBXdjcazRiY3eRgV3vTQ0B+7Wh8uC9cVv7lKfML5m9+9NHlbcgCY0R9EAqD1v/v7o9mhGh2A3ANFg==" | ||
}, | ||
@@ -148,0 +143,0 @@ "wreck": { |
@@ -5,3 +5,3 @@ { | ||
"homepage": "https://hapijs.com", | ||
"version": "17.8.1", | ||
"version": "18.0.0", | ||
"repository": { | ||
@@ -25,3 +25,3 @@ "type": "git", | ||
"catbox": "10.x.x", | ||
"catbox-memory": "3.x.x", | ||
"catbox-memory": "4.x.x", | ||
"heavy": "6.x.x", | ||
@@ -42,5 +42,4 @@ "hoek": "6.x.x", | ||
"handlebars": "4.x.x", | ||
"hapitoc": "1.x.x", | ||
"inert": "5.x.x", | ||
"lab": "17.x.x", | ||
"lab": "18.x.x", | ||
"vision": "5.x.x", | ||
@@ -52,6 +51,5 @@ "wreck": "14.x.x" | ||
"test-tap": "lab -a code -r tap -o tests.tap -m 3000", | ||
"test-cov-html": "lab -a code -r html -o coverage.html -m 3000", | ||
"toc": "hapitoc" | ||
"test-cov-html": "lab -a code -r html -o coverage.html -m 3000" | ||
}, | ||
"license": "BSD-3-Clause" | ||
} |
@@ -11,5 +11,5 @@ <img src="https://raw.github.com/hapijs/hapi/master/images/17.png" align="right"/> | ||
Version 17.x only supports node v8.12.0 and over. For older version of node please use version 16.x. | ||
Version 18.x only supports node v8.12.0 and over. For older version of node please use hapi version 16.x. | ||
Development version: **17.8.x** ([release notes](https://github.com/hapijs/hapi/issues?labels=release+notes&page=1&state=closed)) | ||
Development version: **18.0.x** ([release notes](https://github.com/hapijs/hapi/issues?labels=release+notes&page=1&state=closed)) | ||
[![Linux Build Status](https://secure.travis-ci.org/hapijs/hapi.svg?branch=master)](https://travis-ci.org/hapijs/hapi) | ||
@@ -16,0 +16,0 @@ [![Windows Build Status](https://ci.appveyor.com/api/projects/status/github/hapijs/hapi?branch=master&svg=true)](https://ci.appveyor.com/project/hueniverse/hapi) |
Sorry, the diff of this file is not supported yet
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
179910
6
25
4443
+ Addedcatbox-memory@4.0.1(transitive)
- Removedbig-time@2.0.1(transitive)
- Removedcatbox-memory@3.1.4(transitive)
Updatedcatbox-memory@4.x.x