question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Relative redirect URLs target proxy server instead of upstream server

See original GitHub issue

Hi! 👋

Firstly, thanks for your work on this project! 🙂

Today I used patch-package to patch follow-redirects@1.14.5 for the project I’m working on.

The problem I was running into is when using axios with a proxy and the upstream server returns a relative redirect URL, follow-redirects crafts an incorrect redirectUrl based on its cached this._currentUrl. It turns out that this URL is computed by using url.format(this._options), which doesn’t work correctly when a proxy server is configured because this._options is assumed to be an object containing valid Url parts, when it’s in fact an object containing ClientRequest options with no guarantee that their semantics matches Url parts.

More specifically, the axios http adapter that uses follow-redirects modifies the original options by setting the host, hostname and port to the proxy’s own host/port values, and path property to the full upstream server URL. (This, from what I know, is the correct way to configure a Node.js http(s) request to go through a proxy.)

As a result, parsing the ClientRequest options as if it were a URL results in a weird URL like http://<proxy-host-and-port>/https://<upstream-host-and-port>/<upstream-path>, and when follow-redirects handles a relative redirect URL, it then uses this incorrect currentUrl as the base URL to use with url.resolve, and causes the redirected URL to be based the proxy host rather than the upstream host. A proxy like mitmproxy then detects the redirect as an attempt to connect to itself through itself and immediately breaks the connection with a 502 error.

My solution is to try to resolve the request options’ path property against this (semantically risky) “current URL”. If path is an absolute URL, it will be used instead; if it’s relative, then the original “current URL” will be unchanged. This makes follow-redirects “proxy-friendly” without explicitly adding proxy features.

Here is the diff that solved my problem:

diff --git a/node_modules/follow-redirects/index.js b/node_modules/follow-redirects/index.js
index 7605d7d..eb0009c 100644
--- a/node_modules/follow-redirects/index.js
+++ b/node_modules/follow-redirects/index.js
@@ -277,7 +277,7 @@ RedirectableRequest.prototype._performRequest = function () {
   // Create the native request
   var request = this._currentRequest =
         nativeProtocol.request(this._options, this._onNativeResponse);
-  this._currentUrl = url.format(this._options);
+  this._currentUrl = url.resolve(url.format(this._options), this._options.path)
 
   // Set up event handlers
   request._redirectable = this;

Note that this was previously reported (https://github.com/follow-redirects/follow-redirects/issues/85) but the example snippet seemed to be incorrectly setup. In my case, I could fully reproduce this issue using mitmproxy and a local Node http server (very similar to that issue’s http server, actually). This setup worked flawlessly with curl, and it works with absolute redirects.

This issue body was partially generated by patch-package.

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:9 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
RubenVerborghcommented, Dec 2, 2021

Or really just https://www.twilio.com/blog/node-js-proxy-server since we’re using express already anyway in the tests.

1reaction
RubenVerborghcommented, Dec 2, 2021

Firstly, thanks for your work on this project! 🙂

Well thank you for such a detailed problem description!

BTW, I am willing to draft up a proper PR with tests, if you are willing to consider taking this fix.

You’re amazing.

The first thing I’d need is one/a couple of example cases that fail. So those tests indeed, perhaps even with an actual proxy in the test case so we know it works properly.

I’m not 100% convinced yet by the fix; it might need to be a bit more elaborate, with explicit detection of the proxy case. But we can figure that out when the tests are in place.

Thanks in advance!

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to handle relative urls correctly with a nginx reverse proxy
The problem is basically that using a proxy_pass directive won't rewrite HTML code and therefor relative URL's to for instance a img ...
Read more >
Modes of operation - mitmproxy docs
Your client explicitly connects to mitmproxy and mitmproxy explicitly connects to the target server. # Transparent Proxy. mitmdump --mode transparent. In ...
Read more >
nginx - Intercepting backend 301/302 redirects (proxy_pass ...
I succeeded in solving a more generic case when a redirect location can be any external URL. server { ... location / {...
Read more >
minio behind proxy and presigned urls · Issue #6853 - GitHub
We cannot use the presigned urls because the server generates the url relative to /, not /minio (i.e. example.com/bucketname/ instead of example ...
Read more >
HTTP connection management - Envoy Proxy
Envoy is configured to allow redirects on the original route, and sends a new GET request to Upstream 2, to fetch http://baz.com/eep with...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found