Skip to content

Instantly share code, notes, and snippets.

@htp
Last active March 25, 2026 18:35
Show Gist options
  • Select an option

  • Save htp/fbce19069187ec1cc486b594104f01d0 to your computer and use it in GitHub Desktop.

Select an option

Save htp/fbce19069187ec1cc486b594104f01d0 to your computer and use it in GitHub Desktop.
Test a WebSocket using curl.
curl --include \
--no-buffer \
--header "Connection: Upgrade" \
--header "Upgrade: websocket" \
--header "Host: example.com:80" \
--header "Origin: http://example.com:80" \
--header "Sec-WebSocket-Key: SGVsbG8sIHdvcmxkIQ==" \
--header "Sec-WebSocket-Version: 13" \
http://example.com:80/
@emwalker
Copy link
Copy Markdown

did anybody try same command using TLS? to "wss://echo.websocket.org"

Replacing "http://" with "https://" in the curl command seems to do the trick.

Curious whether anyone has gotten a clean termination after the first message, along the lines of websocat --one-message .... I tried using --max-time, but the curl return status ends up being nonzero.

@balusch
Copy link
Copy Markdown

balusch commented May 31, 2022

I recommend adding --http1.1 to your curl command. The Connection and Upgrade headers are not valid in http/2 and curl will use http/2 if your server supports it.

I lost a few hours trying to figure out why these headers were disappearing when debugging my httpd web socket rewrite rules for the first time.

Thanks, it works!

@o-az
Copy link
Copy Markdown

o-az commented Mar 22, 2023

curl --include \
   --header "Connection: Upgrade" \
   --header "Upgrade: websocket" \
   --header "Sec-WebSocket-Key: qwerty" \
   http://localhost:8000/

This worked for me. I didn't need all the header items

@dannys42
Copy link
Copy Markdown

dannys42 commented May 8, 2023

Anyone know if you can use this to send data (i.e. from stdin or a file) through the web socket? I tried -T -, but that doesn't seem to work.

@GeekSnail
Copy link
Copy Markdown

curl --include \
    -H "Connection: Upgrade" \
    -H "Upgrade: websocket" \
    -H "Sec-WebSocket-Key: qwerty" \
    -H "Sec-WebSocket-Version: 13" \
    https://example.com -k

@marianopeck
Copy link
Copy Markdown

Hi,

@silvioprog @jageee

I am also using this command:

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

but I am getting a 200 response instead of the 101.

Any ideas?

@vi
Copy link
Copy Markdown

vi commented Apr 25, 2024

  1. You need to use HTTP/1.1
  2. You have specified too few headers
$ curl --http1.1 -i -N -H 'Sec-Websocket-Version: 13' -H 'Sec-Websocket-Key: QUo86XL2bHszCCpigvKqHg==' -H "Connection: Upgrade" -H "Upgrade: websocket" -H "Host: echo.websocket.org" -H "Origin: https://www.websocket.org" https://echo.websocket.org
HTTP/1.1 101 Switching Protocols
upgrade: websocket
connection: Upgrade
sec-websocket-accept: 8dlVwoWynsF/RauFo6HjkWl7dLk=
date: Thu, 25 Apr 2024 14:28:01 GMT
server: Fly/610c12e9 (2024-04-23)
via: 1.1 fly.io
fly-request-id: 01HWATFYXA0Y3STERG1SCHNQS2-ams

 Request served by 7811941c69e658

@marianopeck
Copy link
Copy Markdown

Thanks @vi that worked perfectly!

@tony-caffe
Copy link
Copy Markdown

I recommend adding --http1.1 to your curl command. The Connection and Upgrade headers are not valid in http/2 and curl will use http/2 if your server supports it.

I lost a few hours trying to figure out why these headers were disappearing when debugging my httpd web socket rewrite rules for the first time.

You saved my life haha. I wasted so much time thinking my move to E2EE was the issue but stupid ActionCable and AWS Target Group using HTTP/2 was the issue! 🤦

Time to look into AnyCable or something else. Thank you!

