From 5d40c44df62b33920aaec9ee6ccdbec932c05107 Mon Sep 17 00:00:00 2001 From: Eran Hammer Date: Sat, 20 Apr 2013 10:21:00 -0700 Subject: [PATCH] Closes #782 --- docs/API.md | 7 +++---- examples/cookie.js | 37 ++++++++++++++++++------------------- lib/payload.js | 4 ++-- lib/proxy.js | 35 ++++++++++++++++++----------------- lib/route.js | 4 ---- test/integration/payload.js | 15 +++++++++++++-- 6 files changed, 54 insertions(+), 48 deletions(-) diff --git a/docs/API.md b/docs/API.md index 3dc7a0e33..9fc65e39d 100755 --- a/docs/API.md +++ b/docs/API.md @@ -661,8 +661,8 @@ server.route({ method: 'GET', path: '/', config: { auth: 'simple' } }); Cookie authentication provides a simple cookie-based session management. The user has to be authenticated via other means, typically a web form, and upon successful authentication, receive a reply with a session cookie. Subsequent requests containing the session cookie are authenticated (the cookie uses [Iron](https://github.com/hueniverse/iron) to encrypt and sign the session content) and validated via the provided `validateFunc` -in case the cookie's encrypted content requires validation on each request. Note that cookie operates as a plain text secret with the property that -anyone in possession of the cookie content can use it to imperssonate its true owner. The `'cookie`' scheme takes the following required options: +in case the cookie's encrypted content requires validation on each request. Note that cookie operates as a bearer token and anyone in possession +of the cookie content can use it to imperssonate its true owner. The `'cookie`' scheme takes the following required options: - `scheme` - set to `'cookie'`. - `cookie` - the cookie name. Defaults to `'sid'`. - `password` - used for Iron cookie encoding. @@ -767,8 +767,7 @@ server.auth('session', { http.route([ { method: 'GET', path: '/', config: { handler: home, auth: true } }, - { method: 'GET', path: '/login', config: { handler: login, auth: { mode: 'try' } } }, - { method: 'POST', path: '/login', config: { handler: login, auth: { mode: 'try' } } }, + { method: '*', path: '/login', config: { handler: login, auth: { mode: 'try' } } }, { method: 'GET', path: '/logout', config: { handler: logout, auth: true } } ]); diff --git a/examples/cookie.js b/examples/cookie.js index 751d35188..d992bad4e 100755 --- a/examples/cookie.js +++ b/examples/cookie.js @@ -17,53 +17,53 @@ internals.users = { }; -internals.home = function (request) { +internals.home = function () { - request.reply('Login page

Welcome ' + request.auth.credentials.name + '!


'); + this.reply('Login page

Welcome ' + this.auth.credentials.name + '!


'); }; -internals.login = function (request) { +internals.login = function () { - if (request.auth.isAuthenticated) { - return request.reply.redirect('/'); + if (this.auth.isAuthenticated) { + return this.reply.redirect('/'); } var message = ''; var account = null; - if (request.method === 'post') { + if (this.method === 'post') { - if (!request.payload.username || - !request.payload.password) { + if (!this.payload.username || + !this.payload.password) { message = 'Missing username or password'; } else { - account = internals.users[request.payload.username]; + account = internals.users[this.payload.username]; if (!account || - account.password !== request.payload.password) { + account.password !== this.payload.password) { message = 'Invalid username or password'; } } } - if (request.method === 'get' || + if (this.method === 'get' || message) { - return request.reply('Login page' + (message ? '

' + message + '


' : '') + '
Username:
Password:
'); + return this.reply('Login page' + (message ? '

' + message + '


