mirror of
https://github.com/d0zingcat/cors-anywhere.git
synced 2026-05-13 15:09:25 +00:00
Bind proxyRequest event handler once per proxy
Optimization: Create onProxyResponse handler only once, and bind it only once per HttpProxy instance (opposed to binding it for every request)
This commit is contained in:
@@ -84,12 +84,9 @@ function isForbidden(host) {
|
||||
* @param req {ServerRequest} Incoming http request
|
||||
* @param res {ServerResponse} Outgoing (proxied) http request
|
||||
* @param proxy {HttpProxy}
|
||||
* @param location {object} See parseURL
|
||||
* @param requestState.proxyBaseUrl {string} Base URL of the CORS API endpoint.
|
||||
* @param requestState.maxRedirects {number} Maximum number of redirects
|
||||
* @param requestState.redirectCount_ {number} Internally used to count redirects
|
||||
*/
|
||||
function proxyRequest(req, res, proxy, location, requestState) {
|
||||
function proxyRequest(req, res, proxy) {
|
||||
var location = req.corsAnywhereRequestState.location;
|
||||
if (isForbidden(location.hostname)) {
|
||||
res.writeHead(403, 'Refused to visit', withCORS({'Location': location.full_url}, req));
|
||||
return;
|
||||
@@ -99,42 +96,6 @@ function proxyRequest(req, res, proxy, location, requestState) {
|
||||
// Let the "Host" header be the host part of the path (including port, if specified).
|
||||
req.headers.host = location.host;
|
||||
|
||||
// "Allow observer to modify headers or abort response"
|
||||
// https://github.com/nodejitsu/node-http-proxy/blob/ebbba73e/lib/node-http-proxy/http-proxy.js#L321-L322
|
||||
proxy.once('proxyResponse', function(req, res, response) {
|
||||
|
||||
var statusCode = response.statusCode;
|
||||
// Handle redirects
|
||||
if (statusCode === 301 || statusCode === 302 || statusCode === 303 || statusCode === 307 || statusCode === 308) {
|
||||
var locationHeader = response.headers['location'];
|
||||
if (locationHeader) {
|
||||
locationHeader = url.resolve(location.full_url, locationHeader);
|
||||
|
||||
if (statusCode === 301 || statusCode === 302 || statusCode === 303) {
|
||||
// Exclude 307 & 308, because they are rare, and require preserving the method + request body
|
||||
requestState.redirectCount_ = requestState.requestState_ + 1 || 1;
|
||||
if (requestState.redirectCount_ <= requestState.maxRedirects) {
|
||||
req.method = 'GET';
|
||||
proxyRequest(req, res, proxy, parseURL(locationHeader), requestState);
|
||||
|
||||
response.end();
|
||||
// The proxyResponse event is wrapped in a try-catch, throwing an error
|
||||
// prevents the response from being passed to the client.
|
||||
throw new Error('Prevent current response from being passed through.');
|
||||
}
|
||||
}
|
||||
response.headers['location'] = requestState.proxyBaseUrl + '/' + locationHeader;
|
||||
}
|
||||
}
|
||||
withCORS(response.headers, req);
|
||||
|
||||
// Don't slip through cookies
|
||||
delete response.headers['set-cookie'];
|
||||
delete response.headers['set-cookie2'];
|
||||
|
||||
response.headers['x-request-url'] = location.full_url;
|
||||
});
|
||||
|
||||
// Start proxying the request
|
||||
proxy.proxyRequest(req, res, {
|
||||
host: location.hostname,
|
||||
@@ -143,9 +104,67 @@ function proxyRequest(req, res, proxy, location, requestState) {
|
||||
https: location.isHttps
|
||||
}
|
||||
});
|
||||
if (requestState.redirectCount_) {
|
||||
req.emit('end');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* "Allow observer to modify headers or abort response"
|
||||
* https://github.com/nodejitsu/node-http-proxy/blob/ebbba73e/lib/node-http-proxy/http-proxy.js#L321-L322
|
||||
*
|
||||
* This method modifies the response headers of the proxied response.
|
||||
* If a redirect is detected, the response is not sent to the client,
|
||||
* and a new request is initiated.
|
||||
*
|
||||
* @param req {IncomingMessage} Incoming HTTP request, augmented with property corsAnywhereRequestState
|
||||
* @param req.corsAnywhereRequestState {object}
|
||||
* @param req.corsAnywhereRequestState.location {object} See parseURL
|
||||
* @param req.corsAnywhereRequestState.proxyBaseUrl {string} Base URL of the CORS API endpoint
|
||||
* @param req.corsAnywhereRequestState.maxRedirects {number} Maximum number of redirects
|
||||
* @param req.corsAnywhereRequestState.redirectCount_ {number} Internally used to count redirects
|
||||
* @param res {ServerResponse} Outgoing (proxied) HTTP request
|
||||
* @param response {ClientRequest} The
|
||||
*
|
||||
* @this {HttpProxy}
|
||||
*/
|
||||
function onProxyResponse(req, res, response) {
|
||||
/* jshint validthis:true */
|
||||
var proxy = this;
|
||||
var requestState = req.corsAnywhereRequestState;
|
||||
|
||||
var statusCode = response.statusCode;
|
||||
// Handle redirects
|
||||
if (statusCode === 301 || statusCode === 302 || statusCode === 303 || statusCode === 307 || statusCode === 308) {
|
||||
var locationHeader = response.headers['location'];
|
||||
if (locationHeader) {
|
||||
locationHeader = url.resolve(requestState.location.full_url, locationHeader);
|
||||
|
||||
if (statusCode === 301 || statusCode === 302 || statusCode === 303) {
|
||||
// Exclude 307 & 308, because they are rare, and require preserving the method + request body
|
||||
requestState.redirectCount_ = requestState.requestState_ + 1 || 1;
|
||||
if (requestState.redirectCount_ <= requestState.maxRedirects) {
|
||||
req.method = 'GET';
|
||||
requestState.location = parseURL(locationHeader);
|
||||
proxyRequest(req, res, proxy);
|
||||
// TODO: Is it possible to trigger reverseProxy.end() (from node-http-proxy) without
|
||||
// manually emiting the "event" event on req?
|
||||
req.emit('end');
|
||||
|
||||
response.end();
|
||||
// The proxyResponse event is wrapped in a try-catch, throwing an error
|
||||
// prevents the response from being passed to the client.
|
||||
throw new Error('Prevent current response from being passed through.');
|
||||
}
|
||||
}
|
||||
response.headers['location'] = requestState.proxyBaseUrl + '/' + locationHeader;
|
||||
}
|
||||
}
|
||||
withCORS(response.headers, req);
|
||||
|
||||
// Don't slip through cookies
|
||||
delete response.headers['set-cookie'];
|
||||
delete response.headers['set-cookie2'];
|
||||
|
||||
response.headers['x-request-url'] = requestState.location.full_url;
|
||||
}
|
||||
|
||||
|
||||
@@ -265,10 +284,19 @@ var getHandler = exports.getHandler = function(options) {
|
||||
delete req.headers[header];
|
||||
});
|
||||
|
||||
proxyRequest(req, res, proxy, location, {
|
||||
|
||||
req.corsAnywhereRequestState = {
|
||||
location: location,
|
||||
maxRedirects: corsAnywhere.maxRedirects,
|
||||
proxyBaseUrl: proxyBaseUrl
|
||||
});
|
||||
};
|
||||
|
||||
if (!proxy.hasCorsAnywhereResponseHandler) { // Runs once per HttpProxy instance
|
||||
proxy.on('proxyResponse', onProxyResponse);
|
||||
proxy.hasCorsAnywhereResponseHandler = true;
|
||||
}
|
||||
|
||||
proxyRequest(req, res, proxy);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user