HTML5 web sockets - how to communicate with them? - ruby

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...

Related

How do I convey Keep-alive metadata when the HTTP/2 protocol is used?

I have an angular web application that uses Spring boot with an embedded tomcat server in the backend. I want to keep established http connections alive longer to improve the response time of subsequent http requests. With http/1.1 a browser is told to keep the http connection alive by adding Connection: Keep-Alive and something like Keep-Alive: timeout=5, max=1000 to the response header. However connection-specific header fields such as Connection and Keep-Alive are prohibited in HTTP/2. Because of that Chrome and Firefox ignore them in HTTP/2 responses. With HTTP/2, connection-specific metadata should be conveyed by other means.
I can't find anywhere what those 'other means' should be though. Nor can i find anywhere how to configure an embedded Tomcat 9 server to add Keep-alive meta data to a HTTP/2 response. This is how tomcat is configured right now:
#Bean
public WebServerFactoryCustomizer<TomcatServletWebServerFactory> tomcatCustomizer() {
return (tomcat) -> tomcat.addConnectorCustomizers((connector) -> {
if (connector.getProtocolHandler() instanceof AbstractHttp11Protocol) {
AbstractHttp11Protocol<?> protocolHandler = (AbstractHttp11Protocol<?>) connector
.getProtocolHandler();
protocolHandler.setDisableUploadTimeout(false);
protocolHandler.setConnectionUploadTimeout(5000);
protocolHandler.setKeepAliveTimeout(4000);
protocolHandler.setMaxKeepAliveRequests(200);
protocolHandler.setUseKeepAliveResponseHeader(true);
}
});
}
But these settings aren't going to work if i want to use HTTP/2. Any ideas?
With http/1.1 a browser is told to keep the http connection alive by adding Connection: Keep-Alive and something like Keep-Alive: timeout=5, max=1000 to the response header.
That’s not actually true. Since HTTP/1.1 the Connection: Keep-Alive header is defaulted to be the case unless explicitly set to Close. The fact we even have the header is more a left over from HTTP/1.0 days and shouldn’t need to be set. The response has always been more informative of what the server will do rather than an instruction to the client (“hey, FYI I’m going to be using these settings”) but it was always kind of meaningless too since server (and client) could drop the connection if it wanted too. If a server is running out of TCP connections it shouldn’t really keep and old one that is not being used alive rather than accept a new one, in general.
However connection-specific header fields such as Connection and Keep-Alive are prohibited in HTTP/2. Because of that Chrome and Firefox ignore them in HTTP/2 responses. With HTTP/2, connection-specific metadata should be conveyed by other means.
I can't find anywhere what those 'other means' should be though. Nor can i find anywhere how to configure an embedded Tomcat 9 server to add Keep-alive meta data to a HTTP/2 response. This is how tomcat is configured right now:
In the same way as previous, HTTP/2 just got rid of the rather pointless header and assumed you want to keep it alive. It also made less sense in HTTP/2 as it’s used for multiple requests and responses whereas HTTP/1.1 is only used for one at a time and keep-alive is a connection-level setting. So if an HTTP/2 request could specific a keep-alive: close what would that mean for other requests on that connection that are already in-flight? And similarly setting it to keep-alive is implied by the very nature of HTTP/2’s multiplexing.
It’s up to the client and server to decide when best to drop the connection, based on its own logic and resource constraints, though the HTTP/2 spec does go on to say this later:
HTTP/2 connections are persistent. For best performance, it is expected that clients will not close connections until it is determined that no further communication with a server is necessary (for example, when a user navigates away from a particular web page) or until the server closes the connection.

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?

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

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

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.

JavaScript WebSocket onMessage Event is not being fired until certain amount of Data has been received

I'm currently experiencing this odd behaviour with WebSockets in JavaScript, which I can't figure out a reason for and which is driving me nuts.
I hope that someone here can help me to find out what exactly is happening.
The scenario is as follows:
I have a Java application with a web server (io.Undertow), which provides a connecting client (in this case Chrome or Firefox) with the required resources via HTTP. The client then opens a WebSocket connection (native JavaScript Websocket API of the respective browser) to the server, which initiates a new WebSocket session (javax.websocket.Session) for the communication. Then in case of some certain events the server notifies the connected client about these events with one message per event via the mentioned WebSocket connection. So far so good...
The problem:
When such an event occurs after the (re-)establishment of the WebSocket connection, the server correctly sends the message as expected, but the client (both Chrome and Firefox) seems to somehow buffer the incoming messages and does not fire the onMessage event of the WebSocket API until a total data amount of 8187 bytes has been received. (Besides: This is a strange number in my opinion; am I missing some header bytes here?) When this point is reached suddenly all received messages are processed at once and the onMessage event is fired for all of them at the same time. After that the connection works fine and the onMessage event is fired for every single event.
Another thing to mention:
This problem does not occur on the systems of two of my colleagues; on their systems the events are fired correctly from the very beginning. So it has to be something specific to my system.
Does anyone have any idea why this is happening on my system? Is there any system, firewall, browser, other setting that could influence the browser in such a way?
Headers as provided by Chrome:
Request Headers:
Request URL:ws://127.0.0.1:8080/events
Request Method:GET
Status Code:101 Switching Protocols
Accept-Encoding:gzip, deflate, sdch
Accept-Language:de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4
Cache-Control:no-cache
Connection:Upgrade
Cookie:JSESSIONID=...
Host:127.0.0.1:8080
Origin:http://127.0.0.1:8080
Pragma:no-cache
Sec-WebSocket-Extensions:permessage-deflate; client_max_window_bits
Sec-WebSocket-Key:...
Sec-WebSocket-Version:13
Upgrade:websocket
User-Agent:Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36
Response Headers:
Connection:Upgrade
Content-Length:0
Date:Fri, 27 Mar 2015 09:55:01 GMT
Origin:http://127.0.0.1:8080
Sec-WebSocket-Accept:...
Sec-WebSocket-Location:ws://127.0.0.1:8080/events
Set-Cookie:JSESSIONID=...; path=/
Upgrade:WebSocket
Version Information:
Chrome Version: 41.0.2272.101 m
Firefox Version: 36.0.1
Operating System: Windows 8.1 Pro
OS of Colleagues: Windows 8.1 Pro / Linux Ubuntu GNOME 14.04.1
Thanks in advance for any advice.
Chris

Resources