char/avril
(wip) why'd you have to go and make things so complicaaaaated?
git clone https://git.t4t.associates/char/avril
ab5df08
main
files
| README.md | 3.0 KiB |
| internal.d.ts | 835 B |
| lib.rs | 36.5 KiB |
| main.ts | 200 B |
| reader.rs | 5.2 KiB |
| websocket.ts | 14.0 KiB |
WebSocket
Implements the WHATWG WebSockets Standard client API
(new WebSocket(), send(), close(), onopen/onmessage/onerror/onclose, and CloseEvent)
over RFC 6455, using an in-tree decoder and fragment assembler, fastwebsockets for
masked writes, and the same rustls (webpki roots, ring) TLS configuration as fetch.
Behavior notes
- Framing runs on the Tokio runtime shared with fetch and filesystem work (
avril_host::Host). The read half lives in its own task because decoding consumes frame bytes across await points and is therefore not cancellation-safe; received messages and control frames cross to the connection task over a bounded channel. Reads stop when the guest falls behind (TCP back-pressure). - Incoming messages are limited to 16 MiB, including the total of all fragments. A message over this limit fails the connection with close code 1009, before reading the excess payload.
- Sends are queued in call order and awaited only for the write acknowledgement, so
bufferedAmount— not the socket — is the user-visible back-pressure signal, as in browsers. - The close handshake waits up to 30 seconds (RFC 6455 §7.1.5's "reasonable time") for the peer's close frame before giving up and reporting an abnormal closure (1006).
- After exchanging close frames, the client waits up to two seconds for the server to close TCP. If the server does not close, the client closes its own transport; either outcome is reported as a clean close.
- Close codes reported in
closeevents follow RFC 6455 §7.1.5: the code of the first close frame received (1005 when it carries none), or 1006 when no close frame was received. close()before the connection is established fails the connection (error then close) rather than racing the handshake. The cancellation reaches the connection loop whatever it is doing at the time, so a connection that completes its handshake in the same instant still reports the failure (error then close, withoutopen) instead of an open socket.- The event pump keeps a strong reference to the socket until its close event, so a socket with listeners is never collected while open (per the spec's GC rules); a socket without listeners is also held, which is permitted but not required.
- Permission checks happen synchronously in the constructor, as in
fetch.
not implemented
permessage-deflate(noSec-WebSocket-Extensionsis offered; a response offering one fails the connection)- proxy support, cookies, HSTS, and the other fetch integrations beyond permission checks
Sec-WebSocket-Protocolis validated against the response, butSec-WebSocket-Extensionsnegotiation is absent- the
Originrequest header (there is no ambient origin in this runtime) - connection-establishment timeouts (a black-holed server is governed by the OS TCP timeouts)
- ordinary writes are not interruptible: a stalled data or Pong write can delay processing
incoming close frames or a queued
close()call.