0

I am serving content locally, accessible through http://0.0.0.0:4000. That works ok, I get a correct webpage, which contains the following line inside a script:

var socket = io('http://example.com');

i.e. I am referencing an external server. Now my browser shows the followoing error:

GET http://example.com:4000/socket.io/?EIO=3&transport=polling&t=1417447089410-1 net::ERR_CONNECTION_REFUSED

That is, the browser is trying to connect using the same port that it used to get the original page.

Everything works fine when both the SocketIO server and the web server listen on the same port.

Am I missing something? Is this a bug? Is there a workaround? Thank you.

clapas
  • 1,768
  • 3
  • 16
  • 29
  • Have you tried `io('http://example.com:80');` ? – Oleg Dec 01 '14 at 15:45
  • The `socket.io` client first contacts the exact same web server on the same port that the web page was loaded from with a special URL. If webSocket support is present, it then moves the connection over to a websocket. This is the normal `socket.io` connect procedure. Your line of code: `var socket = io('http://example.com');` needs to be the exact same domain and port as the web page is. – jfriend00 Dec 02 '14 at 06:48
  • @Curious Yes, I have tried and it works. The problem arises when I omit the port. – clapas Dec 02 '14 at 08:55
  • @jfriend00 Although the default procedure you explain makes sense -and I would accept it as an answer, I think your last sentence is wrong, since I have been able to connect to other servers and ports when explicitly so set. – clapas Dec 02 '14 at 08:58
  • Yeah, the security aspect is up to the webSocket server on whether it wants to try to enforce same-origin or not (many do, but not all). I added a lot more detail into an answer. – jfriend00 Dec 02 '14 at 09:19

1 Answers1

1

You can read here about how a plain webSocket is initially set up. It all starts with a somewhat standard HTTP GET request, but one that has some special headers set:

GET /chat HTTP/1.1
Host: example.com:8000
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13

The interchange may also allow the host to enforce requests only from web pages on certain origins. While this header can be spoofed from non-web-browser agents (so the server has to be prepared for that), it will likely be correct when the OP is using a real browser (assuming no proxy is modifying it).

If the server accepts the incoming request, it will then return an HTTP response that looks something like this:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

At this point, the socket which used to be an HTTP socket is now a webSocket and both endpoints have agreed that they're going to use the webSocket data format from now on. This initial connection may be followed by some form of authentication or new or existing cookies can also be used in the authentication during the initial HTTP portion of the connection.


socket.io adds some enhancements on top of this by initially requesting a particular path of /socket.io and adding some parameters to the URL. This allows socket.io to negotiate whether it's going to use long polling or a webSocket so there are some exchanges between client/server with socket.io before the above webSocket is initialized.


So, back to your question. The socket.io server simply spies at all incoming web requests on the normal web port (and looks for both it's special path and for special headers to indicate a webSocket initiation rather than a classic HTTP request). So, it runs over the same port as the web server. This is done for a bunch of reasons, all of which provide convenience to the server and server infrastructure since they don't have to configure their network to accept anything other than the usual port 80 they were already accepting (or whatever port they were already using for web requests).

By default in socket.io, the domain and port will default to the same domain and port as the web page you are on. So, if you don't specify one or the other in your connect call, it will use the domain or port from the web page you are on. If you want to use both a different domain and port, then you must specify both of them.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • I understand and appreciate your answer, but is not as clear as I would have expected. I would have put the epilogue this way: "The `socket.io` library will by default try to connect to the same server and through the same port as the ones including it in the web page; and if you change the server, the port will remain the same, so you will have to change it aswell". Thank you! – clapas Dec 02 '14 at 14:41
  • @clapas - I added a new last paragraph. It wasn't clear to me which exact issue was causing your problem so I tried to cover more of how socket.io works. – jfriend00 Dec 02 '14 at 17:52