req: Cache the request IP

This commit is contained in:
PlasmaPower 2016-04-03 20:30:06 -06:00 committed by jongleberry
parent 826ad83db6
commit 54e58d3523
4 changed files with 36 additions and 31 deletions

View file

@ -158,6 +158,7 @@ module.exports = class Application extends Emitter {
keys: this.keys, keys: this.keys,
secure: request.secure secure: request.secure
}); });
request.ip = request.ips[0] || req.socket.remoteAddress || '';
context.accept = request.accept = accepts(req); context.accept = request.accept = accepts(req);
context.state = {}; context.state = {};
return context; return context;

View file

@ -366,19 +366,6 @@ module.exports = {
return 'https' == this.protocol; return 'https' == this.protocol;
}, },
/**
* Return the remote address, or when
* `app.proxy` is `true` return
* the upstream addr.
*
* @return {String}
* @api public
*/
get ip() {
return this.ips[0] || this.socket.remoteAddress || '';
},
/** /**
* When `app.proxy` is `true`, parse * When `app.proxy` is `true`, parse
* the "X-Forwarded-For" ip address list. * the "X-Forwarded-For" ip address list.

View file

@ -4,18 +4,18 @@
const Stream = require('stream'); const Stream = require('stream');
const Koa = require('../..'); const Koa = require('../..');
module.exports = (req, res) => { module.exports = (req, res, app) => {
const socket = new Stream.Duplex(); const socket = new Stream.Duplex();
req = req || { headers: {}, socket: socket, __proto__: Stream.Readable.prototype }; req = Object.assign({ headers: {}, socket }, Stream.Readable.prototype, req);
res = res || { _headers: {}, socket: socket, __proto__: Stream.Writable.prototype }; res = Object.assign({ _headers: {}, socket }, Stream.Writable.prototype, res);
req.socket = req.socket || socket; req.socket.remoteAddress = req.socket.remoteAddress || '127.0.0.1';
res.socket = res.socket || socket; app = app || new Koa();
res.getHeader = k => res._headers[k.toLowerCase()]; res.getHeader = k => res._headers[k.toLowerCase()];
res.setHeader = (k, v) => res._headers[k.toLowerCase()] = v; res.setHeader = (k, v) => res._headers[k.toLowerCase()] = v;
res.removeHeader = (k, v) => delete res._headers[k.toLowerCase()]; res.removeHeader = (k, v) => delete res._headers[k.toLowerCase()];
return (new Koa()).createContext(req, res); return app.createContext(req, res);
}; };
module.exports.request = (req, res) => module.exports(req, res).request; module.exports.request = (req, res, app) => module.exports(req, res, app).request;
module.exports.response = (req, res) => module.exports(req, res).response; module.exports.response = (req, res, app) => module.exports(req, res, app).response;

View file

@ -1,32 +1,49 @@
'use strict'; 'use strict';
const request = require('../helpers/context').request; const assert = require('assert');
const Stream = require('stream');
const Koa = require('../..');
const Request = require('../helpers/context').request;
describe('req.ip', () => { describe('req.ip', () => {
describe('with req.ips present', () => { describe('with req.ips present', () => {
it('should return req.ips[0]', () => { it('should return req.ips[0]', () => {
const req = request(); const app = new Koa();
req.app.proxy = true; const req = { headers: {}, socket: new Stream.Duplex() };
req.header['x-forwarded-for'] = '127.0.0.1'; app.proxy = true;
req.headers['x-forwarded-for'] = '127.0.0.1';
req.socket.remoteAddress = '127.0.0.2'; req.socket.remoteAddress = '127.0.0.2';
req.ip.should.equal('127.0.0.1'); const request = Request(req, undefined, app);
request.ip.should.equal('127.0.0.1');
}); });
}); });
describe('with no req.ips present', () => { describe('with no req.ips present', () => {
it('should return req.socket.remoteAddress', () => { it('should return req.socket.remoteAddress', () => {
const req = request(); const req = { socket: new Stream.Duplex() };
req.socket.remoteAddress = '127.0.0.2'; req.socket.remoteAddress = '127.0.0.2';
req.ip.should.equal('127.0.0.2'); const request = Request(req);
request.ip.should.equal('127.0.0.2');
}); });
describe('with req.socket.remoteAddress not present', () => { describe('with req.socket.remoteAddress not present', () => {
it('should return an empty string', () => { it('should return an empty string', () => {
const req = request(); const socket = new Stream.Duplex();
req.socket.remoteAddress = null; Object.defineProperty(socket, 'remoteAddress', {
req.ip.should.equal(''); get: () => undefined, // So that the helper doesn't override it with a reasonable value
set: () => {}
});
assert.equal(Request({ socket }).ip, '');
}); });
}); });
}); });
it('should be cached', () => {
const req = { socket: new Stream.Duplex() };
req.socket.remoteAddress = '127.0.0.2';
const request = Request(req);
req.socket.remoteAddress = '127.0.0.1';
request.ip.should.equal('127.0.0.2');
});
}); });