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