chimurai / http-proxy-middleware

:zap: The one-liner node.js http-proxy middleware for connect, express, next.js and more
MIT License
10.7k stars 834 forks source link

Server crashed with thousands of [HPM] Upgrading to WebSocket attempts #733

Closed hossein-zare closed 2 years ago

hossein-zare commented 2 years ago

Checks

Describe the bug (be clear and concise)

I want to proxy socket.mydomain.com:4000 to a websocket server running at mydomain.com:4001.

// client
const socket = io('ws://socket.mydomain.com:4000');

it's working fine but If i change socket.domain.com to app.domain.com the server tries to upgrade to websocket then craches.

// client
const socket = io('ws://app.mydomain.com:4000');

Log

[HPM] Upgrading to WebSocket
[HPM] Upgrading to WebSocket
[HPM] Upgrading to WebSocket
[HPM] Upgrading to WebSocket
[HPM] Upgrading to WebSocket
[HPM] Upgrading to WebSocket
[HPM] Upgrading to WebSocket
[HPM] Upgrading to WebSocket
[HPM] Upgrading to WebSocket
[HPM] Upgrading to WebSocket
[HPM] Upgrading to WebSocket
[HPM] Upgrading to WebSocket
[HPM] Upgrading to WebSocket
...

[HPM] Error occurred while proxying request app.mydomain.com:4000/socket.io/?EIO=4&transport=websocket to undefined [HPE_INVALID_CONSTANT] (https://nodejs.org/api/errors.html#errors_common_system_errors)

Error: read ECONNRESET
    at TCP.onStreamRead (node:internal/stream_base_commons:220:20) {
  errno: -4077,
  code: 'ECONNRESET',
  syscall: 'read'
}

Step-by-step reproduction instructions

1. ...
2. ...

Expected behavior (be clear and concise)

The server must not crash if the client tries to connect to another subdomain.

How is http-proxy-middleware used in your project?

-- http-proxy-middleware@2.0.4

const conf = {
  target: `http://mydomain.com:4000`,
  changeOrigin: true,
  ws: true,
  router: {
    'socket.mydomain.com:4000': `http://mydomain.com:4001`,
  }
};

const wsProxy = createProxyMiddleware(conf);

app.use(wsProxy);

server.on('upgrade', wsProxy.upgrade);

What http-proxy-middleware configuration are you using?

const conf = {
  target: `http://mydomain.com:4000`,
  changeOrigin: true,
  ws: true,
  router: {
    'socket.mydomain.com:4000': `http://mydomain.com:4001`,
  }
}

What OS/version and node/version are you seeing the problem?

Windows 10
Node: 16.13.0

Additional context (optional)

No response

Vladyslav-Murashchenko commented 2 years ago

@hossein-zare I am getting the same issue. Do you know how to fix this?

hossein-zare commented 2 years ago

@VladislavMurashchenko

I used http-proxy:

const require('http-proxy');

const app = express();
const server = http.createServer(app);

const proxy = httpProxy.createProxyServer({
    target: {
        host: 'example.com',
        port: 4001
    }
});

server.on('upgrade', (req, socket, head) => {
    const domain = req.headers.host;
    const host = domain.split(':')[0];

    if (host === 'socket.example.com') {
        proxy.ws(req, socket, head);
    } else {
        socket.destroy();
    }
});
chimurai commented 2 years ago

Can you try with v2.0.6?

It contains a fix for server crashes from websocket errors

chimurai commented 2 years ago

Think the filter option is what you were looking for:

// only proxy on this condition:
const filter = (path, req) => {
    const domain = req.headers.host;
    const host = domain.split(':')[0];
    return host === 'socket.example.com'
}

const conf = {
  target: `http://mydomain.com:4000`,
  changeOrigin: true,
  ws: true,
  router: {
    'socket.mydomain.com:4000': `http://mydomain.com:4001`,
  }
};

const wsProxy = createProxyMiddleware(filter, conf);
whatwewant commented 2 years ago

still broken

whatwewant commented 2 years ago

https://github.com/chimurai/http-proxy-middleware/blob/3b9730826187c708fbd16cb0baa588f6aad73a00/src/http-proxy-middleware.ts#L74

@chimurai node-http-proxy socket will throw error if no error listener for default eventemitter

  1. https://github.com/http-party/node-http-proxy/blob/9b96cd725127a024dabebec6c7ea8c807272223d/lib/http-proxy/passes/ws-incoming.js#L121
  2. https://github.com/http-party/node-http-proxy/blob/9b96cd725127a024dabebec6c7ea8c807272223d/lib/http-proxy/passes/ws-incoming.js#L153
  3. https://github.com/http-party/node-http-proxy/blob/9b96cd725127a024dabebec6c7ea8c807272223d/lib/http-proxy/index.js#L38
whatwewant commented 2 years ago

how to: just

this.proxy.ws(req, socket, head, activeProxyOptions, this.logError);