' : '') + '
Username:
Password:
'); } - request.auth.session.set(account); - return request.reply.redirect('/'); + this.auth.session.set(account); + return this.reply.redirect('/'); }; -internals.logout = function (request) { +internals.logout = function () { - request.auth.session.clear(); - return request.reply.redirect('/'); + this.auth.session.clear(); + return this.reply.redirect('/'); }; @@ -83,8 +83,7 @@ internals.main = function () { http.route([ { method: 'GET', path: '/', config: { handler: internals.home, auth: true } }, - { method: 'GET', path: '/login', config: { handler: internals.login, auth: { mode: 'try' } } }, - { method: 'POST', path: '/login', config: { handler: internals.login, auth: { mode: 'try' } } }, + { method: '*', path: '/login', config: { handler: internals.login, auth: { mode: 'try' } } }, { method: 'GET', path: '/logout', config: { handler: internals.logout, auth: true } } ]); diff --git a/lib/payload.js b/lib/payload.js index f09c5e6bf..60b2db443 100755 --- a/lib/payload.js +++ b/lib/payload.js @@ -27,7 +27,7 @@ exports.read = function (request, next) { // Levels are: 'stream', 'raw', 'parse' - var level = request.route.payload; + var level = request.route.payload || (request.route.validate.payload || request.method === 'post' || request.method === 'put' ? 'parse' : 'stream'); if (level === 'stream') { return next(); } @@ -125,7 +125,7 @@ exports.read = function (request, next) { var parse = function (payload) { - request.rawPayload = (payload.length ? payload : null); + request.rawPayload = payload; if (level !== 'parse') { // 'raw' return finish(); diff --git a/lib/proxy.js b/lib/proxy.js index f929a9e4a..c28b745ab 100755 --- a/lib/proxy.js +++ b/lib/proxy.js @@ -69,11 +69,11 @@ internals.Proxy.prototype.handler = function () { var isGet = (request.method === 'get' || request.method === 'head'); + // Parsed payload interface + if (self.settings.isCustomPostResponse || // Custom response method (isGet && request.route.cache.mode.server)) { // GET/HEAD with Cache - // Callback interface - delete options.headers['accept-encoding']; // Remove until Request supports unzip/deflate self.httpClient(options, function (err, res, payload) { @@ -85,29 +85,30 @@ internals.Proxy.prototype.handler = function () { return self.settings.postResponse(request, self.settings, res, payload); }); + + return; } - else { - // Stream interface + // Streamed payload interface - if (!isGet && - request.rawPayload) { + if (!isGet && + request.rawPayload && + request.rawPayload.length) { - options.headers['Content-Type'] = req.headers['content-type']; - options.body = request.rawPayload; - } + options.headers['Content-Type'] = req.headers['content-type']; + options.body = request.rawPayload; + } - var reqStream = self.httpClient(options); - reqStream.on('response', function (resStream) { + var reqStream = self.httpClient(options); + reqStream.on('response', function (resStream) { - request.reply(resStream); // Request._respond will pass-through headers and status code - }); + request.reply(resStream); // Request._respond will pass-through headers and status code + }); - if (!isGet && - request.route.payload === 'stream') { + if (!isGet && + !request.rawPayload) { - request.raw.req.pipe(reqStream); - } + request.raw.req.pipe(reqStream); } }); }; diff --git a/lib/route.js b/lib/route.js index 1054bb2c6..14a5aa722 100755 --- a/lib/route.js +++ b/lib/route.js @@ -50,10 +50,6 @@ exports = module.exports = internals.Route = function (options, server, env) { this.settings.validate = this.settings.validate || {}; Utils.assert(!this.settings.validate.payload || !this.settings.payload || this.settings.payload === 'parse', 'Route payload must be set to \'parse\' when payload validation enabled'); - - this.settings.payload = this.settings.payload || - (this.settings.validate.payload || this.method === 'post' || this.method === 'put' ? 'parse' : 'stream'); - Utils.assert(!this.settings.jsonp || typeof this.settings.jsonp === 'string', 'Bad route JSONP parameter name'); // Authentication configuration diff --git a/test/integration/payload.js b/test/integration/payload.js index 1d266f69b..3922be644 100755 --- a/test/integration/payload.js +++ b/test/integration/payload.js @@ -305,6 +305,7 @@ describe('Payload', function () { var server = new Hapi.Server('localhost', 0, { timeout: { client: 50 } }); server.route({ method: 'POST', path: '/', config: { handler: handler, payload: 'parse' } }); + server.route({ method: '*', path: '/any', handler: handler }); before(function (done) { @@ -324,6 +325,16 @@ describe('Payload', function () { this.push(null); }; + it('sets parse mode when route methos is * and request is POST or PUT', function (done) { + + server.inject({ url: '/any', method: 'POST', headers: { 'Content-Type': 'application/json' }, payload: '{ "key": "09876" }' }, function (res) { + + expect(res.statusCode).to.equal(200); + expect(res.result).to.equal('09876'); + done(); + }); + }); + it('sets the request payload with the streaming data', function (done) { var options = { @@ -461,7 +472,7 @@ describe('Payload', function () { var handler = function () { - this.reply('Success'); + this.reply('Success'); }; var server = new Hapi.Server(); @@ -547,7 +558,7 @@ describe('Payload', function () { var stats = Fs.statSync(path); var fileStream = Fs.createReadStream(path); var fileContents = Fs.readFileSync(path, { encoding: 'binary' }); - + var fileHandler = function (request) { expect(request.raw.req.headers['content-type']).to.contain('multipart/form-data');