diff --git a/README.md b/README.md index b2641908..1719d809 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,9 @@ proxy requests. The following options are supported: * array of strings `originWhitelist` - If set, requests whose origin is not listed are blocked. If this list is empty, all origins are allowed. Example: `['https://good.example.com', 'http://good.example.com']` +* function `handleInitialRequest` - If set, it is called with the request, response and a parsed + URL of the requested destination (null if unavailable). If the function returns true, the request + will not be handled further. It is the responsibility of the function to handle the request. * function `checkRateLimit` - If set, it is called with the origin (string) of the request. If this function returns a non-empty string, the request is rejected and the string is send to the client. * boolean `redirectSameOrigin` - If true, requests to URLs from the same origin will not be proxied but redirected. diff --git a/lib/cors-anywhere.js b/lib/cors-anywhere.js index 90026448..0897f940 100644 --- a/lib/cors-anywhere.js +++ b/lib/cors-anywhere.js @@ -256,6 +256,7 @@ function parseURL(req_url) { // Request handler factory function getHandler(options, proxy) { var corsAnywhere = { + handleInitialRequest: null, // Function that may handle the request instead, by returning a truthy value. getProxyForUrl: getProxyForUrl, // Function that specifies the proxy to use maxRedirects: 5, // Maximum number of redirects to be followed. originBlacklist: [], // Requests from these origins will be blocked. @@ -310,6 +311,10 @@ function getHandler(options, proxy) { var location = parseURL(req.url.slice(1)); + if (corsAnywhere.handleInitialRequest && corsAnywhere.handleInitialRequest(req, res, location)) { + return; + } + if (!location) { // Invalid API call. Show how to correctly use the API showUsage(corsAnywhere.helpFile, cors_headers, res); diff --git a/test/test.js b/test/test.js index 3795a506..b3a47a41 100644 --- a/test/test.js +++ b/test/test.js @@ -620,6 +620,53 @@ describe('originWhitelist', function() { }); }); +describe('handleInitialRequest', function() { + afterEach(stopServer); + + it('GET / with handleInitialRequest', function(done) { + cors_anywhere = createServer({ + handleInitialRequest: function(req, res, location) { + res.writeHead(419); + res.end('res:' + (location && location.href)); + return true; + }, + }); + cors_anywhere_port = cors_anywhere.listen(0).address().port; + request(cors_anywhere) + .get('/') + .expect(419, 'res:null', done); + }); + + it('GET /dummy with handleInitialRequest', function(done) { + cors_anywhere = createServer({ + handleInitialRequest: function(req, res, location) { + res.writeHead(419); + res.end('res:' + (location && location.href)); + return true; + }, + }); + cors_anywhere_port = cors_anywhere.listen(0).address().port; + request(cors_anywhere) + .get('/dummy') + .expect(419, 'res:http://dummy/', done); + }); + + it('GET /example.com with handleInitialRequest', function(done) { + cors_anywhere = createServer({ + handleInitialRequest: function(req, res, location) { + res.setHeader('X-Extra-Header', 'hello ' + location.href); + }, + }); + cors_anywhere_port = cors_anywhere.listen(0).address().port; + request(cors_anywhere) + .get('/example.com') + .set('Origin', 'null') + .expect('Access-Control-Allow-Origin', '*') + .expect('X-Extra-Header', 'hello http://example.com/') + .expect(200, 'Response from example.com', done); + }); +}); + describe('checkRateLimit', function() { afterEach(stopServer);