diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3cd27af --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +coverage/ +node_modules/ +npm-debug.log diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..f034de0 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,15 @@ +language: node_js +node_js: + - "0.6" + - "0.8" + - "0.10" + - "0.11" +matrix: + allow_failures: + - node_js: "0.11" + fast_finish: true +script: + - "test $TRAVIS_NODE_VERSION != '0.6' || npm test" + - "test $TRAVIS_NODE_VERSION = '0.6' || npm run-script test-travis" +after_script: + - "test $TRAVIS_NODE_VERSION = '0.10' && npm install coveralls@2 && cat ./coverage/lcov.info | coveralls" diff --git a/HISTORY.md b/HISTORY.md new file mode 100644 index 0000000..97fa1d1 --- /dev/null +++ b/HISTORY.md @@ -0,0 +1,4 @@ +0.1.0 / 2014-09-21 +================== + + * Initial release diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..b7dce6c --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +(The MIT License) + +Copyright (c) 2014 Douglas Christopher Wilson + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..2b4988f --- /dev/null +++ b/README.md @@ -0,0 +1,53 @@ +# forwarded + +[![NPM Version][npm-image]][npm-url] +[![NPM Downloads][downloads-image]][downloads-url] +[![Node.js Version][node-version-image]][node-version-url] +[![Build Status][travis-image]][travis-url] +[![Test Coverage][coveralls-image]][coveralls-url] + +Parse HTTP X-Forwarded-For header + +## Installation + +```sh +$ npm install forwarded +``` + +## API + +```js +var forwarded = require('forwarded') +``` + +### forwarded(req) + +```js +var addresses = forwarded(req) +``` + +Parse the `X-Forwarded-For` header from the request. Returns an array +of the addresses, including the socket address for the `req`. In reverse +order (i.e. index `0` is the socket address and the last index is the +furthest address, typically the end-user). + +## Testing + +```sh +$ npm test +``` + +## License + +[MIT](LICENSE) + +[npm-image]: https://img.shields.io/npm/v/forwarded.svg?style=flat +[npm-url]: https://npmjs.org/package/forwarded +[node-version-image]: https://img.shields.io/node/v/forwarded.svg?style=flat +[node-version-url]: http://nodejs.org/download/ +[travis-image]: https://img.shields.io/travis/jshttp/forwarded.svg?style=flat +[travis-url]: https://travis-ci.org/jshttp/forwarded +[coveralls-image]: https://img.shields.io/coveralls/jshttp/forwarded.svg?style=flat +[coveralls-url]: https://coveralls.io/r/jshttp/forwarded?branch=master +[downloads-image]: https://img.shields.io/npm/dm/forwarded.svg?style=flat +[downloads-url]: https://npmjs.org/package/forwarded diff --git a/index.js b/index.js new file mode 100644 index 0000000..2f5c340 --- /dev/null +++ b/index.js @@ -0,0 +1,35 @@ +/*! + * forwarded + * Copyright(c) 2014 Douglas Christopher Wilson + * MIT Licensed + */ + +/** + * Module exports. + */ + +module.exports = forwarded + +/** + * Get all addresses in the request, using the `X-Forwarded-For` header. + * + * @param {Object} req + * @api public + */ + +function forwarded(req) { + if (!req) { + throw new TypeError('argument req is required') + } + + // simple header parsing + var proxyAddrs = (req.headers['x-forwarded-for'] || '') + .split(/ *, */) + .filter(Boolean) + .reverse() + var socketAddr = req.connection.remoteAddress + var addrs = [socketAddr].concat(proxyAddrs) + + // return all addresses + return addrs +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..d447523 --- /dev/null +++ b/package.json @@ -0,0 +1,33 @@ +{ + "name": "forwarded", + "description": "Parse HTTP X-Forwarded-For header", + "version": "0.1.0", + "contributors": [ + "Douglas Christopher Wilson " + ], + "license": "MIT", + "keywords": [ + "x-forwarded-for", + "http", + "req" + ], + "repository": "jshttp/forwarded", + "devDependencies": { + "istanbul": "0.3.2", + "mocha": "~1.21.4" + }, + "files": [ + "LICENSE", + "HISTORY.md", + "README.md", + "index.js" + ], + "engines": { + "node": ">= 0.6" + }, + "scripts": { + "test": "mocha --reporter spec --bail --check-leaks test/", + "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/", + "test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/" + } +} diff --git a/test/test.js b/test/test.js new file mode 100644 index 0000000..3c2dc19 --- /dev/null +++ b/test/test.js @@ -0,0 +1,37 @@ + +var assert = require('assert') +var forwarded = require('..') + +describe('forwarded(req)', function () { + it('should require req', function () { + assert.throws(forwarded.bind(null), /argument req.*required/) + }) + + it('should work with X-Forwarded-For header', function () { + var req = createReq('127.0.0.1') + assert.deepEqual(forwarded(req), ['127.0.0.1']) + }) + + it('should include entries from X-Forwarded-For', function () { + var req = createReq('127.0.0.1', { + 'x-forwarded-for': '10.0.0.2, 10.0.0.1' + }) + assert.deepEqual(forwarded(req), ['127.0.0.1', '10.0.0.1', '10.0.0.2']) + }) + + it('should skip blank entries', function () { + var req = createReq('127.0.0.1', { + 'x-forwarded-for': '10.0.0.2,, 10.0.0.1' + }) + assert.deepEqual(forwarded(req), ['127.0.0.1', '10.0.0.1', '10.0.0.2']) + }) +}) + +function createReq(socketAddr, headers) { + return { + connection: { + remoteAddress: socketAddr + }, + headers: headers || {} + }; +}