Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updated http-proxy dependency to ^1.15.2 #183

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

idmadj
Copy link

@idmadj idmadj commented Jul 8, 2019

Fixes #182

Fixes issue where cors-anywhere fails when used alongside browserify.
@Rob--W
Copy link
Owner

Rob--W commented Jul 9, 2019

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.

@bulk88
Copy link
Contributor

bulk88 commented Oct 5, 2020

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).

@artyom-88
Copy link

I have the same issue. yarn resolutions feature helped to solve it.

  "resolutions": {
    "http-proxy": ">=1.15.2"
  },

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Cors Anywhere fails when used alongside browserify
4 participants