• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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