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