Skip to content

Commit 5f032a3

Browse files
committed
Decorate request. Closes hapijs#2481
1 parent 86aa8e6 commit 5f032a3

File tree

8 files changed

+135
-18
lines changed

8 files changed

+135
-18
lines changed

lib/connection.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ var Shot = require('shot');
1212
var Statehood = require('statehood');
1313
var Topo = require('topo');
1414
var Auth = require('./auth');
15-
var Request = require('./request');
1615
var Route = require('./route');
1716
var Schema = require('./schema');
1817

@@ -212,7 +211,7 @@ internals.Connection.prototype._dispatch = function (options) {
212211

213212
// Create request
214213

215-
var request = new Request(self, req, res, options);
214+
var request = self.server._requestor.request(self, req, res, options);
216215

217216
// Check load
218217

lib/plugin.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,11 +289,17 @@ internals.Plugin.prototype.cache = function (options, _segment) {
289289

290290
internals.Plugin.prototype.decorate = function (type, property, method) {
291291

292-
Hoek.assert(type === 'reply' || type === 'server', 'Unknown decoration type:', type);
292+
Hoek.assert(['reply', 'request', 'server'].indexOf(type) !== -1, 'Unknown decoration type:', type);
293293
Hoek.assert(property, 'Missing decoration property name');
294294
Hoek.assert(typeof property === 'string', 'Decoration property must be a string');
295295
Hoek.assert(property[0] !== '_', 'Property name cannot begin with an underscore:', property);
296296

297+
// Request
298+
299+
if (type === 'request') {
300+
return this.root._requestor.decorate(property, method);
301+
}
302+
297303
// Reply
298304

299305
if (type === 'reply') {

lib/reply.js

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,16 @@ var internals = {};
1111

1212
exports = module.exports = internals.Reply = function () {
1313

14-
this._decorations = {};
14+
this._decorations = null;
1515
};
1616

1717

1818
internals.Reply.prototype.decorate = function (property, method) {
1919

20-
Hoek.assert(!this._decorations[property], 'Reply interface decoration already defined:', property);
20+
Hoek.assert(!this._decorations || !this._decorations[property], 'Reply interface decoration already defined:', property);
2121
Hoek.assert(['request', 'response', 'close', 'state', 'unstate', 'redirect', 'continue'].indexOf(property) === -1, 'Cannot override built-in reply interface decoration:', property);
2222

23+
this._decorations = this._decorations || {};
2324
this._decorations[property] = method;
2425
};
2526

@@ -80,10 +81,12 @@ internals.Reply.prototype.interface = function (request, realm, next) { //
8081
reply.redirect = internals.redirect;
8182
reply.continue = internals.continue;
8283

83-
var methods = Object.keys(this._decorations);
84-
for (var i = 0, il = methods.length; i < il; ++i) {
85-
var method = methods[i];
86-
reply[method] = this._decorations[method];
84+
if (this._decorations) {
85+
var methods = Object.keys(this._decorations);
86+
for (var i = 0, il = methods.length; i < il; ++i) {
87+
var method = methods[i];
88+
reply[method] = this._decorations[method];
89+
}
8790
}
8891

8992
return reply;

lib/request.js

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,46 @@ var Transmit = require('./transmit');
1717

1818
// Declare internals
1919

20-
var internals = {};
20+
var internals = {
21+
properties: ['connection', 'server', 'url', 'query', 'path', 'method', 'mime', 'setUrl', 'setMethod', 'headers', 'id', 'app', 'plugins', 'route', 'auth', 'session', 'pre', 'preResponses', 'info', 'orig', 'params', 'paramsArray', 'payload', 'state', 'jsonp', 'response', 'raw', 'tail', 'addTail', 'domain', 'log', 'getLog', 'generateResponse']
22+
};
23+
24+
25+
exports = module.exports = internals.Generator = function () {
26+
27+
this._decorations = null;
28+
};
29+
30+
31+
internals.Generator.prototype.request = function (connection, req, res, options) {
32+
33+
var request = new internals.Request(connection, req, res, options);
34+
35+
// Decorate
36+
37+
if (this._decorations) {
38+
var methods = Object.keys(this._decorations);
39+
for (var i = 0, il = methods.length; i < il; ++i) {
40+
var method = methods[i];
41+
request[method] = this._decorations[method];
42+
}
43+
}
2144

45+
return request;
46+
};
47+
48+
49+
internals.Generator.prototype.decorate = function (property, method) {
50+
51+
Hoek.assert(!this._decorations || !this._decorations[property], 'Request interface decoration already defined:', property);
52+
Hoek.assert(internals.properties.indexOf(property) === -1, 'Cannot override built-in request interface decoration:', property);
53+
54+
this._decorations = this._decorations || {};
55+
this._decorations[property] = method;
56+
};
2257

23-
exports = module.exports = internals.Request = function (connection, req, res, options) {
58+
59+
internals.Request = function (connection, req, res, options) {
2460

2561
var self = this;
2662

@@ -89,16 +125,11 @@ exports = module.exports = internals.Request = function (connection, req, res, o
89125
if (options.credentials) {
90126
this.auth.credentials = options.credentials;
91127
}
92-
if (options.artifacts) {
93-
this.auth.artifacts = options.artifacts;
94-
}
95-
96128

97129
if (options.artifacts) {
98130
this.auth.artifacts = options.artifacts;
99131
}
100132

101-
102133
// Assigned elsewhere:
103134

104135
this.orig = {};
@@ -314,7 +345,7 @@ internals.Request.prototype._execute = function () {
314345
serverTimeout = Math.floor(serverTimeout - self._bench.elapsed()); // Calculate the timeout from when the request was constructed
315346
var timeoutReply = function () {
316347

317-
self._log(['request', 'server', 'timeout', 'error'], { timeout: serverTimeout, elapsed: self._bench.elapsed()});
348+
self._log(['request', 'server', 'timeout', 'error'], { timeout: serverTimeout, elapsed: self._bench.elapsed() });
318349
self._reply(Boom.serverTimeout());
319350
};
320351

lib/server.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ var Handler = require('./handler');
1717
var Methods = require('./methods');
1818
var Plugin = require('./plugin');
1919
var Reply = require('./reply');
20+
var Request = require('./request');
2021
var Schema = require('./schema');
2122

2223

@@ -46,6 +47,7 @@ exports = module.exports = internals.Server = function (options) {
4647
this._heavy = new Heavy(this._settings.load);
4748
this._mime = new Mimos(this._settings.mime);
4849
this._replier = new Reply();
50+
this._requestor = new Request();
4951
this._decorations = {};
5052
this._plugins = {}; // Exposed plugin properties by name
5153
this._app = {};

test/plugin.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1298,6 +1298,33 @@ describe('Plugin', function () {
12981298

12991299
describe('decorate()', function () {
13001300

1301+
it('decorates request', function (done) {
1302+
1303+
var server = new Hapi.Server();
1304+
server.connection();
1305+
1306+
server.decorate('request', 'getId', function () {
1307+
1308+
return this.id;
1309+
});
1310+
1311+
server.route({
1312+
method: 'GET',
1313+
path: '/',
1314+
handler: function (request, reply) {
1315+
1316+
return reply(request.getId());
1317+
}
1318+
});
1319+
1320+
server.inject('/', function (res) {
1321+
1322+
expect(res.statusCode).to.equal(200);
1323+
expect(res.result).to.match(/^.*\:.*\:.*\:.*\:.*$/);
1324+
done();
1325+
});
1326+
});
1327+
13011328
it('decorates reply', function (done) {
13021329

13031330
var server = new Hapi.Server();

test/reply.js

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ describe('Reply', function () {
6060
});
6161
});
6262

63-
describe('_interface()', function () {
63+
describe('interface()', function () {
6464

6565
it('uses reply(null, result) for result', function (done) {
6666

@@ -113,6 +113,23 @@ describe('Reply', function () {
113113
done();
114114
});
115115
});
116+
117+
it('skips decorations on minimal server', function (done) {
118+
119+
var handler = function (request, reply) {
120+
121+
return reply(reply.view === undefined);
122+
};
123+
124+
var server = new Hapi.Server({ minimal: true });
125+
server.connection();
126+
server.route({ method: 'GET', path: '/', handler: handler });
127+
server.inject('/', function (res) {
128+
129+
expect(res.result).to.equal(true);
130+
done();
131+
});
132+
});
116133
});
117134

118135
describe('response()', function () {

test/request.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,38 @@ var it = lab.it;
2424
var expect = Code.expect;
2525

2626

27+
describe('Request.Generator', function () {
28+
29+
it('decorates request multiple times', function (done) {
30+
31+
var server = new Hapi.Server();
32+
server.connection();
33+
34+
server.decorate('request', 'x2', function () {
35+
36+
return 2;
37+
});
38+
39+
server.decorate('request', 'abc', 1);
40+
41+
server.route({
42+
method: 'GET',
43+
path: '/',
44+
handler: function (request, reply) {
45+
46+
return reply(request.x2() + request.abc);
47+
}
48+
});
49+
50+
server.inject('/', function (res) {
51+
52+
expect(res.statusCode).to.equal(200);
53+
expect(res.result).to.equal(3);
54+
done();
55+
});
56+
});
57+
});
58+
2759
describe('Request', function () {
2860

2961
it('sets client address', function (done) {

0 commit comments

Comments
 (0)