websocket-rails: Server emits http:// protocol; client expects ws:// protocol - websocket

From Using the JavaScript Client:
Notice the lack of a protocol prefix on the server URL. Do not add http:// or ws:// to the URL that you pass to the new dispatcher. WebSocketRails will choose the best available transport for you and prepend the correct prefix automatically.
I'm using WebSocketRails for the first time. I'm getting this error in the client:
WebSocket connection to 'ws://localhost:3000/websocket' failed: Connection closed before receiving a handshake response
If I navigate my browser to http://localhost:3000/websocket, I get the messages that I am expecting. If I navigate to the ws URL, I get ERR_DISALLOWED_URL_SCHEME. So it appears that the server is producing the messages, but the client is trying the wrong protocol.
How do I force the client to use the http protocol rather than ws, or force the server to broadcast it with ws rather than http?

Finally found the answer by digging into the source code. The second parameter of the constructor is called use_websockets and defaults to true. Setting it to false apparently forces it to use http instead of ws.
var dispatcher = new WebSocketRails('localhost:3000/websocket',false);

Related

Is there a way to use custom headers when opening WebSocket connection?

I'm trying to make a WSS connection using default karate.webSocket(url, handler);
Connection is successful, but desired host requires Authorization: Bearer XXX header when upgrading connection from https to wss
Is it possible to provide custom HTTP headers from *.feature file for WebSocket connection?
Actually no, we never realized this was needed until now. We've opened an issue: https://github.com/intuit/karate/issues/775 - hope we can count on you to test this.

Should WebSocket server only handle GET requests?

I have a WebSocket server written which only handles upgrade requests which are GET requests. If a POST or any other kind of request with the required headers comes it is handled by a HTTP server.
In the specification it is not stated explicitly that the WebSocket upgrade request should be a GET request.
If the upgrade request is not a GET request should the server handle it as a WebSocket upgrade request, should it pass it to be handled by the HTTP server or should it respond to it with a status code like 400 Bad Request ?
Could this be a design decision where the server decides not to handle methods which are not GET requests?
From section 4.1 (Client Requirements) of the webSocket specification, it says this:
The method of the request MUST be GET, and the HTTP version MUST
be at least 1.1
And, then later in section 4.2.1 (Reading the Client's Opening Handshake) of the webSocket specification, it says this:
The client's opening handshake consists of the following parts. If
the server, while reading the handshake, finds that the client did
not send a handshake that matches the description below (note that as
per [RFC2616], the order of the header fields is not important),
including but not limited to any violations of the ABNF grammar
specified for the components of the handshake, the server MUST stop
processing the client's handshake and return an HTTP response with an
appropriate error code (such as 400 Bad Request).
An HTTP/1.1 or higher GET request, including a "Request-URI"
[RFC2616] that should be interpreted as a /resource name/
defined in Section 3 (or an absolute HTTP/HTTPS URI containing
the /resource name/).
So, there are multiple places where it says the http request must be a GET.
As for your specific questions:
Should WebSocket server only handle GET requests?
Yes, a webSocket connection will always start with a GET request, not a POST or any other method.
If the upgrade request is not a GET request should the server handle it as a WebSocket upgrade request, should it pass it to be handled by the HTTP server or should it respond to it with a status code like 400 Bad Request ?
As described in the above reference portion of the specfication, the server should respond with a status code like 400 Bad Request.
Could this be a design decision where the server decides not to handle methods which are not GET requests?
Yes.

Ruby: Persistent HTTP client not receiving response on second request

I am trying to create an HTTP client that uses persistent connections. My Code works when I send my first request and get my first response. However, when I send a second request, I am unable to get a second response. I am not sure why? I got the same error when I was coding in C.
Here is the code
require 'socket'
include Socket::Constants
socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
sockaddr = Socket.pack_sockaddr_in( 80, 'www.google.com' )
socket.connect( sockaddr )
# This Works
socket.write( "GET / HTTP/1.0\r\n\r\n" )
results = socket.read
# This Works
socket.write( "GET / HTTP/1.0\r\n\r\n" )
# THIS DOESN'T WORK
results = socket.read
I do not want to use built libraries like Net::HTTP. What do I need to do to make this work?
You cannot make 2 HTTP requests on the same connection, unless you've told the server that you're expecting to do so. This is how HTTP persistent connection works. At a minimum, you have to make sure to add this to your request header:
Connection: keep-alive
Servers have differing support for persistent connections, although it's become common for servers to support basic persistent connections. Here's an SO question that asks What exactly does a “persistent connection” mean?
Start there, and you'll find what you need to know to make persistent connections work correctly. You may have to check the HTTP response headers for an indication that the server will honor your request, or you may have to check that the server didn't simply close the connection when it was finished writing the first response. On your final request through a persistent connection, you should also specify the header:
Connection: close
Also check out these resources:
IETF HTTP 1.1 specification
W3 HTTP 1.1 section 8: Persistent Connections
Safari Books Online HTTP: The Definitive Guide - Persistent Connections

Capture HTTPS request to nonexistent server with FiddlerCore

I am trying to send a response to an HTTPS request, using FiddlerCore.
I need things to work like this: I put some fake URL in browser, like https://my_url_that_doesnt_exist.com/, then I intercept this request with FiddlerCore and respond to it with my data. But I only see a CONNECT and the host URL. I know this is because of HTTPS and Fiddler being a proxy. But is there a way to get the real full URL and be able to respond to HTTPS request, using FiddlerCore?
Also I use this code to create a root certificate if it's missing:
if (!Fiddler.CertMaker.rootCertExists())
{
if (!Fiddler.CertMaker.createRootCert())
{
throw new Exception("Could not create a certificate.");
}
}
also, I use these startup settings:
FiddlerCoreStartupFlags fcsf = FiddlerCoreStartupFlags.Default | FiddlerCoreStartupFlags.DecryptSSL|FiddlerCoreStartupFlags.AllowRemoteClients;
and CONFIG.IgnoreServerCertErrors = true;
This HTTPS request is not visible in Fiddler itself. I mean when I try some non-existent URL to which I'd like my app to respond with some custom content. It's also HTTP, not HTTPS, and Fiddler itself contains the following in response:
[Fiddler] DNS Lookup for "my_url_that_doesnt_exist.com" failed. The requested name is valid, but no data of the requested type was found
But if I use some existing HTTPS URL, like google plus or anything like that, I can see the HTTPS and all the request details.
So the question follows: How can I intercept HTTPS request to a non-existent URL and serve my content instead?
I can provide any additional details if needed.
Also makecert.exe is in the same folder where all my binaries are.
The problem is that HTTPS traffic flows through a CONNECT tunnel, and by default that secure traffic won't be sent if creating the CONNECT tunnel to the target server doesn't first succeed. Of course, if that target server doesn't exist, you end up with a DNS error in creating the tunnel, so the secure requests are never sent.
The workaround is to tell Fiddler to tell the client that the CONNECT tunnel was created, without even trying to contact the server. Do so by adding this inside the BeforeRequest handler:
if (oSession.HTTPMethodIs("CONNECT"))
{
oSession.oFlags["x-replywithtunnel"] = "GenerateTunnel";
return;
}

dart, turning a http request into a websocket?

I'm picking my way through the dartiverse_search example from the welcome page in dart editor. I see that it uses a path route to decide whether to transform a request into a websocket:
// The client will connect using a WebSocket. Upgrade requests to '/ws' and
// forward them to 'handleWebSocket'.
router.serve('/ws')
.transform(new WebSocketTransformer())
.listen(handleWebSocket);
Is it possible to turn a request into a websocket without using a routing path, for example using a query string to the root url?
You can specify any condition for upgrading to a WebSocket connection. You can even upgrade any connection request to a WebSocket connection without specifying a condition like this:
WebSocketTransformer.upgrade(request).then((WebSocket websocket) {
websocket.listen((String text) {
// process sent data
});
websocket.add(JSON.encode("Hello"));
});
If the request is not a valid web socket upgrade request a HTTP response with status code 500 will be returned. Otherwise the returned future will complete with the [WebSocket] when the upgrade process is complete.

Resources