Rob--W / cors-anywhere

CORS Anywhere is a NodeJS reverse proxy which adds CORS headers to the proxied request.
MIT License
8.62k stars 6.03k forks source link

performance problem, cors-anywhere doesn't use outbound HTTP keep-alive #464

Closed bulk88 closed 1 year ago

bulk88 commented 1 year ago

In evaluating the performance of this nodeJS package, vs rewriting in Cloudflare Workers/Deno Deploy or Deno/Bun/perl/C if Im desperate. Cloudflare workers as a CORS proxy is unusable for my very unique use case, my target content origin is also CF based, its webmaster decided to block CF's IPs.

I noticed CORS-A inherits a performance degradation from https://github.com/http-party/node-http-proxy . node-http-proxy does NOT implement keep-alive, therefore cors-anywhere doesn't either. All outbound connections to a content server, are "Connection: close". That means HTTPS TLS negotiation every single time for all requests. I mean, its 1-2 ms ping, on a same city DC to DC fiber link, but those extra 3-6ms will add up and add up, if a UA page load has 2-5 CORS proxy requests before drawing content to eyeball.

CORS-A and node-http-proxy are starting to show their age. Lack of H2 and H2C (most cloud providers now offer H2 clear, from their edge proxy, TLS-removed, to your process) incoming, and no HTTP/S 1.1 keep-alive, and no H2 outbound.

PS. OT JSONP support would be nice, for some ancient Win2K embedded "adtech" screens I have, but I switch to a cloudflare worker for that and efficiency reasons, (99% of content servers doesn't block CF IPs), plus JSONP and IE 5, maybe IE 6, have performance problems, doing a 2nd string eval() on 800KB-1.4MB of JS-code (really JSON) on P2/P3 machines. So I break the typical convention of JSONP proxies returning {"status": 200; "content-type": "application/json"; "content": "{\"foo\":true}"} and just inline the content server JSON into JSONP, mild security problems if content server is NOT TRUSTED and returns malicious/malformed JSON, to avoid 2 rounds through the JS parser in ancient IE.

fetch("https://cors-anywhere.herokuapp.com/http://scooterlabs.com/echo")
Simple webservice echo test: make a request to this endpoint to return the HTTP request parameters and headers. Results available in plain text, JSON, or XML formats. See http://www.cantoni.org/2012/01/08/simple-webservice-echo-test for more details, or https://github.com/bcantoni/echotest for source code.

Array
(
    [method] => GET
    [headers] => Array
        (
            [Host] => scooterlabs.com
            [Connection] => close
            [Sec-Ch-Ua] => "(Not(A:Brand";v="8", "Chromium";v="98"
            [Sec-Ch-Ua-Mobile] => ?0
            [User-Agent] => Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.0.0 Safari/537.36
            [Sec-Ch-Ua-Platform] => "Windows"
            [Accept] => */*
            [Origin] => https://example.org
            [Sec-Fetch-Site] => cross-site
            [Sec-Fetch-Mode] => cors
            [Sec-Fetch-Dest] => empty
            [Referer] => https://example.org/
            [Accept-Encoding] => gzip, deflate, br
            [Accept-Language] => en-US,en;q=0.9
            [X-Forwarded-For] => 72.229.170.XXX
            [X-Forwarded-Proto] => https
            [X-Forwarded-Port] => 443
        )

    [request] => Array
        (
        )

    [client_ip] => 72.229.170.XXX
    [time_utc] => 2023-06-16T23:24:10+0000
    [info] => Echo service from Scooterlabs (http://www.scooterlabs.com)
)
Rob--W commented 1 year ago

For the scenario of repeatedly connecting to the same server, closing the connection is indeed suboptimal.

CORS Anywhere, as the name implies (and the functionality shows) is designed to connect to arbitrary destinations on behalf of different users. Keeping open connections around is wasteful from this perspective.

Another potential concern of keeping connections open is reusing the same connection for different clients. This is a lesser concern though, because by design CORS anywhere is meant for accessing public resources only.