@@ -115,7 +115,14 @@ defmodule Mint.WebSocket do
115115 import Mint.HTTP , only: [ get_private: 2 , put_private: 3 , protocol: 1 ]
116116
117117 @ typedoc """
118- An immutable data structure representing a WebSocket connection
118+ An immutable data structure representing WebSocket state.
119+
120+ You will usually want to keep these around:
121+
122+ * The Mint connection
123+ * The request reference for the WebSocket upgrade request
124+ * This WebSocket data structure
125+
119126 """
120127 @ opaque t :: % __MODULE__ {
121128 extensions: [ Extension . t ( ) ] ,
@@ -131,55 +138,52 @@ defmodule Mint.WebSocket do
131138 @ type error :: Mint.Types . error ( ) | WebSocketError . t ( ) | UpgradeFailureError . t ( )
132139
133140 @ typedoc """
134- Shorthand notations for control frames
141+ Shorthand notations for control frames.
135142
136- * `:ping` - shorthand for `{:ping, ""}`
137- * `:pong` - shorthand for `{:pong, ""}`
138- * `:close` - shorthand for `{:close, nil, nil}`
143+ * `:ping` - shorthand for `{:ping, ""}`
144+ * `:pong` - shorthand for `{:pong, ""}`
145+ * `:close` - shorthand for `{:close, nil, nil}`
139146
140147 These may be passed to `encode/2`. Frames decoded with `decode/2` are always
141148 in `t:frame/0` format.
142149 """
143150 @ type shorthand_frame :: :ping | :pong | :close
144151
145152 @ typedoc """
146- A WebSocket frame
147-
148- * `{:binary, binary}` - a frame containing binary data. Binary frames
149- can be used to send arbitrary binary data such as a PDF.
150- * `{:text, text}` - a frame containing string data. Text frames must be
151- valid utf8. Elixir has wonderful support for utf8: `String.valid?/1`
152- can detect valid and invalid utf8.
153- * `{:ping, binary}` - a control frame which the server should respond to
154- with a pong. The binary data must be echoed in the pong response.
155- * `{:pong, binary}` - a control frame which forms a reply to a ping frame.
156- Pings and pongs may be used to check the a connection is alive or to
157- estimate latency.
158- * `{:close, code, reason}` - a control frame used to request that a connection
159- be closed or to acknowledgee a close frame send by the server.
153+ A WebSocket frame.
154+
155+ * `{:binary, binary}` - a frame containing binary data. Binary frames
156+ can be used to send arbitrary binary data such as a PDF.
157+ * `{:text, text}` - a frame containing string data. Text frames must be
158+ valid utf8. Elixir has wonderful support for utf8: `String.valid?/1`
159+ can detect valid and invalid utf8.
160+ * `{:ping, binary}` - a control frame which the server should respond to
161+ with a pong. The binary data must be echoed in the pong response.
162+ * `{:pong, binary}` - a control frame which forms a reply to a ping frame.
163+ Pings and pongs may be used to check the a connection is alive or to
164+ estimate latency.
165+ * `{:close, code, reason}` - a control frame used to request that a connection
166+ be closed or to acknowledgee a close frame send by the server.
160167
161168 These may be passed to `encode/2` or returned from `decode/2`.
162169
163170 ## Close frames
164171
165172 In order to close a WebSocket connection gracefully, either the client or
166173 server sends a close frame. Then the other endpoint responds with a
167- close with code `1_000` and then closes the TCP connection. This can be
168- accomplished in Mint.WebSocket like so:
174+ close with code `1_000` and then closes the TCP/TLS connection. This can be
175+ accomplished in ` Mint.WebSocket` like so:
169176
170- ```elixir
171- {:ok, websocket, data} = Mint.WebSocket.encode(websocket, :close)
172- {:ok, conn} = Mint.WebSocket.stream_request_body(conn, ref, data)
177+ {:ok, websocket, data} = Mint.WebSocket.encode(websocket, :close)
178+ {:ok, conn} = Mint.WebSocket.stream_request_body(conn, ref, data)
173179
174- close_response = receive(do: (message -> message))
175- {:ok, conn, [{:data, ^ref, data}]} = Mint.WebSocket.stream(conn, close_response)
176- {:ok, websocket, [{:close, 1_000, ""}]} = Mint.WebSocket.decode(websocket, data)
180+ close_response = receive(do: (message -> message))
181+ {:ok, conn, [{:data, ^ref, data}]} = Mint.WebSocket.stream(conn, close_response)
182+ {:ok, websocket, [{:close, 1_000, ""}]} = Mint.WebSocket.decode(websocket, data)
177183
178- Mint.HTTP.close(conn)
179- ```
184+ Mint.HTTP.close(conn)
180185
181- [rfc6455
182- section 7.4.1](https://datatracker.ietf.org/doc/html/rfc6455#section-7.4.1)
186+ [RFC6455 § 7.4.1](https://datatracker.ietf.org/doc/html/rfc6455#section-7.4.1)
183187 documents codes which may be used in the `code` element.
184188 """
185189 @ type frame ::
@@ -206,8 +210,8 @@ defmodule Mint.WebSocket do
206210
207211 ## Options
208212
209- * `:extensions` - a list of extensions to negotiate. See the extensions
210- section below.
213+ * `:extensions` - a list of extensions to negotiate. See the extensions
214+ section below.
211215
212216 ## Extensions
213217
@@ -220,27 +224,33 @@ defmodule Mint.WebSocket do
220224 Extensions may be passed as a list of `Mint.WebSocket.Extension` structs
221225 or with the following shorthand notations:
222226
223- * `module` - shorthand for `{module, []}`
224- * `{module, params}` - shorthand for `{module, params, []}`
225- * `{module, params, opts}` - a shorthand which is expanded to a
226- `Mint.WebSocket.Extension` struct
227+ * `module` - shorthand for `{module, []}`
228+ * `{module, params}` - shorthand for `{module, params, []}`
229+ * `{module, params, opts}` - a shorthand which is expanded to a
230+ `Mint.WebSocket.Extension` struct
227231
228232 ## Examples
229233
230- ```elixir
231- {:ok, conn} = Mint.HTTP.connect(:http, "localhost", 9_000)
232- {:ok, conn, ref} =
233- Mint.WebSocket.upgrade(:ws, conn, "/", [], extensions: [Mint.WebSocket.PerMessageDeflate])
234- # or provide params:
235- {:ok, conn, ref} =
236- Mint.WebSocket.upgrade(
237- :ws,
238- conn,
239- "/",
240- [],
241- extensions: [{Mint.WebSocket.PerMessageDeflate, [:client_max_window_bits]]}]
242- )
243- ```
234+ First, establish the Mint connection:
235+
236+ {:ok, conn} = Mint.HTTP.connect(:http, "localhost", 9_000)
237+
238+ Then, send the upgrade request (with an extension in this example):
239+
240+ {:ok, conn, ref} =
241+ Mint.WebSocket.upgrade(:ws, conn, "/", [], extensions: [Mint.WebSocket.PerMessageDeflate])
242+
243+ Here's an example of providing extension parameters:
244+
245+ {:ok, conn, ref} =
246+ Mint.WebSocket.upgrade(
247+ :ws,
248+ conn,
249+ "/",
250+ [],
251+ extensions: [{Mint.WebSocket.PerMessageDeflate, [:client_max_window_bits]]}]
252+ )
253+
244254 """
245255 @ spec upgrade (
246256 scheme :: :ws | :wss ,
@@ -291,30 +301,36 @@ defmodule Mint.WebSocket do
291301
292302 @ doc """
293303 Creates a new WebSocket data structure given the server's reply to the
294- upgrade request
304+ upgrade request.
305+
306+ `request_ref` should be the reference of the request made with `upgrade/5`.
307+ `status` and `response_headers` should be the status code and headers
308+ of the server's response to the upgrade request—see the example below.
309+
310+ The returned [WebSocket data structure](`t:t/0`) is used to encode and decode frames.
295311
296312 This function will setup any extensions accepted by the server using
297313 the `c:Mint.WebSocket.Extension.init/2` callback.
298314
299315 ## Options
300316
301- * `:mode` - (default: `:active`) either `:active` or `:passive`. This
302- corresponds to the same option in `Mint.HTTP.connect/4`.
317+ * `:mode` - (default: `:active`) either `:active` or `:passive`. This
318+ corresponds to the same option in `Mint.HTTP.connect/4`.
303319
304320 ## Examples
305321
306- ```elixir
307- http_reply = receive(do: (message -> message))
308- {:ok, conn, [{:status, ^ref, status}, {:headers, ^ref, headers}, {:done, ^ref}]} =
309- Mint.WebSocket.stream(conn, http_reply)
322+ http_reply = receive(do: (message -> message))
323+
324+ {:ok, conn, [{:status, ^ref, status}, {:headers, ^ref, headers}, {:done, ^ref}]} =
325+ Mint.WebSocket.stream(conn, http_reply)
326+
327+ {:ok, conn, websocket} =
328+ Mint.WebSocket.new(conn, ref, status, headers)
310329
311- {:ok, conn, websocket} =
312- Mint.WebSocket.new(conn, ref, status, resp_headers)
313- ```
314330 """
315331 @ spec new (
316332 Mint.HTTP . t ( ) ,
317- reference ( ) ,
333+ Mint.Types . request_ref ( ) ,
318334 Mint.Types . status ( ) ,
319335 Mint.Types . headers ( )
320336 ) ::
@@ -360,23 +376,26 @@ defmodule Mint.WebSocket do
360376
361377 @ doc """
362378 A wrapper around `Mint.HTTP.stream/2` for streaming HTTP and WebSocket
363- messages
379+ messages.
364380
365- This function does not decode WebSocket frames. Instead, once a WebSocket
381+ ** This function does not decode WebSocket frames** . Instead, once a WebSocket
366382 connection has been established, decode any `{:data, request_ref, data}`
367383 frames with `decode/2`.
368384
369- This function is a drop-in replacement for `Mint.HTTP.stream/2` which
385+ This function is a drop-in replacement for `Mint.HTTP.stream/2`, which
370386 enables streaming WebSocket data after the bootstrapping HTTP/1 connection
371387 has concluded. It decodes both WebSocket and regular HTTP messages.
372388
373389 ## Examples
374390
375391 message = receive(do: (message -> message))
392+
376393 {:ok, conn, [{:data, ^websocket_ref, data}]} =
377394 Mint.WebSocket.stream(conn, message)
395+
378396 {:ok, websocket, [{:text, "hello world!"}]} =
379397 Mint.WebSocket.decode(websocket, data)
398+
380399 """
381400 @ spec stream ( Mint.HTTP . t ( ) , term ( ) ) ::
382401 { :ok , Mint.HTTP . t ( ) , [ Mint.Types . response ( ) ] }
@@ -419,7 +438,7 @@ defmodule Mint.WebSocket do
419438 end
420439
421440 @ doc """
422- Receives data from the socket
441+ Receives data from the socket.
423442
424443 This function is used instead of `stream/2` when the connection is
425444 in `:passive` mode. You must pass the `mode: :passive` option to
@@ -431,8 +450,10 @@ defmodule Mint.WebSocket do
431450 ## Examples
432451
433452 {:ok, conn, [{:data, ^ref, data}]} = Mint.WebSocket.recv(conn, 0, 5_000)
453+
434454 {:ok, websocket, [{:text, "hello world!"}]} =
435455 Mint.WebSocket.decode(websocket, data)
456+
436457 """
437458 @ spec recv ( Mint.HTTP . t ( ) , non_neg_integer ( ) , timeout ( ) ) ::
438459 { :ok , Mint.HTTP . t ( ) , [ Mint.Types . response ( ) ] }
@@ -460,12 +481,17 @@ defmodule Mint.WebSocket do
460481 end
461482
462483 @ doc """
463- Streams chunks of data on the connection
484+ Streams chunks of data on the connection.
464485
465486 `stream_request_body/3` should be used to send encoded data on an
466487 established WebSocket connection that has already been upgraded with
467488 `upgrade/5`.
468489
490+ > #### Encoding {: .warning}
491+ >
492+ > This function doesn't perform any encoding. You should use `encode/2`
493+ > to encode frames before sending them with `stream_request_body/3`.
494+
469495 This function is a wrapper around `Mint.HTTP.stream_request_body/3`. It
470496 delegates to that function unless the `request_ref` belongs to an HTTP/1
471497 WebSocket connection. When the request is an HTTP/1 WebSocket, this
@@ -479,6 +505,7 @@ defmodule Mint.WebSocket do
479505
480506 {:ok, websocket, data} = Mint.WebSocket.encode(websocket, {:text, "hello world!"})
481507 {:ok, conn} = Mint.WebSocket.stream_request_body(conn, websocket_ref, data)
508+
482509 """
483510 @ spec stream_request_body (
484511 Mint.HTTP . t ( ) ,
@@ -505,7 +532,7 @@ defmodule Mint.WebSocket do
505532 end
506533
507534 @ doc """
508- Encodes a frame into a binary
535+ Encodes a frame into a binary.
509536
510537 The resulting binary may be sent with `stream_request_body/3`.
511538
@@ -514,29 +541,27 @@ defmodule Mint.WebSocket do
514541
515542 ## Examples
516543
517- ```elixir
518- {:ok, websocket, data} = Mint.WebSocket.encode(websocket, {:text, "hello world"})
519- {:ok, conn} = Mint.WebSocket.stream_request_body(conn, websocket_ref, data)
520- ```
544+ {:ok, websocket, data} = Mint.WebSocket.encode(websocket, {:text, "hello world"})
545+ {:ok, conn} = Mint.WebSocket.stream_request_body(conn, websocket_ref, data)
546+
521547 """
522548 @ spec encode ( t ( ) , shorthand_frame ( ) | frame ( ) ) :: { :ok , t ( ) , binary ( ) } | { :error , t ( ) , any ( ) }
523549 defdelegate encode ( websocket , frame ) , to: Frame
524550
525551 @ doc """
526- Decodes a binary into a list of frames
552+ Decodes a binary into a list of frames.
527553
528- The binary may received from the connection with `Mint.HTTP. stream/2`.
554+ The binary may received from the connection with `stream/2`.
529555
530556 This function will invoke the `c:Mint.WebSocket.Extension.decode/2` callback
531557 for any accepted extensions.
532558
533559 ## Examples
534560
535- ```elixir
536- message = receive(do: (message -> message))
537- {:ok, conn, [{:data, ^ref, data}]} = Mint.HTTP.stream(conn, message)
538- {:ok, websocket, frames} = Mint.WebSocket.decode(websocket, data)
539- ```
561+ message = receive(do: (message -> message))
562+ {:ok, conn, [{:data, ^ref, data}]} = Mint.HTTP.stream(conn, message)
563+ {:ok, websocket, frames} = Mint.WebSocket.decode(websocket, data)
564+
540565 """
541566 @ spec decode ( t ( ) , data :: binary ( ) ) ::
542567 { :ok , t ( ) , [ frame ( ) | { :error , term ( ) } ] } | { :error , t ( ) , any ( ) }
0 commit comments