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

feat: allow sending a custom proxy timeout error #1650

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

Conversation

rowanmanning
Copy link

When using proxyTimeout it's very difficult to tell the difference between a regular socket hangup and a timeout because, in both cases, an ECONNRESET error is thrown. Ideally we should be able to identify when a proxy request has failed because it took too long, this would allow us to do things like send appropriate 504 status code.

Suddenly throwing a different error would probably be considered a breaking change because it's possible that users of http-proxy are relying on the ECONNRESET error. I decided to add the custom timeout error behind a new option for now so that people can opt into using it.

If you set this option:

var proxy = httpProxy.createProxyServer({
  target: 'http://example.com',
  proxyTimeout: 100,
  proxyTimeoutCustomError: true
});

Then the error that gets thrown will have a message of "The proxy request timed out" and a code of ETIMEDOUT to match Node.js: https://nodejs.org/api/errors.html#common-system-errors

This allows for custom error handling code like this:

proxy.on('error', function(err, req, res) {
  if (err.code === 'ETIMEDOUT') {
    res.writeHead(504);
  } else {
    res.writeHead(503);
  }
  // ...
});

A note on implementation

I had to switch from request.abort() to request.destroy() for this to work. request.abort() has been deprecated since Node.js v14.1.0 and request.destroy() has been available since Node.js v0.3.0 so I think this is a safe bet. If you're worried about it then I could always switch to request.abort() for the case when proxyTimeoutCustomError is falsy.


Resolves #1331.

When using `proxyTimeout` it's very difficult to tell the difference
between a regular socket hangup and a timeout because, in both cases, an
`ECONNRESET` error is thrown. Ideally we should be able to identify when
a proxy request has failed because it took too long, this would allow us
to do things like send appropriate `504` status code.

Suddenly throwing a different error would probably be considered a
breaking change because it's possible that users of http-proxy are
relying on the `ECONNRESET` error. I decided to add the custom timeout
error behind a new option for now so that people can opt into using it.

If you set this option:

```js
var proxy = httpProxy.createProxyServer({
  target: 'http://example.com',
  proxyTimeout: 100,
  proxyTimeoutCustomError: true
});
```

Then the error that gets thrown will have a message of `"The proxy
request timed out"` and a code of `ETIMEDOUT` to match Node.js:
https://nodejs.org/api/errors.html#common-system-errors

This allows for custom error handling code like this:

```js
proxy.on('error', function(err, req, res) {
  if (err.code === 'ETIMEDOUT') {
    res.writeHead(504);
  } else {
    res.writeHead(503);
  }
  // ...
});
```

Resolves http-party#1331.
@JoaoOtavioS
Copy link

Hi, I took the liberty of implementing this in my fork. https://github.com/squarecloudofc/http-proxy

Denoder added a commit to refactorjs/http-proxy that referenced this pull request Oct 22, 2023
Added Pull Request from:
 - http-party/node-http-proxy#1634
- http-party/node-http-proxy#1638
- http-party/node-http-proxy#1650

fix tests that were having issues with the ports (if it fails the tests needs to be reran, seems to be an async issue)
timeoutError.code = 'ETIMEDOUT';
return proxyReq.destroy(timeoutError);
}
proxyReq.destroy();
Copy link

@ravin00 ravin00 Oct 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's the change here?

expect(err).to.be.an(Error);
expect(errReq).to.be.equal(req);
expect(errRes).to.be.equal(res);
expect(new Date().getTime() - started).to.be.greaterThan(99);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about adding the expect(new Date().getTime() - started).to.be.above(99); . Will it make a difference to this line or to the whole code

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.

Specific error for timeouts
3 participants