Skip to content

Commit

Permalink
Merge branch 'master' into close-on-payload
Browse files Browse the repository at this point in the history
  • Loading branch information
hueniverse authored May 29, 2017
2 parents 347b74a + 50aaf12 commit e637840
Show file tree
Hide file tree
Showing 21 changed files with 319 additions and 87 deletions.
15 changes: 8 additions & 7 deletions API.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# 16.1.x API Reference
# 16.2.x API Reference

- [Server](#server)
- [`new Server([options])`](#new-serveroptions)
Expand Down Expand Up @@ -2598,7 +2598,7 @@ following options:
- `true` - any payload allowed (no validation performed). This is the default.
- `false` - no payload allowed.
- a [Joi](http://github.com/hapijs/joi) validation object. This will receive the request's
headers, params, query, payload, and auth credentials and isAuthenticated flags as context.
headers, params, query, payload, app, and auth as context.
- a validation function using the signature `function(value, options, next)` where:
- `value` - the object containing the response object.
- `options` - the server validation options, merged with an object containing the request's
Expand Down Expand Up @@ -2654,7 +2654,7 @@ following options:

- `validate` - request input validation rules for various request components. When using a
[Joi](http://github.com/hapijs/joi) validation object, the values of the other inputs (i.e.
`headers`, `query`, `params`, `payload`, and `auth`) are made available under the validation
`headers`, `query`, `params`, `payload`, `app`, and `auth`) are made available under the validation
context (accessible in rules as `Joi.ref('$query.key')`). Note that validation is performed in
order (i.e. headers, params, query, payload) and if type casting is used (converting a string to
number), the value of inputs not yet validated will reflect the raw, unvalidated and unmodified
Expand Down Expand Up @@ -2901,7 +2901,7 @@ Note that prerequisites do not follow the same rules of the normal
will use the result as the response sent back to the client. In a prerequisite method, calling
`reply()` will assign the returned value to the provided `assign` key. If the returned value is an
error, the `failAction` setting determines the behavior. To force the return value as the response
and ends the request lifecycle, use the `reply().takeover()` method.
and skip any other prerequisites and the handler, use the `reply().takeover()` method.

The reason for the difference in the reply interface behavior is to allow reusing handlers and
prerequisites methods interchangeably. By default, the desired behavior for a prerequisite is to
Expand Down Expand Up @@ -3064,7 +3064,7 @@ server.connection({ port: 80 });

const onRequest = function (request, reply) {

const uri = request.raw.req.url;
const uri = request.url.href;
const parsed = Url.parse(uri, false);
parsed.query = Qs.parse(parsed.query);
request.setUrl(parsed);
Expand Down Expand Up @@ -3442,7 +3442,8 @@ The response object provides the following methods:
- `count` - the number of spaces to indent nested object keys. Defaults to no indentation.
- `state(name, value, [options])` - sets an HTTP cookie where:
- `name` - the cookie name.
- `value` - the cookie value. If no `encoding` is defined, must be a string.
- `value` - the cookie value. If no `encoding` is defined, must be a string. See
[`server.state()`](#serverstatename-options) for supported `encoding` values.
- `options` - optional configuration. If the state was previously registered with the server
using [`server.state()`](#serverstatename-options),
the specified keys in `options` override those same keys in the server definition (but not
Expand Down Expand Up @@ -3631,7 +3632,7 @@ const preResponse = function (request, reply) {
message: (error.output.statusCode === 404 ? 'page not found' : 'something went wrong')
};

return reply.view('error', ctx);
return reply.view('error', ctx).code(error.output.statusCode);
};

server.ext('onPreResponse', preResponse);
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Lead Maintainer: [Eran Hammer](https://github.com/hueniverse)
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.

Development version: **16.1.x** ([release notes](https://github.com/hapijs/hapi/issues?labels=release+notes&page=1&state=closed))
Development version: **16.2.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)](http://travis-ci.org/hapijs/hapi)

For the latest updates, [change log](http://hapijs.com/updates), and release information visit [hapijs.com](http://hapijs.com) and follow [@hapijs](https://twitter.com/hapijs) on twitter. If you have questions, please open an issue in the
Expand Down
3 changes: 2 additions & 1 deletion SPONSORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
- Greg Allen
- Raffi Minassian
- CNN Digital
- Bryan Sapot

# Supporters

Expand All @@ -22,4 +23,4 @@
- Julian Lannigan
- Louis Beltramo
- Essau Ramirez

- Dave Stevens
1 change: 1 addition & 0 deletions lib/connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ exports = module.exports = internals.Connection = function (server, options) {

this.listener = this.settings.listener || (this.settings.tls ? Https.createServer(this.settings.tls) : Http.createServer());
this.listener.on('request', this._dispatch());
this.listener.on('checkContinue', this._dispatch({ expectContinue: true }));
this._init();

this.listener.on('clientError', (err, socket) => {
Expand Down
2 changes: 1 addition & 1 deletion lib/handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ internals.pre = function (pre) {
}

if (pre.assign) {
request.pre[pre.assign] = response.source;
request.pre[pre.assign] = (response instanceof Error ? response : response.source);
request.preResponses[pre.assign] = response;
}

Expand Down
44 changes: 25 additions & 19 deletions lib/plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,15 +65,7 @@ exports = module.exports = internals.Plugin = function (server, connections, env
test: (name, request, next) => request.connection.auth.test(name, request, next)
};

this.cache.provision = (opts, callback) => {

if (!callback) {
return Promises.wrap(null, this.cache.provision, [opts]);
}

return this.root._createCache(opts, callback);
};

this.cache = internals.cache(this);
this._single();

// Decorations
Expand Down Expand Up @@ -333,20 +325,34 @@ internals.Plugin.prototype.bind = function (context) {
};


internals.Plugin.prototype.cache = function (options, _segment) {
internals.cache = (plugin) => {

const policy = function (options, _segment) {

options = Schema.apply('cachePolicy', options);

options = Schema.apply('cachePolicy', options);
const segment = options.segment || _segment || (plugin.realm.plugin ? '!' + plugin.realm.plugin : '');
Hoek.assert(segment, 'Missing cache segment name');

const segment = options.segment || _segment || (this.realm.plugin ? '!' + this.realm.plugin : '');
Hoek.assert(segment, 'Missing cache segment name');
const cacheName = options.cache || '_default';
const cache = plugin.root._caches[cacheName];
Hoek.assert(cache, 'Unknown cache', cacheName);
Hoek.assert(!cache.segments[segment] || cache.shared || options.shared, 'Cannot provision the same cache segment more than once');
cache.segments[segment] = true;

const cacheName = options.cache || '_default';
const cache = this.root._caches[cacheName];
Hoek.assert(cache, 'Unknown cache', cacheName);
Hoek.assert(!cache.segments[segment] || cache.shared || options.shared, 'Cannot provision the same cache segment more than once');
cache.segments[segment] = true;
return new Catbox.Policy(options, cache.client, segment);
};

policy.provision = (opts, callback) => {

if (!callback) {
return Promises.wrap(null, plugin.cache.provision, [opts]);
}

return plugin.root._createCache(opts, callback);
};

return new Catbox.Policy(options, cache.client, segment);
return policy;
};


Expand Down
31 changes: 23 additions & 8 deletions lib/reply.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,34 +64,48 @@ internals.Reply.prototype.decorate = function (property, method) {

internals.Reply.prototype.interface = function (request, realm, options, next) { // next(err || response, data);

const reply = (err, response, data) => {
let reply = (err, response, data) => {

Hoek.assert(data === undefined || options.data, 'Reply interface does not allow a third argument');

reply._data = data; // Held for later
return reply.response(err !== null && err !== undefined ? err : response);
};

const domain = request.domain;
if (domain) {
reply = domain.bind(reply);

reply.close = domain.bind(internals.close);
reply.continue = domain.bind(internals.continue);
reply.redirect = domain.bind(internals.redirect);
reply.response = domain.bind(internals.response);
reply.entity = domain.bind(internals.entity);
}
else {
reply.close = internals.close;
reply.continue = internals.continue;
reply.redirect = internals.redirect;
reply.response = internals.response;
reply.entity = internals.entity;
}

reply._settings = options;
reply._replied = false;
reply._next = Hoek.once(next);

reply.realm = realm;
reply.request = request;

reply.close = internals.close;
reply.continue = internals.continue;
reply.state = internals.state;
reply.unstate = internals.unstate;
reply.redirect = internals.redirect;
reply.response = internals.response;
reply.entity = internals.entity;

if (this._decorations) {
const methods = Object.keys(this._decorations);
for (let i = 0; i < methods.length; ++i) {
const method = methods[i];
reply[method] = this._decorations[method];
const decoration = this._decorations[method];
reply[method] = (domain ? domain.bind(decoration) : decoration);
}
}

Expand Down Expand Up @@ -199,7 +213,8 @@ internals.entity = function (options) {

this.request._entity = options;

if (Response.unmodified(this.request, options)) {
const entity = Response.entity(options.etag, options);
if (Response.unmodified(this.request, entity)) {
return this.response().code(304).takeover();
}

Expand Down
1 change: 1 addition & 0 deletions lib/request.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ internals.Request = function (connection, req, res, options) {
this._entity = {}; // Entity information set via reply.entity()
this._logger = [];
this._allowInternals = !!options.allowInternals;
this._expectContinue = !!options.expectContinue;
this._isPayloadPending = !!(req.headers['content-length'] || req.headers['transfer-encoding']); // false when incoming payload fully processed
this._isBailed = false; // true when lifecycle should end
this._isReplied = false; // true when response processing started
Expand Down
20 changes: 16 additions & 4 deletions lib/response.js
Original file line number Diff line number Diff line change
Expand Up @@ -181,12 +181,24 @@ internals.Response.prototype.vary = function (value) {

internals.Response.prototype.etag = function (tag, options) {

Hoek.assert(tag !== '*', 'ETag cannot be *');
const entity = internals.Response.entity(tag, options);
this._header('etag', entity.etag);
this.settings.varyEtag = entity.vary;
return this;
};


internals.Response.entity = function (tag, options) {

options = options || {};
this._header('etag', (options.weak ? 'W/' : '') + '"' + tag + '"');
this.settings.varyEtag = options.vary !== false && !options.weak; // vary defaults to true
return this;

Hoek.assert(tag !== '*', 'ETag cannot be *');

return {
etag: (options.weak ? 'W/' : '') + '"' + tag + '"',
vary: (options.vary !== false && !options.weak), // vary defaults to true
modified: options.modified
};
};


Expand Down
4 changes: 4 additions & 0 deletions lib/route.js
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,10 @@ internals.payload = function (request, next) {
return next();
}

if (request._expectContinue) {
request.raw.res.writeContinue();
}

const onParsed = (err, parsed) => {

request.mime = parsed.mime;
Expand Down
2 changes: 1 addition & 1 deletion lib/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ const Heavy = require('heavy');
const Hoek = require('hoek');
const Items = require('items');
const Mimos = require('mimos');
const Podium = require('podium');
const Connection = require('./connection');
const Defaults = require('./defaults');
const Ext = require('./ext');
const Methods = require('./methods');
const Plugin = require('./plugin');
const Podium = require('podium');
const Promises = require('./promises');
const Reply = require('./reply');
const Request = require('./request');
Expand Down
13 changes: 9 additions & 4 deletions lib/validation.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,11 @@ internals.input = function (source, request, next) {
params: request.params,
query: request.query,
payload: request.payload,
auth: request.auth
auth: request.auth,
app: {
route: request.route.settings.app,
request: request.app
}
}
};

Expand Down Expand Up @@ -220,9 +224,10 @@ exports.response = function (request, next) {
params: request.params,
query: request.query,
payload: request.payload,
auth: {
isAuthenticated: request.auth.isAuthenticated,
credentials: request.auth.credentials
auth: request.auth,
app: {
route: request.route.settings.app,
request: request.app
}
}
};
Expand Down
Loading

0 comments on commit e637840

Please sign in to comment.