Comparing version 17.0.0-rc1 to 17.0.0-rc2
@@ -83,3 +83,8 @@ 'use strict'; | ||
this.settings.default = this._setupRoute(Hoek.clone(options)); // Can change options | ||
this.settings.default = this._setupRoute(Hoek.clone(options)); // Prevent changes to options | ||
const routes = this.server._router.table(); | ||
for (let i = 0; i < routes.length; ++i) { | ||
routes[i].rebuild(); | ||
} | ||
}; | ||
@@ -96,3 +101,3 @@ | ||
const realm = strategy.realm; | ||
const response = await request.server._replier.execute(strategy.methods.authenticate, request, { bind, realm, auth: true }); | ||
const response = await request.server._responder.execute(strategy.methods.authenticate, request, { bind, realm, auth: true }); | ||
@@ -210,2 +215,25 @@ if (!response.isAuth) { | ||
internals.Auth.prototype._enabled = function (route, type) { | ||
const config = this.lookup(route); | ||
if (!config) { | ||
return false; | ||
} | ||
if (type === 'authenticate') { | ||
return true; | ||
} | ||
for (let i = 0; i < config.strategies.length; ++i) { | ||
const name = config.strategies[i]; | ||
const strategy = this._strategies[name]; | ||
if (strategy.methods[type]) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
}; | ||
internals.Auth.authenticate = function (request) { | ||
@@ -238,6 +266,2 @@ | ||
const config = this.lookup(request.route); | ||
if (!config) { | ||
return; | ||
} | ||
return internals.authenticate(config, request, this); | ||
@@ -270,3 +294,3 @@ }; | ||
const realm = strategy.realm; | ||
const response = await request.server._replier.execute(strategy.methods.payload, request, { bind, realm }); | ||
const response = await request.server._responder.execute(strategy.methods.payload, request, { bind, realm }); | ||
@@ -287,5 +311,3 @@ if (response && | ||
const auth = request.server.auth; | ||
const config = auth.lookup(request.route); | ||
if (!config || | ||
!request.auth.isAuthenticated || | ||
if (!request.auth.isAuthenticated || | ||
request.auth.strategy === 'bypass') { | ||
@@ -303,3 +325,6 @@ | ||
const realm = strategy.realm; | ||
return await request.server._replier.execute(strategy.methods.response, request, { bind, realm, continue: 'undefined' }); | ||
const error = await request.server._responder.execute(strategy.methods.response, request, { bind, realm, continue: 'undefined' }); | ||
if (error) { | ||
throw error; | ||
} | ||
}; | ||
@@ -328,3 +353,3 @@ | ||
const realm = strategy.realm; | ||
const response = await request.server._replier.execute(strategy.methods.authenticate, request, { bind, realm, auth: true }); | ||
const response = await request.server._responder.execute(strategy.methods.authenticate, request, { bind, realm, auth: true }); | ||
@@ -331,0 +356,0 @@ const message = (response.isAuth ? internals.validate(response.error, response.data, name, config, request, errors) : internals.validate(response, null, name, config, request, errors)); |
@@ -62,6 +62,8 @@ 'use strict'; | ||
internals.Compression.prototype.encoding = function (response) { | ||
internals.Compression.prototype.encoding = function (response, length) { | ||
const request = response.request; | ||
if (!request.server.settings.compression) { | ||
if (!request.server.settings.compression || | ||
(length !== null && length < request.server.settings.compression.minBytes)) { | ||
return null; | ||
@@ -68,0 +70,0 @@ } |
@@ -86,3 +86,3 @@ 'use strict'; | ||
internals.handler = function (request, reply) { | ||
internals.handler = function (request, responder) { | ||
@@ -131,3 +131,3 @@ // Validate CORS preflight request | ||
const response = reply(); | ||
const response = responder.wrap(); | ||
response._header('access-control-allow-origin', request.headers.origin); | ||
@@ -150,13 +150,6 @@ response._header('access-control-allow-methods', method); | ||
exports.headers = function (response) { | ||
exports.headers = function (request) { | ||
const request = response.request; | ||
if (request._route._special) { | ||
return; | ||
} | ||
const settings = request.route.settings.cors; | ||
if (!settings) { | ||
return; | ||
} | ||
const response = request.response; | ||
@@ -163,0 +156,0 @@ response.vary('origin'); |
@@ -14,6 +14,5 @@ 'use strict'; | ||
exports.server = { | ||
compression: true, // Enable response compression | ||
compression: {}, // Enable response compression | ||
debug: { | ||
request: ['implementation'], | ||
log: ['implementation'] | ||
request: ['implementation'] | ||
}, | ||
@@ -44,3 +43,3 @@ load: { | ||
}, | ||
log: false, // Enables request level log collection | ||
log: {}, // Enables request level log generation and collection | ||
payload: { | ||
@@ -47,0 +46,0 @@ failAction: 'error', |
@@ -39,3 +39,3 @@ 'use strict'; | ||
const node = { | ||
func: methods[i], // Request: function (request, reply), Server: function (server) | ||
func: methods[i], // Request: function (request, responder), Server: function (server) | ||
bind: options.bind, | ||
@@ -42,0 +42,0 @@ plugin: event.plugin |
@@ -15,32 +15,30 @@ 'use strict'; | ||
try { | ||
// Prerequisites | ||
// Prerequisites | ||
if (request._route._prerequisites) { | ||
for (let i = 0; i < request._route._prerequisites.length; ++i) { // Serial execution of each set | ||
const set = request._route._prerequisites[i]; | ||
const pres = []; | ||
for (let j = 0; j < set.length; ++j) { | ||
pres.push(internals.handler(request, set[j].method, set[j])); | ||
} | ||
if (request._route._prerequisites) { | ||
for (let i = 0; i < request._route._prerequisites.length; ++i) { // Serial execution of each set | ||
const set = request._route._prerequisites[i]; | ||
const pres = []; | ||
for (let j = 0; j < set.length; ++j) { | ||
pres.push(internals.handler(request, set[j].method, set[j])); | ||
} | ||
const responses = await Promise.all(pres); // Parallel execution within sets | ||
const responses = await Promise.all(pres); // Parallel execution within sets | ||
for (let j = 0; j < responses.length; ++j) { | ||
if (responses[j] !== undefined) { | ||
request._setResponse(responses[j]); | ||
return; | ||
} | ||
for (let j = 0; j < responses.length; ++j) { | ||
if (responses[j] !== undefined) { | ||
return responses[j]; | ||
} | ||
} | ||
} | ||
} | ||
// Handler | ||
// Handler | ||
const result = await internals.handler(request, request.route.settings.handler); | ||
request._setResponse(result); | ||
const result = await internals.handler(request, request.route.settings.handler); | ||
if (result._takeover) { | ||
return result; | ||
} | ||
catch (err) { | ||
request._setResponse(err); | ||
} | ||
request._setResponse(result); | ||
}; | ||
@@ -53,3 +51,3 @@ | ||
const realm = request.route.realm; | ||
const response = await request.server._replier.execute(method, request, { bind, realm, continue: 'null' }); | ||
const response = await request.server._responder.execute(method, request, { bind, realm, continue: 'null' }); | ||
@@ -137,9 +135,9 @@ // Handler | ||
[ | ||
function (request, reply) { }, | ||
function (request, responder) { }, | ||
{ | ||
method: function (request, reply) { } | ||
method: function (request, responder) { } | ||
assign: key1 | ||
}, | ||
{ | ||
method: function (request, reply) { }, | ||
method: function (request, responder) { }, | ||
assign: key2 | ||
@@ -149,3 +147,3 @@ } | ||
{ | ||
method: function (request, reply) { }, | ||
method: function (request, responder) { }, | ||
assign: key3 | ||
@@ -152,0 +150,0 @@ } |
@@ -249,3 +249,3 @@ 'use strict'; | ||
Hoek.assert(['reply', 'request', 'server'].indexOf(type) !== -1, 'Unknown decoration type:', type); | ||
Hoek.assert(['responder', 'request', 'server'].indexOf(type) !== -1, 'Unknown decoration type:', type); | ||
Hoek.assert(property, 'Missing decoration property name'); | ||
@@ -265,7 +265,7 @@ Hoek.assert(typeof property === 'string', 'Decoration property must be a string'); | ||
// Reply | ||
// Responder | ||
if (type === 'reply') { | ||
this.root._replier.decorate(property, method); | ||
this.root.decorations.reply.push(property); | ||
if (type === 'responder') { | ||
this.root._responder.decorate(property, method); | ||
this.root.decorations.responder.push(property); | ||
return; | ||
@@ -272,0 +272,0 @@ } |
@@ -98,3 +98,3 @@ 'use strict'; | ||
this._setUrl(req.url, this.server.settings.router.stripTrailingSlash); // Sets: this.url, this.path, this.query | ||
this._setMethod(req.method); // Sets: this.method | ||
this._setMethod(req.method); // Sets: this.method | ||
@@ -109,3 +109,3 @@ this.id = now + ':' + server.info.id + ':' + server._requestCounter.value++; | ||
this._route = this.server._router.specials.notFound.route; // Used prior to routing (only settings are used, not the handler) | ||
this._route = this.server._router.specials.notFound.route; // Used prior to routing (only settings are used, not the handler) | ||
this.route = this._route.public; | ||
@@ -143,3 +143,3 @@ | ||
this._states = {}; | ||
this._entity = {}; // Entity information set via reply.entity() | ||
this._entity = {}; // Entity information set via responder.entity() | ||
this._logger = []; | ||
@@ -163,9 +163,11 @@ this._allowInternals = !!options.allowInternals; | ||
const about = { | ||
method: this.method, | ||
url: this.url.href, | ||
agent: this.raw.req.headers['user-agent'] | ||
}; | ||
if (this.route.settings.log.stats) { | ||
const about = { | ||
method: this.method, | ||
url: this.url.href, | ||
agent: this.raw.req.headers['user-agent'] | ||
}; | ||
this._log(['received'], about, now); // Must be last for object to be fully constructed | ||
this._log(['received'], about, now); // Must be last for object to be fully constructed | ||
} | ||
} | ||
@@ -274,3 +276,3 @@ | ||
if (this.route.settings.log) { | ||
if (this.route.settings.log.collect) { | ||
if (typeof data === 'function') { | ||
@@ -293,3 +295,3 @@ update = update(); | ||
Hoek.assert(this.route.settings.log, 'Request logging is disabled'); | ||
Hoek.assert(this.route.settings.log.collect, 'Request logging is disabled'); | ||
@@ -346,4 +348,3 @@ if (typeof tags === 'boolean') { | ||
if (response) { | ||
await this._reply(response); | ||
return; | ||
return this._reply(response); | ||
} | ||
@@ -360,4 +361,3 @@ } | ||
await this._reply(Boom.badRequest('Invalid path')); | ||
return; | ||
return this._reply(Boom.badRequest('Invalid path')); | ||
} | ||
@@ -390,13 +390,16 @@ | ||
for (let i = 0; i < this._route._cycle.length; ++i) { | ||
if (this._isReplied) { | ||
return; | ||
} | ||
await this._lifecycle(this._route._cycle, false); | ||
this._reply(); | ||
} | ||
if (this._isBailed) { | ||
await this._reply(); | ||
async _lifecycle(cycle, postCycle) { | ||
for (let i = 0; i < cycle.length; ++i) { | ||
if ((this._isReplied && !postCycle) || | ||
this._isBailed) { | ||
return; | ||
} | ||
const func = this._route._cycle[i]; | ||
const func = cycle[i]; | ||
let response; | ||
@@ -412,14 +415,17 @@ try { | ||
catch (err) { | ||
response = err; | ||
response = Response.wrap(err, this); | ||
} | ||
if (response && | ||
response !== this.server._replier.continue) { | ||
response !== this.server._responder.continue) { | ||
await this._reply(response); | ||
return; | ||
this._setResponse(response); | ||
if (!postCycle || | ||
typeof response === 'symbol') { | ||
return; | ||
} | ||
} | ||
} | ||
await this._reply(); | ||
} | ||
@@ -436,16 +442,18 @@ | ||
let serverTimeout = this.route.settings.timeout.server; | ||
if (serverTimeout) { | ||
serverTimeout = Math.floor(serverTimeout - this._bench.elapsed()); // Calculate the timeout from when the request was constructed | ||
const timeoutReply = () => { | ||
if (!serverTimeout) { | ||
return; | ||
} | ||
this._log(['request', 'server', 'timeout', 'error'], { timeout: serverTimeout, elapsed: this._bench.elapsed() }); | ||
this._reply(Boom.serverUnavailable()).then(Hoek.ignore); | ||
}; | ||
serverTimeout = Math.floor(serverTimeout - this._bench.elapsed()); // Calculate the timeout from when the request was constructed | ||
const timeoutReply = () => { | ||
if (serverTimeout <= 0) { | ||
return timeoutReply(); | ||
} | ||
this._log(['request', 'server', 'timeout', 'error'], { timeout: serverTimeout, elapsed: this._bench.elapsed() }); | ||
this._reply(Boom.serverUnavailable()); | ||
}; | ||
this._serverTimeoutId = setTimeout(timeoutReply, serverTimeout); | ||
if (serverTimeout <= 0) { | ||
return timeoutReply(); | ||
} | ||
this._serverTimeoutId = setTimeout(timeoutReply, serverTimeout); | ||
} | ||
@@ -459,3 +467,3 @@ | ||
const realm = ext.plugin.realm; | ||
const response = await this.server._replier.execute(ext.func, this, { bind, realm }); | ||
const response = await this.server._responder.execute(ext.func, this, { bind, realm }); | ||
@@ -465,3 +473,3 @@ // Process response | ||
if (typeof response === 'symbol') { | ||
if (response === this.server._replier.continue) { | ||
if (response === this.server._responder.continue) { | ||
continue; | ||
@@ -510,28 +518,23 @@ } | ||
if (this.response === this.server._replier.close) { | ||
this.raw.res.end(); // End the response in case it wasn't already closed | ||
if (typeof this.response === 'symbol') { // close or abort | ||
this._abort(); | ||
return; | ||
} | ||
if (this.response === this.server._replier.abandon || | ||
this.response === this.server._replier.close) { | ||
this._finalize(); | ||
await this._lifecycle(this._route._postCycle, true); | ||
if (typeof this.response === 'symbol') { // close or abort | ||
this._abort(); | ||
return; | ||
} | ||
if (this.server.root._extensions.route.onPreResponse.nodes) { | ||
let response; | ||
try { | ||
response = await this._invoke(this.server.root._extensions.route.onPreResponse); | ||
} | ||
catch (err) { | ||
response = err; | ||
} | ||
await Transmit.send(this); | ||
this._finalize(); | ||
} | ||
if (response) { | ||
this._setResponse(response); | ||
} | ||
_abort() { | ||
if (this.response === this.server._responder.close) { | ||
this.raw.res.end(); // End the response in case it wasn't already closed | ||
} | ||
await Transmit.send(this); | ||
this._finalize(); | ||
@@ -538,0 +541,0 @@ } |
@@ -484,10 +484,10 @@ 'use strict'; | ||
let source = this.source; | ||
// Processor marshal | ||
try { | ||
if (!this._processors.marshal) { | ||
this._streamify(this.source); | ||
return; | ||
if (this._processors.marshal) { | ||
source = await this._processors.marshal(this); | ||
} | ||
const source = await this._processors.marshal(this); | ||
this._streamify(source); | ||
} | ||
@@ -497,5 +497,4 @@ catch (err) { | ||
} | ||
} | ||
_streamify(source) { | ||
// Stream source | ||
@@ -508,3 +507,3 @@ if (source instanceof Stream) { | ||
if (source._readableState.objectMode) { | ||
throw Boom.badImplementation('Cannot reply with stream in object mode'); | ||
throw Boom.badImplementation('Cannot responder with stream in object mode'); | ||
} | ||
@@ -516,7 +515,15 @@ | ||
// Plain source (non string or null) | ||
const jsonify = (this.variety === 'plain' && source !== null && typeof source !== 'string'); | ||
if (!jsonify && | ||
this.settings.stringify) { | ||
throw Boom.badImplementation('Cannot set formatting options on non object response'); | ||
} | ||
let payload = source; | ||
if (this.variety === 'plain' && | ||
source !== null && | ||
typeof source !== 'string') { | ||
if (jsonify) { | ||
const options = this.settings.stringify || {}; | ||
@@ -527,7 +534,13 @@ const space = options.space || this.request.route.settings.json.space; | ||
const escape = this.request.route.settings.json.escape || false; | ||
if (replacer || space) { | ||
payload = JSON.stringify(payload, replacer, space); | ||
try { | ||
if (replacer || space) { | ||
payload = JSON.stringify(payload, replacer, space); | ||
} | ||
else { | ||
payload = JSON.stringify(payload); | ||
} | ||
} | ||
else { | ||
payload = JSON.stringify(payload); | ||
catch (err) { | ||
throw Boom.boomify(err); | ||
} | ||
@@ -543,5 +556,2 @@ | ||
} | ||
else if (this.settings.stringify) { | ||
throw Boom.badImplementation('Cannot set formatting options on non object response'); | ||
} | ||
@@ -579,2 +589,6 @@ this._payload = new internals.Response.Payload(payload, this.settings); | ||
if (stream.unpipe) { | ||
stream.unpipe(); | ||
} | ||
if (stream.close) { | ||
@@ -648,2 +662,19 @@ stream.close(); | ||
} | ||
writeToStream(stream) { | ||
if (this._prefix) { | ||
stream.write(this._prefix, this._encoding); | ||
} | ||
if (this._data) { | ||
stream.write(this._data, this._encoding); | ||
} | ||
if (this._suffix) { | ||
stream.write(this._suffix, this._encoding); | ||
} | ||
stream.end(); | ||
} | ||
}; | ||
@@ -650,0 +681,0 @@ |
@@ -14,2 +14,3 @@ 'use strict'; | ||
const Handler = require('./handler'); | ||
const Headers = require('./headers'); | ||
const Schema = require('./schema'); | ||
@@ -191,2 +192,3 @@ const Security = require('./security'); | ||
this._cycle = [internals.drain, Handler.execute]; | ||
this.rebuild(); | ||
return; | ||
@@ -208,10 +210,13 @@ } | ||
this._extensions[event.type].add(event); | ||
if (event.type === 'onPreResponse') { | ||
return; | ||
} | ||
} | ||
if (this._special) { | ||
this._postCycle = (this._extensions.onPreResponse.nodes ? [this._extensions.onPreResponse] : []); | ||
this._marshalCycle = [Headers.type, Headers.content]; | ||
return; | ||
} | ||
// Build lifecycle array | ||
const cycle = []; | ||
this._cycle = []; | ||
@@ -221,23 +226,22 @@ // 'onRequest' | ||
if (this.settings.jsonp) { | ||
cycle.push(internals.parseJSONP); | ||
this._cycle.push(internals.parseJSONP); | ||
} | ||
if (this.settings.state.parse) { | ||
cycle.push(internals.state); | ||
this._cycle.push(internals.state); | ||
} | ||
if (this._extensions.onPreAuth.nodes) { | ||
cycle.push(this._extensions.onPreAuth); | ||
this._cycle.push(this._extensions.onPreAuth); | ||
} | ||
const authenticate = (this.settings.auth !== false); // Anything other than 'false' can still require authentication | ||
if (authenticate) { | ||
cycle.push(Auth.authenticate); | ||
if (this.server.auth._enabled(this, 'authenticate')) { | ||
this._cycle.push(Auth.authenticate); | ||
} | ||
if (this.method !== 'get') { | ||
cycle.push(internals.payload); | ||
this._cycle.push(internals.payload); | ||
if (authenticate) { | ||
cycle.push(Auth.payload); | ||
if (this.server.auth._enabled(this, 'payload')) { | ||
this._cycle.push(Auth.payload); | ||
} | ||
@@ -247,42 +251,65 @@ } | ||
if (this._extensions.onPostAuth.nodes) { | ||
cycle.push(this._extensions.onPostAuth); | ||
this._cycle.push(this._extensions.onPostAuth); | ||
} | ||
if (this.settings.validate.headers) { | ||
cycle.push(Validation.headers); | ||
this._cycle.push(Validation.headers); | ||
} | ||
if (this.settings.validate.params) { | ||
cycle.push(Validation.params); | ||
this._cycle.push(Validation.params); | ||
} | ||
if (this.settings.jsonp) { | ||
cycle.push(internals.cleanupJSONP); | ||
this._cycle.push(internals.cleanupJSONP); | ||
} | ||
if (this.settings.validate.query) { | ||
cycle.push(Validation.query); | ||
this._cycle.push(Validation.query); | ||
} | ||
if (this.settings.validate.payload) { | ||
cycle.push(Validation.payload); | ||
this._cycle.push(Validation.payload); | ||
} | ||
if (this._extensions.onPreHandler.nodes) { | ||
cycle.push(this._extensions.onPreHandler); | ||
this._cycle.push(this._extensions.onPreHandler); | ||
} | ||
cycle.push(Handler.execute); // Must not call next() with an Error | ||
this._cycle.push(Handler.execute); | ||
if (this._extensions.onPostHandler.nodes) { | ||
cycle.push(this._extensions.onPostHandler); // An error from here on will override any result set in handler() | ||
this._cycle.push(this._extensions.onPostHandler); | ||
} | ||
this._postCycle = []; | ||
if (this.settings.response._validate && | ||
this.settings.response.sample !== 0) { | ||
cycle.push(Validation.response); | ||
this._postCycle.push(Validation.response); | ||
} | ||
this._cycle = cycle; | ||
if (this._extensions.onPreResponse.nodes) { | ||
this._postCycle.push(this._extensions.onPreResponse); | ||
} | ||
this._marshalCycle = [Headers.type]; | ||
if (this.settings.cors) { | ||
this._marshalCycle.push(Cors.headers); | ||
} | ||
if (this.settings.security) { | ||
this._marshalCycle.push(Security.headers); | ||
} | ||
this._marshalCycle.push(Headers.unmodified); | ||
this._marshalCycle.push(Headers.cache); | ||
this._marshalCycle.push(Headers.state); | ||
this._marshalCycle.push(Headers.content); | ||
if (this.server.auth._enabled(this, 'response')) { | ||
this._marshalCycle.push(Auth.response); // Must be last in case requires access to headers | ||
} | ||
}; | ||
@@ -365,3 +392,3 @@ | ||
// failAction: 'error', 'log', 'ignore', function (request, reply, error) | ||
// failAction: 'error', 'log', 'ignore', function (request, responder, error) | ||
@@ -389,3 +416,3 @@ const failAction = request.route.settings.payload.failAction; | ||
return await request.server._replier.execute(failAction, request, { realm: request.route.realm, args: [err] }); | ||
return await request.server._responder.execute(failAction, request, { realm: request.route.realm, args: [err] }); | ||
} | ||
@@ -392,0 +419,0 @@ }; |
@@ -101,3 +101,6 @@ 'use strict'; | ||
jsonp: Joi.string(), | ||
log: Joi.boolean(), | ||
log: Joi.object({ | ||
stats: Joi.boolean().default(false), | ||
collect: Joi.boolean().default(false) | ||
}), | ||
payload: Joi.object({ | ||
@@ -190,3 +193,6 @@ output: Joi.string().valid('data', 'stream', 'file'), | ||
cache: Joi.allow(null), // Validated elsewhere | ||
compression: Joi.boolean(), | ||
compression: Joi.object({ | ||
minBytes: Joi.number().min(1).integer().default(1024) | ||
}) | ||
.allow(false), | ||
debug: Joi.object({ | ||
@@ -193,0 +199,0 @@ request: Joi.array().items(Joi.string()).single().allow(false), |
@@ -64,28 +64,26 @@ 'use strict'; | ||
exports.headers = function (response) { | ||
exports.headers = function (request) { | ||
const request = response.request; | ||
const response = request.response; | ||
const security = response.request.route.settings.security; | ||
const security = request.route.settings.security; | ||
if (security) { | ||
if (security._hsts) { | ||
response._header('strict-transport-security', security._hsts, { override: false }); | ||
} | ||
if (security._hsts) { | ||
response._header('strict-transport-security', security._hsts, { override: false }); | ||
} | ||
if (security._xframe) { | ||
response._header('x-frame-options', security._xframe, { override: false }); | ||
} | ||
if (security._xframe) { | ||
response._header('x-frame-options', security._xframe, { override: false }); | ||
} | ||
if (security.xss) { | ||
response._header('x-xss-protection', '1; mode=block', { override: false }); | ||
} | ||
if (security.xss) { | ||
response._header('x-xss-protection', '1; mode=block', { override: false }); | ||
} | ||
if (security.noOpen) { | ||
response._header('x-download-options', 'noopen', { override: false }); | ||
} | ||
if (security.noOpen) { | ||
response._header('x-download-options', 'noopen', { override: false }); | ||
} | ||
if (security.noSniff) { | ||
response._header('x-content-type-options', 'nosniff', { override: false }); | ||
} | ||
if (security.noSniff) { | ||
response._header('x-content-type-options', 'nosniff', { override: false }); | ||
} | ||
}; |
@@ -27,3 +27,3 @@ 'use strict'; | ||
const Plugin = require('./plugin'); | ||
const Reply = require('./reply'); | ||
const Responder = require('./responder'); | ||
const Request = require('./request'); | ||
@@ -66,3 +66,3 @@ const Route = require('./route'); | ||
this._decorations = {}; | ||
this.decorations = { request: [], reply: [], server: [] }; | ||
this.decorations = { request: [], responder: [], server: [] }; | ||
this._dependencies = []; // Plugin dependencies | ||
@@ -73,3 +73,3 @@ this._events = new Podium(internals.events); | ||
this._registrations = {}; // Tracks plugin for dependency validation { name -> { version } } | ||
this._replier = new Reply(); | ||
this._responder = new Responder(); | ||
this._requestor = new Request(); | ||
@@ -474,3 +474,3 @@ this._plugins = {}; // Exposed plugin properties by name | ||
internals.notFound = function (request, reply) { | ||
internals.notFound = function () { | ||
@@ -481,3 +481,3 @@ throw Boom.notFound(); | ||
internals.badRequest = function (request, reply) { | ||
internals.badRequest = function () { | ||
@@ -522,3 +522,3 @@ throw Boom.badRequest(); | ||
request._execute().then(); | ||
request._execute(); | ||
} | ||
@@ -525,0 +525,0 @@ }; |
@@ -6,3 +6,2 @@ 'use strict'; | ||
const Http = require('http'); | ||
const Stream = require('stream'); | ||
@@ -15,6 +14,3 @@ const Ammo = require('ammo'); | ||
const Auth = require('./auth'); | ||
const Cors = require('./cors'); | ||
const Response = require('./response'); | ||
const Security = require('./security'); | ||
@@ -47,59 +43,6 @@ | ||
const response = request.response; | ||
Cors.headers(response); | ||
internals.content(response, false); | ||
Security.headers(response); | ||
internals.unmodified(response); | ||
try { | ||
await internals.state(response); | ||
for (let i = 0; i < request._route._marshalCycle.length; ++i) { | ||
const func = request._route._marshalCycle[i]; | ||
await func(request); | ||
} | ||
catch (err) { | ||
request._log(['state', 'response', 'error'], err); | ||
request._states = {}; // Clear broken state | ||
throw err; | ||
} | ||
internals.cache(response); | ||
if (response._isPayloadSupported() || | ||
request.method === 'head') { | ||
await response._marshal(); | ||
if (request.jsonp && | ||
response._payload.jsonp) { | ||
response._header('content-type', 'text/javascript' + (response.settings.charset ? '; charset=' + response.settings.charset : '')); | ||
response._header('x-content-type-options', 'nosniff'); | ||
response._payload.jsonp(request.jsonp); | ||
} | ||
if (response._payload.size && | ||
typeof response._payload.size === 'function') { | ||
response._header('content-length', response._payload.size(), { override: false }); | ||
} | ||
if (!response._isPayloadSupported()) { | ||
response._close(); // Close unused file streams | ||
response._payload = new internals.Empty(); // Set empty stream | ||
} | ||
internals.content(response, true); | ||
} | ||
else { | ||
// Set empty stream | ||
response._close(); // Close unused file streams | ||
response._payload = new internals.Empty(); | ||
delete response.headers['content-length']; | ||
} | ||
const authError = await Auth.response(request); // Must be last in case requires access to headers | ||
if (authError) { | ||
throw authError; | ||
} | ||
}; | ||
@@ -140,3 +83,3 @@ | ||
const request = response.request; | ||
const length = parseInt(response.headers['content-length'], 10); // In case value is a string | ||
const length = internals.length(response); | ||
@@ -155,3 +98,3 @@ // Empty response | ||
const encoding = request.server.root._compression.encoding(response); | ||
const encoding = request.server.root._compression.encoding(response, length); | ||
@@ -164,3 +107,3 @@ // Range | ||
response.statusCode === 200 && | ||
length > 0 && | ||
length && | ||
!encoding) { | ||
@@ -203,3 +146,2 @@ | ||
if (encoding && | ||
length !== 0 && | ||
response.statusCode !== 206 && | ||
@@ -244,10 +186,31 @@ response._isPayloadSupported()) { | ||
return internals.pipe(response, compressor, ranger); | ||
// Finalize response stream | ||
const stream = internals.chain([response._payload, response._tap(), compressor, ranger]); | ||
return internals.pipe(request, stream); | ||
}; | ||
internals.pipe = function (response, compressor, ranger) { | ||
internals.length = function (response) { | ||
const request = response.request; | ||
const source = response._payload; | ||
const header = response.headers['content-length']; | ||
if (header === undefined) { | ||
return null; | ||
} | ||
if (typeof header === 'string') { | ||
const length = parseInt(header, 10); | ||
if (!isFinite(length)) { | ||
return null; | ||
} | ||
return length; | ||
} | ||
return header; | ||
}; | ||
internals.pipe = function (request, stream) { | ||
const team = new Teamwork.Team({ meetings: 1 }); | ||
@@ -259,3 +222,3 @@ | ||
source.removeListener('error', end); | ||
stream.removeListener('error', end); | ||
@@ -277,4 +240,3 @@ request.raw.req.removeListener('aborted', onAborted); | ||
source.unpipe(); | ||
Response.drain(source); | ||
Response.drain(stream); | ||
} | ||
@@ -288,15 +250,18 @@ | ||
if ((event || err) && | ||
request._events) { | ||
if (event || | ||
err) { | ||
request._events.emit('disconnect'); | ||
if (request._events) { | ||
request._events.emit('disconnect'); | ||
} | ||
request._log(event ? ['response', 'error', event] : ['response', 'error'], err); | ||
} | ||
else if (request.route.settings.log.stats) { | ||
request._log(['response'], err); | ||
} | ||
const tags = (err ? ['response', 'error'] : (event ? ['response', 'error', event] : ['response'])); | ||
request._log(tags, err); | ||
team.attend(); | ||
}; | ||
source.once('error', end); | ||
const onAborted = () => end(null, 'aborted'); | ||
@@ -312,7 +277,9 @@ const onClose = () => end(null, 'close'); | ||
const tap = response._tap(); | ||
const preview = (tap ? source.pipe(tap) : source); | ||
const compressed = (compressor ? preview.pipe(compressor) : preview); | ||
const ranged = (ranger ? compressed.pipe(ranger) : compressed); | ||
ranged.pipe(request.raw.res); | ||
if (stream.writeToStream) { | ||
stream.writeToStream(request.raw.res); | ||
} | ||
else { | ||
stream.once('error', end); | ||
stream.pipe(request.raw.res); | ||
} | ||
@@ -360,148 +327,14 @@ return team.work; | ||
internals.Empty = function () { | ||
internals.chain = function (sources) { | ||
Stream.Readable.call(this); | ||
}; | ||
Hoek.inherits(internals.Empty, Stream.Readable); | ||
internals.Empty.prototype._read = function (/* size */) { | ||
this.push(null); | ||
}; | ||
internals.cache = function (response) { | ||
const request = response.request; | ||
if (response.headers['cache-control']) { | ||
return; | ||
} | ||
const policy = request.route.settings.cache && | ||
request._route._cache && | ||
(request.route.settings.cache._statuses[response.statusCode] || (response.statusCode === 304 && request.route.settings.cache._statuses['200'])); | ||
if (policy || | ||
response.settings.ttl) { | ||
const ttl = (response.settings.ttl !== null ? response.settings.ttl : request._route._cache.ttl()); | ||
const privacy = (request.auth.isAuthenticated || response.headers['set-cookie'] ? 'private' : request.route.settings.cache.privacy || 'default'); | ||
response._header('cache-control', 'max-age=' + Math.floor(ttl / 1000) + ', must-revalidate' + (privacy !== 'default' ? ', ' + privacy : '')); | ||
} | ||
else if (request.route.settings.cache) { | ||
response._header('cache-control', request.route.settings.cache.otherwise); | ||
} | ||
}; | ||
internals.content = function (response, postMarshal) { | ||
let type = response.headers['content-type']; | ||
if (!type) { | ||
if (response._contentType) { | ||
const charset = (response.settings.charset && response._contentType !== 'application/octet-stream' ? '; charset=' + response.settings.charset : ''); | ||
response.type(response._contentType + charset); | ||
let from = sources[0]; | ||
for (let i = 1; i < sources.length; ++i) { | ||
const to = sources[i]; | ||
if (to) { | ||
from.once('error', (err) => to.emit('error', err)); | ||
from = from.pipe(to); | ||
} | ||
} | ||
else { | ||
type = type.trim(); | ||
if ((!response._contentType || !postMarshal) && | ||
response.settings.charset && | ||
type.match(/^(?:text\/)|(?:application\/(?:json)|(?:javascript))/)) { | ||
if (!type.match(/; *charset=/)) { | ||
const semi = (type[type.length - 1] === ';'); | ||
response.type(type + (semi ? ' ' : '; ') + 'charset=' + (response.settings.charset)); | ||
} | ||
} | ||
} | ||
return from; | ||
}; | ||
internals.state = async function (response) { | ||
const request = response.request; | ||
const names = {}; | ||
const states = []; | ||
const requestStates = Object.keys(request._states); | ||
for (let i = 0; i < requestStates.length; ++i) { | ||
const stateName = requestStates[i]; | ||
names[stateName] = true; | ||
states.push(request._states[stateName]); | ||
} | ||
const keys = Object.keys(request.server.states.cookies); | ||
for (let i = 0; i < keys.length; ++i) { | ||
const name = keys[i]; | ||
const autoValue = request.server.states.cookies[name].autoValue; | ||
if (!autoValue || names[name]) { | ||
continue; | ||
} | ||
names[name] = true; | ||
if (typeof autoValue !== 'function') { | ||
states.push({ name, value: autoValue }); | ||
continue; | ||
} | ||
try { | ||
const value = await autoValue(request); | ||
states.push({ name, value }); | ||
} | ||
catch (err) { | ||
throw Boom.boomify(err); | ||
} | ||
} | ||
if (!states.length) { | ||
return; | ||
} | ||
let header = await request.server.states.format(states); | ||
const existing = response.headers['set-cookie']; | ||
if (existing) { | ||
header = (Array.isArray(existing) ? existing : [existing]).concat(header); | ||
} | ||
response._header('set-cookie', header); | ||
}; | ||
internals.unmodified = function (response) { | ||
const request = response.request; | ||
// Set headers from reply.entity() | ||
if (request._entity.etag && | ||
!response.headers.etag) { | ||
response.etag(request._entity.etag, { vary: request._entity.vary }); | ||
} | ||
if (request._entity.modified && | ||
!response.headers['last-modified']) { | ||
response.header('last-modified', request._entity.modified); | ||
} | ||
if (response.statusCode === 304) { | ||
return; | ||
} | ||
const entity = { | ||
etag: response.headers.etag, | ||
vary: response.settings.varyEtag, | ||
modified: response.headers['last-modified'] | ||
}; | ||
if (Response.unmodified(request, entity)) { | ||
response.code(304); | ||
} | ||
}; |
@@ -146,3 +146,3 @@ 'use strict'; | ||
return request.server._replier.execute(request.route.settings.validate.failAction, request, { realm: request.route.realm, args: [source, error] }); | ||
return request.server._responder.execute(request.route.settings.validate.failAction, request, { realm: request.route.realm, args: [source, error] }); | ||
}; | ||
@@ -238,4 +238,4 @@ | ||
return request.server._replier.execute(request.route.settings.response.failAction, request, { realm: request.route.realm, args: [err] }); | ||
return request.server._responder.execute(request.route.settings.response.failAction, request, { realm: request.route.realm, args: [err] }); | ||
} | ||
}; |
@@ -5,3 +5,3 @@ { | ||
"homepage": "http://hapijs.com", | ||
"version": "17.0.0-rc1", | ||
"version": "17.0.0-rc2", | ||
"repository": { | ||
@@ -8,0 +8,0 @@ "type": "git", |
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
162428
24
4058