@realyukii
Copy link
Copy Markdown

I got status code 400 :"

I tried to connect to websocket server with simple setup using ws library:

const { WebSocketServer } = require('ws');

const wss = new WebSocketServer({ port: 8080 });

wss.on('connection', function connection(ws) {
  ws.on('error', console.error);

  ws.on('message', function message(data) {
    console.log('received: %s', data);
  });

  ws.send('something');
});

and I can't use curl to test it:

curl --include \
     --no-buffer \
     --header "Connection: Upgrade" \
     --header "Upgrade: websocket" \
     --header "Host: localhost:8080" \
     --header "Origin: http://localhost:8080" \
     --header "Sec-WebSocket-Key: SGVsbG8sIHdvcmxkIQ==" \
     --header "Sec-WebSocket-Version: 13" \
     http://localhost:8080/
HTTP/1.1 400 Bad Request
Connection: close
Content-Type: text/html
Content-Length: 43

Missing or invalid Sec-WebSocket-Key header

@realyukii
Copy link
Copy Markdown

realyukii commented May 27, 2025

browser developer tools on the network tab have copy as curl value, however it seems still no luck:

curl 'ws://localhost:8080/' -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:138.0) Gecko/20100101 Firefox/138.0' -H 'Accept: */*' -H 'Accept-Language: en-US,en;q=0.7,id;q=0.3' -H 'Accept-Encoding: gzip, deflate, br, zstd' -H 'Sec-WebSocket-Version: 13' -H 'Origin: null' -H 'Sec-WebSocket-Extensions: permessage-deflate' -H 'Sec-WebSocket-Key: 3tMWYzcHwmObiLR3nWOgsg==' -H 'Connection: keep-alive, Upgrade' -H 'Sec-Fetch-Dest: empty' -H 'Sec-Fetch-Mode: websocket' -H 'Sec-Fetch-Site: cross-site' -H 'Pragma: no-cache' -H 'Cache-Control: no-cache' -H 'Upgrade: websocket'
curl: (22) Refused WebSockets upgrade: 400

@realyukii
Copy link
Copy Markdown

realyukii commented May 27, 2025

okay, changing Sec-WebSocket-key with the one provided from browser works (not sure why):

curl --include \
     --no-buffer \
     --header "Connection: Upgrade" \
     --header "Upgrade: websocket" \
     --header "Host: localhost:8080" \
     --header "Origin: http://localhost:8080" \
     --header "Sec-WebSocket-Key: 3tMWYzcHwmObiLR3nWOgsg==" \
     --header "Sec-WebSocket-Version: 13" \
     http://localhost:8080/
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: YLxhg+bEzrZXCaOyyI5QkRBIdT4=

�       something

EDIT:
after reading the wikipedia, turned out it just a random 16-byte encoded with base64, on Linux, you can generate it with:

head -c 16 /dev/urandom | base64

@enderandpeter
Copy link
Copy Markdown

This was very helpful. Thanks so much. In my case I just needed to confirm that the websocket server could be connected to and the connection would be upgraded, but I see how the headers and other settings can be changed as needed for any particular situation.

@rajsek
Copy link
Copy Markdown

rajsek commented Mar 25, 2026

Just got to know about this so posting here to help others

WebSocket has been supported by curl as a non-experimental feature since version 8.11.0 (November 6 2024). With the upcoming release of version 8.16.0, we are taking it a step further.

With that release, you can use WebSocket in a pipe from the command line. Like this:

curl --no-progress-meter -T . -N wss://echo.websocket.org/
Request served by 4d896d95b55478dsadsa
Hello!
Hello!
you just echo what I send?
you just echo what I send?
...

This command line contacts the “echo” server run by websocket.org which just sends back what it receives from the client. The command line options are:

-T .: tells curl to upload the data from stdin, in non-blocking fashion.
-N: to avoid buffering of output data, so that even a single character received from the server is on stdout right away.
--no-progress-meter: to avoid curl cluttering stderr with information about how much was sent/received.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment