daydreamer
daydreamer

Reputation: 92149

How to hit the WebSocket Endpoint?

I see that there is websocket endpoint which works out fins with Java tests. In logs I see

Connecting to: ws://127.0.0.1:8080/76f48a44-0af8-444c-ba97-3f1ed34afc91/tweets  

Just like any other REST API I would like to hit it via browser or curl, but when I do that I see

➜  tweetstream git:(master) ✗ curl ws://127.0.0.1:8080/b9b90525-4cd4-43de-b893-7ef107ad06c2/tweets  
curl: (1) Protocol ws not supported or disabled in libcurl  

and

➜  tweetstream git:(master) ✗ curl http://127.0.0.1:8080/b9b90525-4cd4-43de-b893-7ef107ad06c2/tweets
<html><head><title>Error</title></head><body>Not Found</body></html>%  

Is there a way to test websocket APIs with browser/curl?

Upvotes: 20

Views: 49500

Answers (8)

x-yuri
x-yuri

Reputation: 18973

tl;dr curl -H 'Upgrade: websocket' -H "Sec-WebSocket-Key: `openssl rand -base64 16`" -H 'Sec-WebSocket-Version: 13' --http1.1 -sSv https://ws.ifelse.io (depending on the server you might need to provide Origin and/or Connection: Upgrade)

First, how does the websocket protocol work in a few words? A client connects to a server, sends a handshake request, receives "101 Switching Protocols" (a handshake response) after which they send frames back and forth.

The handshake looks along the following lines:

GET / HTTP/1.1
Host: ws.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Version: 13
Origin: http://example.com

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=

Upgrade makes it switch from HTTP(s) to the websocket protocol.

Connection specifies that Upgrade is a hop-by-hop header (headers that intermediaries should consume, not forward). But my experiments show that it works w/o this header. Or to be more precise, it might be optional if there's a reverse proxy in front of the server (e.g. nginx).

Sec-WebSocket-Key/Sec-WebSocket-Accept is a security measure described here, here and here.

Sec-WebSocket-Version specifies the websocket protocol version. According to RFC 6455 it should be equal 13.

Origin is needed when the client is a browser and the origin of the requesting page doesn't match the origin of the websocket server URL.

A detailed description of what should constitute a websocket handshake request can be found here.

That's how it goes with HTTP/1.1. HTTP/2 is a different story.

Knowing this to establish a websocket connection with curl:

$ curl -H 'Upgrade: websocket' \
       -H "Sec-WebSocket-Key: `openssl rand -base64 16`" \
       -H 'Sec-WebSocket-Version: 13' \
       --http1.1 \
       -sSv \
       https://ws.ifelse.io
...
> GET / HTTP/1.1
> Host: ws.ifelse.io
> Upgrade: websocket
> Sec-WebSocket-Key: e2dujvcbYbN747lapeH+WA==
> Sec-WebSocket-Version: 13
...
< HTTP/1.1 101 Switching Protocols
< Connection: upgrade
< upgrade: websocket
< sec-websocket-accept: 6wmMGMtN00aWw3loYd6P36EHKMI=

The other options are wscat, websocat.

Upvotes: 2

Abhishek Shah
Abhishek Shah

Reputation: 77

curl --include \
--no-buffer \
--header "Connection: Upgrade" \
--header "Upgrade: websocket" \
--header "Host: echo.websocket.org" \
--header "Origin: http://echo.websocket.org" \
--header "Sec-WebSocket-Version: 13" \
http://echo.websocket.org

Add the header if you have an additional sub-protocol configured for the WebSocket endpoint:

--header "Sec-protocol: protocol-name"

Replace thee Origin, Host and endpoint to test with your own server. If you have basic auth enabled, add the Authorization header like this:

 --header "Authorization: Basic RVZCLVAxNzI2MzAzOv"

Upvotes: 1

Vi.
Vi.

Reputation: 38742

For completeness, I'd like to add my own CLI tool: websocat.

$ websocat wss://echo.websocket.org/
qwer
qwer
1234
1234

It does not do the "browser" part of the question, but should be a valid substitute for "curl" in this case.

Upvotes: 9

Vinod Kannan
Vinod Kannan

Reputation: 31

I have used this and found it to be quite simple

http://www.websocket.org/echo.html

Upvotes: 2

facundofarias
facundofarias

Reputation: 3043

I had to use this command to make it work:

$ curl -i -N -H "Connection: Upgrade" -H "Upgrade: websocket" -H "Host: echo.websocket.org" -H "Origin: http://www.websocket.org" -H "Sec-WebSocket-Version: 13" -H 'Sec-WebSocket-Key: +onQ3ZxjWlkNa0na6ydhNg==' http://www.websocket.org

I am using Jetty, and if I didn't add the Sec-WebSocket-Version/Sec-WebSocket-Key doesn't work. Just for the record.

Upvotes: 5

user3697288
user3697288

Reputation: 9

I wrote a cURL like WebSocket client. You can send single data frame (text/binary) via this tool and then it closes the socket. Also you can add HTTP headers in the initial HTTP upgrade process.

https://github.com/jussmen/WebSocket_cURL

Upvotes: 0

Damian
Damian

Reputation: 2788

This did the trick for me:

$ curl -i -N -H "Connection: Upgrade" -H "Upgrade: websocket" -H "Host: echo.websocket.org" -H "Origin: http://www.websocket.org" http://echo.websocket.org

from: http://www.thenerdary.net/post/24889968081/debugging-websockets-with-curl

Upvotes: 17

Lee Adams
Lee Adams

Reputation: 331

If you mean literally to test the implementation of websockets, I found Autobahn's test suite to be very useful: http://autobahn.ws/

If you just want to noodle with a websocket I would recommend using the developer tools in a browser like chrome to make a connection and send/recv data:

var ws = new WebSocket("ws://127.0.0.1:8080/76f48a44-0af8-444c-ba97-3f1ed34afc91/tweets");
ws.onclose = function() { // thing to do on close
};
ws.onerror = function() { // thing to do on error
};
ws.onmessage = function() { // thing to do on message
};
ws.onopen = function() { // thing to do on open
};
ws.send("Hello World");

Upvotes: 11

Related Questions