cors-anywhere
cors-anywhere copied to clipboard
Updated http-proxy dependency to ^1.15.2
Fixes #182
CORS Anywhere relies on (undocumented) internals of the http-proxy
library. Use a specific version instead of a version range to ensure that CORS Anywhere is guaranteed to work.
Look for "1.11.1" at lib/cors-anywhere.js, verify that the logic still makes sense and replace "1.11.1" with the chosen value.
A bunch of unit tests are also failing with this PR (see the results from Travis), they must pass before the PR can be merged.
since cors-anywhere uses an old http-proxy version, it is impossible to use cors-anywhere and a modern http-proxy's "selfHandleResponse" flag to intercept and rewrite the steams if necessary
https://github.com/http-party/node-http-proxy/blob/v1.11.1/lib/http-proxy/passes/web-incoming.js#L157
no "selfHandleResponse" in that old version
27b62a2d73a1b7cdda7239ea6de9c140bf78b11d
lib/cors-anywhere.js | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 92 insertions(+), 3 deletions(-)
diff --git a/lib/cors-anywhere.js b/lib/cors-anywhere.js
index 1a1c372..4c8da25 100644
--- a/lib/cors-anywhere.js
+++ b/lib/cors-anywhere.js
@@ -8,6 +8,7 @@ var net = require('net');
var url = require('url');
var regexp_tld = require('./regexp-top-level-domain');
var getProxyForUrl = require('proxy-from-env').getProxyForUrl;
+const zlib = require('zlib');
var help_text = {};
function showUsage(help_file, headers, response) {
@@ -44,6 +45,68 @@ function isValidHostName(hostname) {
);
}
+const { Transform } = require('stream')
+
+class Filter extends Transform {
+
+ constructor(bodyEnc, destURLString) {
+ super({
+ //readableObjectMode: true,
+ //writableObjectMode: true
+ })
+ this.bufArr = [];
+ this.bodyEnc = bodyEnc;
+ this.destURLString = destURLString;
+ }
+
+ _transform(chunk, encoding, next) {
+ //save ref to buffer-array in array of buffer-arrays
+ //concat array of buffer-arrays later to avoid O(n^2) copying
+ this.bufArr.push(chunk);
+ //do not pass on data
+ return next();
+ //commented out, passes chunks in chain to write sink (dont do that)
+ //null is error obj
+ //return next(null, chunk);
+ }
+ _flush(next) {
+ var error;
+ var uncomp;
+ var compBuf = Buffer.concat(this.bufArr);
+ if (this.bodyEnc == 'gzip') {
+ uncomp = zlib.gunzipSync(compBuf);
+ } else if (this.bodyEnc == 'br') {
+ uncomp = zlib.brotliDecompressSync(compBuf);
+ } else if (this.bodyEnc == 'none'){
+ uncomp = compBuf;
+ } else {
+ error = new Error("HTML Transformer must have encoding type");
+ }
+ var stringBody = uncomp.toString('utf8');
+ debugger;
+ //dont match cdn-cgi directly, and use relative URLs, so if some bizzare
+ //debuggin reason this goes through TWO CORS proxies, both can rewrite the
+ //HTML and correctly handoff
+ stringBody = stringBody.replace("background-image:url('/", "background-image:url('/"+this.destURLString);
+ stringBody = stringBody.replace('href="/', 'href="/'+this.destURLString);
+ stringBody = stringBody.replace('src="/', 'src="/'+this.destURLString);
+ stringBody = stringBody.replace('action="/', 'action="/'+this.destURLString);
+ uncomp = Buffer.from(stringBody);
+ if (this.bodyEnc == 'gzip') {
+ compBuf = zlib.gzipSync(uncomp);
+ } else if (this.bodyEnc == 'br') {
+ compBuf = zlib.brotliCompressSync(uncomp);
+ } else if (this.bodyEnc == 'none'){
+ compBuf = uncomp;
+ }
+ //pass buffer to outgoing to client stream
+ next(error,compBuf);
+ }
+
+}
+
+
+
/**
* Adds CORS headers to the response headers.
*
@@ -112,6 +175,22 @@ function proxyRequest(req, res, proxy) {
return proxyReqOn.call(this, 'response', function(proxyRes) {
if (onProxyResponse(proxy, proxyReq, proxyRes, req, res)) {
try {
+ // test if Cloudflare Captcha screen
+ if (proxyRes.headers["cf-chl-bypass"]) {
+// Hook "proxyRes.pipe(res);" in ancient v1.11.1 http-proxy version before
+// "selfHandleResponse" was introduced because cors-anywhere forces using an
+// old http-proxy version
+// https://github.com/http-party/node-http-proxy/blob/v1.11.1/lib/http-proxy/passes/web-incoming.js#L157
+ var oldPipeFunc = proxyRes.pipe;
+ proxyRes.pipe = function (dest, pipeOpts) {
+ var enc = this.headers["content-encoding"] || 'none';
+ var url = new URL(this.req.agent.protocol+"//"+this.req.getHeader("Host"));
+ url.port = this.req.socket.remotePort;
+ var transformer = new Filter(enc, url.toString());
+ var stream = oldPipeFunc.call(this, transformer);
+ stream.pipe(dest, pipeOpts);
+ };
+ }
listener(proxyRes);
} catch (err) {
// Wrap in try-catch because an error could occur:
I cooked this up to selectively rewrite HTML inside cors-anywhere but it took too long and its more class monkey method patching and it seems very fragile. Performance is poor in TTTB/etc if the HTML is rewritten, but its very rare in my use case (99% of HTTP reqs go through XHR to API endpoint, rarely a cloudflare captcha comes up and it must be manually solved by the user in an iframe and the XHR JSON POST repeated).
I have the same issue. yarn resolutions feature helped to solve it.
"resolutions": {
"http-proxy": ">=1.15.2"
},