1<!-- 2Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 3 4SPDX-License-Identifier: curl 5--> 6 7# WebSocket in curl 8 9## URL 10 11WebSocket communication with libcurl is done by setting up a transfer to a URL 12using the `ws://` or `wss://` URL schemes. The latter one being the secure 13version done over HTTPS. 14 15When using `wss://` to do WebSocket over HTTPS, the standard TLS and HTTPS 16options will be acknowledged for the CA, verification of server certificate 17etc. 18 19WebSocket communication is done by upgrading a connection from either HTTP or 20HTTPS. When given a WebSocket URL to work with, libcurl considers it a 21transfer failure if the upgrade procedure fails. This means that a plain HTTP 22200 response code is considered an error for this work. 23 24## API 25 26The WebSocket API is described in the individual man pages for the new API. 27 28WebSocket with libcurl can be done two ways. 29 301. Get the WebSocket frames from the server sent to the write callback. You 31 can then respond with `curl_ws_send()` from within the callback (or outside 32 of it). 33 342. Set `CURLOPT_CONNECT_ONLY` to 2L (new for WebSocket), which makes libcurl 35 do an HTTP GET + `Upgrade:` request plus response in the 36 `curl_easy_perform()` call before it returns and then you can use 37 `curl_ws_recv()` and `curl_ws_send()` to receive and send WebSocket frames 38 from and to the server. 39 40The new options to `curl_easy_setopt()`: 41 42 `CURLOPT_WS_OPTIONS` - to control specific behavior. `CURLWS_RAW_MODE` makes 43 libcurl provide all WebSocket traffic raw in the callback. 44 45The new function calls: 46 47 `curl_ws_recv()` - receive a WebSocket frame 48 49 `curl_ws_send()` - send a WebSocket frame 50 51 `curl_ws_meta()` - return WebSocket metadata within a write callback 52 53## Max frame size 54 55The current implementation only supports frame sizes up to a max (64K right 56now). This is because the API delivers full frames and it then cannot manage 57the full 2^63 bytes size. 58 59If we decide we need to support (much) larger frames than 64K, we need to 60adjust the API accordingly to be able to deliver partial frames in both 61directions. 62 63## Errors 64 65If the given WebSocket URL (using `ws://` or `wss://`) fails to get upgraded 66via a 101 response code and instead gets another response code back from the 67HTTP server - the transfer will return `CURLE_HTTP_RETURNED_ERROR` for that 68transfer. Note then that even 2xx response codes are then considered error 69since it failed to provide a WebSocket transfer. 70 71## Test suite 72 73I looked for an existing small WebSocket server implementation with maximum 74flexibility to dissect and cram into the test suite but I ended up deciding 75that extending the existing test suite server sws to deal with WebSocket 76might be the better way. 77 78- This server is already integrated and working in the test suite 79 80- We want maximum control and ability to generate broken protocol and negative 81 tests as well. A dumber and simpler TCP server could then be easier to 82 massage into this than a "proper" WebSocket server. 83 84## Command line tool WebSocket 85 86The plan is to make curl do WebSocket similar to telnet/nc. That part of the 87work has not been started. 88 89Ideas: 90 91 - Read stdin and send off as messages. Consider newline as end of fragment. 92 (default to text? offer option to set binary) 93 - Respond to PINGs automatically 94 - Issue PINGs at some default interval (option to switch off/change interval?) 95 - Allow `-d` to specify (initial) data to send (should the format allow for 96 multiple separate frames?) 97 - Exit after N messages received, where N can be zero. 98 99## Future work 100 101- Verify the Sec-WebSocket-Accept response. It requires a sha-1 function. 102- Verify Sec-WebSocket-Extensions and Sec-WebSocket-Protocol in the response 103- Make WebSocket work with hyper 104- Consider a `curl_ws_poll()` 105- Make sure WebSocket code paths are fuzzed 106- Add client-side PING interval 107- Provide option to disable PING-PONG automation 108- Support compression (`CURLWS_COMPRESS`) 109 110## Why not libWebSocket 111 112libWebSocket is said to be a solid, fast and efficient WebSocket library with 113a vast amount of users. My plan was originally to build upon it to skip having 114to implement the low level parts of WebSocket myself. 115 116Here are the reasons why I have decided to move forward with WebSocket in 117curl **without using libWebSocket**: 118 119- doxygen generated docs only makes them hard to navigate. No tutorial, no 120 clearly written explanatory pages for specific functions. 121 122- seems (too) tightly integrated with a specific TLS library, while we want to 123 support WebSocket with whatever TLS library libcurl was already made to 124 work with. 125 126- seems (too) tightly integrated with event libraries 127 128- the references to threads and thread-pools in code and APIs indicate too 129 much logic for our purposes 130 131- "bloated" - it is a *huge* library that is actually more lines of code than 132 libcurl itself 133 134- WebSocket is a fairly simple protocol on the network/framing layer so 135 making a homegrown handling of it should be fine 136