Random bad request 400 errors with Socket.io 1.0.6 - node.js

I'm using Node.js on port 8082 and Apache on port 80.
Everything works fine for a while and than the browser start to show error messages "400 Bad Request", CORS errors.
The server is setting the CORS headers. As you can see I'm also using Redis adapter.
var io = require('socket.io').listen(8082);
io.adapter(redis({ host: '127.0.0.1', port: 6379 }));
io.set('origins', 'domain.com:*');
Can't say why some times all works fine, some times don't.
The error always occurs when Socket.io try to upgrade from pooling to websocket.
When I use the client from https://cdn.socket.io/socket.io-1.0.6.js I got less errors.
When I use a local reference for socket.io-1.0.6.js the errors occurs with more frequency.
Can't find a error pattern.
After the erros, I restart the Node.js server, try a few requests, works for a while and again, errors. Some times works again without restarting the server.
Request headers sample
Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding gzip, deflate
Accept-Language pt-BR,pt;q=0.8,en-US;q=0.5,en;q=0.3
Cookie io=RjKzZ6Y1OTQeSEsPAAAL; SGM_DESENV=cb5ae798c2f6f5d3f38c6ed16a6e4696
Host 200.238.251.79:8082
Origin http://200.238.251.79
Referer http://200.238.251.79/maximiliano/sgp/admin/custodiacompartilhada/add
User-Agent Mozilla/5.0 (Windows NT 5.1; rv:29.0) Gecko/20100101 Firefox/29.0
Response headers sample
Access-Control-Allow-Credentials true
Access-Control-Allow-Origin http://200.238.251.79
Connection keep-alive
Content-Length 101
Content-Type application/octet-stream
Date Fri, 25 Jul 2014 16:10:26 GMT
Set-Cookie io=9OYcCmU24IyzrAS3AAAM
Error messages
NetworkError: 400 Bad Request - http://200.238.251.79:8082/socket.io/?EIO=2&transport=polling&t=1406304539856-2&sid=RjKzZ6Y1OTQeSEsPAAAL
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://200.238.251.79:8082/socket.io/?EIO=2&transport=polling&t=1406304539856-2&sid=RjKzZ6Y1OTQeSEsPAAAL This can be fixed by moving the resource to the same domain or enabling CORS.

CORS does not allow wildcard in the domain name.
You either have to allow from all domain:
io.set('origins', '*');
or specify the port:
io.set('origins', 'http://200.238.251.79:8082');
(requesting on another port implies CORS)

Related

Express & HPM - 404 Not Found & Client Disconnected w/ PVE xterm websocket

I am using Express and HPM to proxy all requests to my website. This is all wrapped together into a little tool I call ws-proxy (ws for web server, not websocket).
One of the things proxied is my PVE/Proxmox Virtual Environment node, which uses secure WebSockets for the xterm.js and NoVNC consoles.
ws-proxy mre
What is weird about this, is after starting ws-proxy, I have about 30 seconds to open a console which will be sustained, but connections after this time will be closed with a 404 Not Found error. In the console, I see
[HPM] Upgrading to WebSocket
[HPM] Upgrading to WebSocket (sometimes up to 4 times)
[HPM] Client disconnected
In my browser, I see the connection returned as 404.
With websocat, I get:
websocat: WebSocketError: Received unexpected status code (404 Not Found)
websocat: error running
After additional debugging, I see something in the stack is sending a 404 and closing the connection, where just afterwards PVE sends the 101 Switching Protocols. This also sometimes causes a write after end error, sometimes socket hangup.
I've spent months looking into this and I have nowhere else to look at this point.
http-proxy-middleware#826 (by me)
404 in inspect element:
error log in console after a recent attempt (error will change)
Full list of steps between client and server:
Cloudflare
DigitalOcean w/ ssh-forward (not the problem)
ws-proxy
server
Non-websocket (HTTP) requests work fine. This is with HPM v2 and Node.js v16.
Update 1
After Ryker's answer, I attempted the solution which should have fixed it, but I see something else of concern after setting the logLevel to debug:
0|ws-proxy | pve.internal.0xlogn.dev ::1 - - [02/Nov/2022:23:17:14 +0000] "POST /api2/json/nodes/proxmox/lxc/105/termproxy HTTP/1.1" 200 487 "https://pve.internal.0xlogn.dev/?console=lxc&vmid=105&node=proxmox&resize=scale&xtermjs=1" "Mozilla/5.0 (X11; Linux x86_64; rv:106.0) Gecko/20100101 Firefox/106.0"
0|ws-proxy | Upgrade request for vhost pve.internal.0xlogn.dev, proxy out
0|ws-proxy | [HPM] GET /api2/json/nodes/proxmox/lxc/105/vncwebsocket?port=5900&vncticket=REDACTED -> https://10.0.1.2:8006
0|ws-proxy | [HPM] GET /api2/json/nodes/proxmox/lxc/105/vncwebsocket?port=5900&vncticket=REDACTED -> http://10.0.1.108:80
0|ws-proxy | [HPM] Upgrading to WebSocket
0|ws-proxy | [HPM] Upgrading to WebSocket
0|ws-proxy | [HPM] Client disconnected
0|ws-proxy | [HPM] GET /api2/json/cluster/resources -> https://10.0.1.2:8006
Notice the two GET requests? Something is duplicating the request.
My 'upgrade' event listener:
httpsServer.on('upgrade', (req, socket, head) => {
if (!req.headers.host) {
console.log('No vhost specified in upgrade request. Ignoring.');
socket.end();
return;
} else {
console.log(`Upgrade request for vhost ${req.headers.host}, proxy out`);
vhostProxyMiddlewareList[req.headers.host].upgrade(req, socket, head);
}
})
What's even weirder here, is after restarting, I get a short time where the request isn't duplicated. Plus, there is a normal HTTP request anyway.
Update 2
After noticing the dual requests, I believe it is possible the module vhost is causing a weird wildcard and sending the request to two target nodes. I will update shortly.
Update 3
After further work I believe this is true. However, vhost is not at fault, rather something is implicitly calling next().
Update 4
This is still an issue, even after multiple attempts at changing this. I have not heard anything back from HPM.
http-proxy-middleware relies on a initial http request in order to listen to the http upgrade event by default. To proxy WebSockets without the initial http request, you can subscribe to the server's http upgrade event manually.
Add this listener to your http server
const wsProxy = createProxyMiddleware({ target: targetURL, onError, ...PROXY_DEFAULT_OPTIONS, ...addlProxyOptions });
httpsServer.on('upgrade', wsProxy.upgrade); // <-- subscribe to http 'upgrade'

Specifying proxy for http-proxy-middleware

