SocketIO websocket handshake is different from what is described by RFC 6455 - websocket

I am attempting to learn more about the websockets protocol. According to RFC 6455, the step of this protocol is the handshake, which begins with the HTTP Upgrade request:
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
to which the server responds with a HTTP Switching Protocols message:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: chat
I attempted to observe this using a simple program based on socketIO (nodeJS websockets library. After capturing the traffic, I noticed that the first message the client sends the server is:
GET /socket.io/?EIO=3&transport=polling&t=1443149751115-0 HTTP/1.1
Host: localhost
Connection: keep-alive
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.85 Safari/537.36
Origin: null
Accept: */*
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8
to which the server responds with:
HTTP/1.1 200 OK
Content-Type: application/octet-stream
Content-Length: 101
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: null
Set-Cookie: io=3Z_TCqv9LKKXcWCjAAAD
Date: Fri, 25 Sep 2015 02:55:51 GMT
Connection: keep-alive
....0{"sid":"3Z_TCqv9LKKXcWCjAAAD","upgrades": ["websocket"],"pingInterval":25000,"pingTimeout":60000}
is SocketIO not following the RFC for websockets or am I missing something?

socket.io has it's own connection management stuff BEFORE it connects on a webSocket that allows it to negotiate which type of connection it's actually going to make to the server and allows it to send some configuration options down to the client. This will confuse you if you're trying to study a plain webSocket.
socket.io is an additonal protocol on top of webSocket. It will eventually use a standard webSocket underneath, but it will have additional stuff around that. If you continued to follow the socket.io connection, you would have eventually seen a standard webSocket connection.
I would suggest you first just make a plain webSocket connection from your client (no socket.io) and study that network trace.

In js client side, connect to server with websocket transports. That enables default websocket mechanism as the same as RFC 6455.
var socket = io.connect('http://localhost:8080', {
transports: [
'websocket',
'polling'
]
});

I believe you are correct, socket.io does not respect RFC 6455. To test this I ran a javascript server in an ubuntu virtualbox, and in the host ubuntu performed a successful socket.io interaction with the server. I captured the network traffic with sudo tcpdump -i vboxnet1 -w dump.out and analyzed the results with wireshark.
The socket.io handshake is just as the original poster represents, and the entire script completes successfully (with client receiving websocket messages) without the tcpdump ever displaying an HTTP request with an upgrade header as per https://www.rfc-editor.org/rfc/rfc6455#section-4.1

Related

How do I answer WebSocket client's handshake

I am trying to create a simple webSocket server on STM32 board. I have a simple html/js webpage which is trying to connect to my server. It is sending client's handshake, which I parse on server. It does all needed procedures to create answer and specifically sec-websocket-accept. This is how request and response look like:
GET / HTTP/1.1
Host: IP
Connection: Upgrade
Pragma: no-cache
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.136 YaBrowser/20.2.2.177 Yowser/2.5 Safari/537.36
Upgrade: websocket
Origin: http://192.168.1.61
Sec-WebSocket-Version: 13
Accept-Encoding: gzip, deflate
Accept-Language: ru,en;q=0.9
Sec-WebSocket-Key: PswqFRjY8rupf+Gq8/Cndw==
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: XhywTKBnx/pq+hEDH66h7tZBArk=
I don't know if my browser can't see this response or it just doesn't accept connection, but I know that response is sent to browser's ip/port, I can track it with Wireshark. The response is formed correctly with all needed /r/n and repeating myself, the encoding is done right. Am I missing something or what kind of problem may I have?

Chrome Canary does not offer HTTP/2

I'm trying to implement a small HTTP/2 server in C# in order to get to know the protocol. I'm running Chrome's latest canary build (v 45.0.2436.5), however I can't seem to get the client to negotiate an upgrade to an HTTP/2 connection.
The RFC states the following:
A client that makes a request for an "http" URI without prior
knowledge about support for HTTP/2 on the next hop uses the HTTP
Upgrade mechanism (Section 6.7 of [RFC7230]). The client does so by
making an HTTP/1.1 request that includes an Upgrade header field with
the "h2c" token.
which lead me to believe that the first request should contain an Upgrade header, but it doesn't. This is the request I'm getting:
GET / HTTP/1.1
Host: 127.0.0.1:1234
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2436.5 Safari/537.36
HTTPS: 1
Accept-Encoding: gzip, deflate, sdch
Accept-Language: de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4
Can anyone explain to me why this happens?
Thanks in advance for answers!
Chrome does not implement the HTTP/1.1 Upgrade to HTTP/2. It only implements HTTP/2 over TLS via ALPN.
The same is true for Firefox.
Browsers, in general, have preferred to use TLS because the IETF and the web in general are moving towards "everything TLS". Furthermore, using TLS gives a much higher rate of success in connection establishment.
For these and other reasons no browser so far has implemented the clear-text upgrade mechanism (that is not required by the specification).
There are rumors that Internet Explorer 11 will support the HTTP/1.1 Upgrade to HTTP/2, but I'm not sure if it's already available.
Meanwhile there are other (command line) tools that can perform the HTTP/1.1 Upgrade to HTTP/2.
For example, nghttp2 or curl.
For Java, you can use Jetty's HttpClient as explained here.
I'm not aware of HTTP/2 C# clients, perhaps you can look at other implementations here.

HTML5 web sockets - how to communicate with them?

I've tested many socket examples and communication between them was pretty simple: socket is opened and stays open until you close it and no information is being sent except the one you have sent.
With HTML5 web sockets these two moments are different.
At first, as soon as the client HTML5 socket connects to server socket it sends a bunch of information:
GET /echo HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Host: localhost:2002
Origin: null
Pragma: no-cache
Cache-Control: no-cache
Sec-WebSocket-Key: iYzsmhdzg6h6/UGtCLLGVA==
Sec-WebSocket-Version: 13
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits, x-webkit-deflate-frame
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.114 Safari/537.36
Cookie: _rails-socket-listener_session=dGtleFYxNjhIaUZrZVpOWUNIMHdFZFd6WW9wY2FJYjIwOWdSMFVPR1ZkYkZUakExdVlhNzMvWEphNG1IRUIvT1JsQ0N6bHF4REFXTkJUemE4R2RjOER6bXdhSEt6M0tIYmRwV0w3VzkrVGt4MzN2Z0M3MXMyYndZR3hvOGMySTJTZmdEMW9JdEE5ZERuSDB4VCtROFNnPT0tLTlheG1KamlBSVVmT0tUZ1F5bmQ0OUE9PQ%3D%3D--23413749a30295f08d277292837c76187a02a332
How to interpret this information? What to do with it?
At second, when I send some string from debugging server (Hercules setup utility), socket's onmessage event is not fired and client socket closes the connection immediately after this.
So, I suppose that HTML5 web socket expects some handshaking before it could be used. Where to read about it?
BTW: I am using Ruby as server-side language.
I've tested many web socket examples ....
From what you describe you did not use "web sockets" but simply "sockets", e.g. direct TCP/IP. WebSockets (e.g. what you call "HTML web sockets") are different: they are used to create something socket like over an established HTTP connection. Therefore you see the HTTP query with the "Upgrade: websocket" header, with the "Sec-WebSocket-Key" etc.
After establishing the connection (server sends response with code 101) the WebSocket connection has their own framing and scrambling of the data, so you cannot just use it with the normal socket tools.
See https://www.rfc-editor.org/rfc/rfc6455 for the specification and use "WebSockets" as the keyword if you look for more documentation, usage...

Server not sending HTTP 101 response when creating a websocket using CC3000 and socket.io

I am connecting CC3000 to a node.js server using socket.io. I have used the following library to create a websocket
https://github.com/chadstachowicz/socket_io_arduino_cc3000
In SocketIOClient.cpp, it creates a TCP connection, gets a session-id(sid). It disconnects and creates another TCP connection and uses the sid to upgrade the connection to websocket. For this the client(here CC3000) sends the following header information:
client.print(F("GET /socket.io/1/websocket/"));
client.print(sid);
client.println(F(" HTTP/1.1"));
client.print(F("Host: "));
client.println(hostname);
client.println(F("Origin: ArduinoSocketIOClient"));
client.println(F("Upgrade: WebSocket")); // must be camelcase ?!
client.println(F("Connection: Upgrade\r\n"));
After this request the client waits for HTTP 101 response from the server. But the server is not sending any response. It logs as warning "websocket connection invalid" and ends the connection.
Is the protocol for creating websocket fine or is there any missing information in the header?
Also, I want to know what should the value of 'Origin' be? During first handshake it is "Arduino" whereas in the second handshake it is "ArduinoSocketIOClient".
You are missing the Sec-WebSocket-Key and Sec-WebSocket-Version headers, key part of the WebSocket protocol handshake.
This is how an actual handshake looks:
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://example.com

How will you design a proxy server that supports HTTP 1.1 keep-alive completely?

It seems even nginx only half supports HTTP 1.1 keep-alive requests:
It is an HTTP/1.0 proxy without the
ability for keep-alive requests yet.
(As a result, backend connections are
created and destroyed on every
request.) Nginx talks HTTP/1.1 to the
browser and HTTP/1.0 to the backend
server. As such it handles keep-alive
to the browser. (source)
Were it you,how would you implement this?
The hardest part I think is how to make the response the same order as requested in keep-alive mode.

Resources