I have a nodeJS project for a front-end that connects to multiple micro services.When we do final deployments we actually deploy the built JS and HTML in a WAR file along with the backend.
However, for development we use the http-proxy-middleware so we are able to do quick changes and edits on the front-end and see the results.
Today though, I would like to be able to see the connections leaving NODE-JS and going towards our microservices.
Specifically, I want to tunnel them through fiddler ( which is an http proxy usually running on port 8888 ).
Does anyone know to do this?
I tried setting e.g. the following but it doesn't affect the outgoing connection:
npm config set proxy http://localhost:8888
npm config set proxy http://localhost:8888 is used to configure NPM to download packages through a proxy.
You will need to connect to fiddler's HTTP proxy instead of your usual backend, with the relevant HTTP headers for proxying.
So a request would look something like
http.get ({
host: '127.0.0.1',
port: 8888,
path: 'http://actual.backend/url'
}, function (response) {
console.log (response);
});
Well, the answer to my problem is to use fiddler as a reverse proxy:
https://docs.telerik.com/fiddler/Configure-Fiddler/Tasks/UseFiddlerAsReverseProxy
I came across it by accident partly. I thought maybe I can't intercept all requests, but I could set my endpoint as being fiddler.
I did that, and saw a response in fiddler from the Fiddler Echo Service.
It basically displays a page similar to:
Fiddler Echo Service
PUT /abc-service/initialize HTTP/1.1
accept-language: en-AU,en;q=0.9,el;q=0.8,en-NZ;q=0.7,en-US;q=0.6,en-GB;q=0.5
accept-encoding: gzip, deflate, br
accept: */*
postman-token: 0466cca5-21f9-67ab-be05-5227ef667fe4
user-agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36
origin: chrome-extension://fhbjgbiflinjbdggehcddcbncdddomop
cache-control: no-cache
content-length: 0
connection: close
host: localhost:8889
X-Tenant-Id: abc
X-Forwarded-Proto: http
X-Forwarded-Force-Http-Protocol: true
X-Forwarded-Prefix: abc-service
This page returned a HTTP/200 response
Originating Process Information: node:15044
--------------------------------------------------------------------------------
•To configure Fiddler as a reverse proxy instead of seeing this page, see Reverse Proxy Setup ( https://docs.telerik.com/fiddler/Configure-Fiddler/Tasks/UseFiddlerAsReverseProxy )
•You can download the FiddlerRoot certificate

HAProxy not running nodeJS API correctly

I am running coreOS in EC2.
I have a nodeJS api docker image and running that in couple of ports (25001 and 25002). When I curl to them, I see proper response.
My intent is to have a HAProxy above these (run at 25000) which will load balance between these two.
So here are steps that I did:
DockerFile for HaProxy:
FROM haproxy:1.5
COPY haproxy.cfg /usr/local/etc/haproxy/haproxy.cfg
haproxy.cfg :
global
# daemon
maxconn 256
log /dev/log local0
defaults
mode http
log global
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms
frontend http-in
bind *:25000
default_backend node_api
backend node_api
mode http
balance roundrobin
server api1 localhost:25001
server api2 localhost:25002
Result:
When I run curl for individual services they work --->
curl -i localhost:25001/ping
HTTP/1.1 200 OK
X-Powered-By: Express
Access-Control-Allow-Origin: *
Content-Type: application/json; charset=utf-8
Content-Length: 68
ETag: W/"44-351401c7"
Date: Sat, 06 Jun 2015 17:22:09 GMT
Connection: keep-alive
{"error":0,"msg":"loc receiver is alive and ready for data capture"}
Same works for 25002
But when I run for 25000, I get a timeout error like below:
curl -i localhost:25000/ping
HTTP/1.0 504 Gateway Time-out
Cache-Control: no-cache
Connection: close
Content-Type: text/html
<html><body><h1>504 Gateway Time-out</h1>
The server didn't respond in time.
</body></html>
I am wondering what am I doing wrong here? Any help would be appreciated ...
When you tell HAProxy that the back-end server is located at
server api1 localhost:25001
you're giving an address relative to the HAProxy container. But your Node servers aren't running on that container, so there's nobody at localhost.
You've got a few options here.
You could use the --link option for docker run to connect HAProxy to your two back-ends.
You could use the --net=host option for docker run and then your servers can find each other at localhost
You could provide HAProxy the address of your host as the back-end address
The first option is the most container-y, but the performance of Docker's bridged network is poor at high loads. The second option is good as long as you don't mind that you're letting everything break out of its container when it comes to the network. The third is kludgey but doesn't have the other two problems.
Docker's article on networking has more details.

Node.js application not loadingproperly in Chromium: Connection timed out while reading response header from upstream

I'm running a Node.JS application in the subdomain of WP site. The WP site itself is running on Nginx, php-fpm and Varnish and works just fine, so I'm using Nginx to proxy connections to the Node app.
With Firefox, the Node app works perfectly. The home page and every other page loads, including the admin end. However, on Chromium, the site does not load properly. If I attempt to view the home page, the main content area loads, but the sidebar does not. And I get the following message in the Web console:
WebSocket connection to 'ws://forum.site.com/socket.io/1/websocket/91qNR-mt333a'
failed: Unexpected response code: 502
In the Nginx log file, I see entries like:
2089 upstream prematurely closed connection while reading response header from upstream,
client: 127.0.0.1, server: forum.site.com, request: "GET /socket.io/1/websocket/91qNR-
mt333a HTTP/1.1", upstream: "http://127.0.0.1:4567/socket.io/1/websocket/91qNRaWZ3-
mt333a", host: "forum.site.com"
And if I try to navigate between posts on the site, I get these messages in the Web console:
Failed to load resource: the server responded with a status of 504 (Gateway Time-out)
http://forum.site.com/socket.io/1/xhr-polling/91qNRaWZ3rYcF-mt333a?t=1396434040701
Then these lines from Nginx error log:
2128 upstream timed out (110: Connection timed out) while reading response header from
upstream, client: 127.0.0.1, server: forum.site.com, request: "GET /socket.io/1/xhr-
polling/uH9QTAWUGmomqFoy333e?t=1396434162051 HTTP/1.1", upstream:
"http://127.0.0.1:4567/socket.io/1/xhr-polling/uH9QTAWUGmomqFoy333e?t=1396434162051",
host: "forum.site.com", referrer: "http://forum.site.com/category/35/dual-boots"
I've looked at similar issues on this site and other sites and tried to implement the suggested solutions, but no luck so far. For example, in the Nginx config for the subdomain, I've added the following:
proxy_buffers 8 32k;
proxy_buffer_size 64k;
proxy_connect_timeout 120;
proxy_read_timeout 300;
And played around with different values for the last two lines, but still no luck.
What baffles me is that the site works perfectly on FF. It's only on Chromium that I'm having these problem. I've not tried on IE, but I'm not really concerned about that browser at this point.
I'm sure there's something that I'm overlooking, but I don't know what.
Btw, the site exhibits the same behavior on Android's default browser.
Could Varnish be the culprit here. I have Varnish (port 80) in front of Nginx (8080). Does Varnish play nice with WebSockets?
Finally figured out that the problem is with Varnish, which by default does not handle WebSocket traffic. It has to be explicitly configured for it.
See this link for the solution.

What response code to return for insecure POST not acceptable?

If somebody accesses my server via http (i. e. not https) then I redirect GET requests to the https version.
But I don't know what to do with POST and PUT because I cannot redirect them (the browser does a GET on redirect I believe).
I should return an error code. What HTTP error code should I return?
Typically, you would return a 403 - Forbidden. The general description of this is "The server understood the request, but refuses to authorize it." which would fit your situation.
Technically right answer is to use 403.4 but substatuses it's a IIS only feature and nginx doesn't support it.
So I've prefer to return 418 "I'm a teapot" or 451 "Unavailable For Legal Reasons" (because it's not legal to use plain-text http anymore, haha, just joking :)), this statuses quite exotic and should trigger client to figure out what going on.
nginx has an option to return status with text like
# cat /etc/nginx/conf.d/default.conf
server {
listen 80 default_server;
location / {
add_header Content-Type text/plain;
return 418 "TLS REQUIRED";
}
}
# curl -v http://localhost/
* About to connect() to localhost port 80 (#0)
* Trying ::1...
* Connection refused
* Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 80 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.29.0
> Host: localhost
> Accept: */*
>
< HTTP/1.1 418
< Server: nginx/1.16.1
< Date: Sat, 15 Feb 2020 07:13:20 GMT
< Content-Type: application/octet-stream
< Content-Length: 12
< Connection: keep-alive
<
* Connection #0 to host localhost left intact
TLS REQUIRED
But browsers like Chrome or Firefox can't handle this right, Chrome says ERR_INVALID_RESPONSE and Firefox says "File not found" and this behavior doesn't solve our goal.
So I've stay with just returning status 418.
http://www.ietf.org/id/draft-ietf-httpbis-p2-semantics-18.txt explains HTTP response codes. If you want an error code, just return a 404 if requests cannot be serviced at that URL.
7.4.5. 404 Not Found
The server has not found anything matching the effective request URI.
No indication is given of whether the condition is temporary or
permanent. The 410 (Gone) status code SHOULD be used if the server
knows, through some internally configurable mechanism, that an old
resource is permanently unavailable and has no forwarding address.
This status code is commonly used when the server does not wish to
reveal exactly why the request has been refused, or when no other
response is applicable.

Resources