This package, rfc6455, provides RFC 6455 compatible WebSockets server and client interfaces for Racket, building on Racket’s web-server collection.
Besides support for RFC 6455, the final WebSockets standard, the package also incorporates code supporting the earlier, draft hybi-00 proposal, because several common older browsers still use this protocol variant.
Wikipedia has a section on browser support for WebSocket protocol variations. In 2013, at the time this manual was written, it stated that "all the latest browsers except Android browser support the latest specification (RFC 6455) of the WebSocket protocol." For up-to-date, detailed information on browser support for WebSockets, see caniuse.com.
This package has been developed against
Firefox 24.0 (which is an RFC 6455 peer)
Chrome 30.0.1599.101 (which is an RFC 6455 peer)
Safari 5.1.10 (which is a hybi-00 peer)
Version 2.0.0 of this library introduces a new interface to streaming message reception, ws-recv-stream, and makes a breaking change to the way ws-conn? values work as synchronizable events. The synchronization result of such an event is now a received message, where previously it was an uninteresting value. See the (new) procedure ws-recv-evt.
In addition, prior to version 2.0.0, the default #:payload-type for ws-recv was actually 'text, even though the documentation claimed that it was 'auto. From version 2.0.0, the default is 'auto in both the documentation and the implementation.
Version 1.0.1 of this library is the last version with the old #:stream? interface to streaming receives. It also has an interface bug: when (1) using a ws-conn? as an synchronizable event, (2) with an event-handler that calls ws-recv, (3) connected to a client that occasionally sends websocket "ping" frames, the call to ws-recv may get stuck waiting for the next non-"ping" frame, leading to a kind of temporary stall on the thread invoking sync. This bug was the chief motivation for the changes of version 2.0.0.
Using the legacy net/websocket-compatible interface:
Using an interface that supports URL path matching and WebSocket subprotocol selection:
(require net/rfc6455) (ws-serve* #:port 8081 (ws-service-mapper ["/test" ; the URL path (regular expression) [(subprotocol) ; if client requests subprotocol "subprotocol" (lambda (c) (ws-send! c "You requested a subprotocol"))] [(#f) ; if client did not request any subprotocol (lambda (c) (ws-send! c "You didn't explicitly request a subprotocol"))]]))
Creating a client connection:
(require net/rfc6455) (require net/url) (define c (ws-connect (string->url "ws://localhost:8081/"))) (ws-send! c "Hello world!")
All the code in this package is licensed under the LGPL, version 3.0 or any later version. Each source file has a brief copyright and licensing notice attached, but see the licence text itself for full details.
The only exceptions to the above are the files marked "public domain" in the net/rfc6455/examples directory. They are intended to be examples of usage of the package for people to build on without concern for licensing minutiae.
|(require net/rfc6455)||package: rfc6455|
The interface is based on the net/websocket API from older versions of Racket, with some extensions and differences.
(ws-conn-supports-payload-type? c payload-type) → boolean? c : ws-conn? payload-type : symbol?
(ws-service-mapper [uri-regexp [(protocol ...) function-expr] ...] ...)
protocol = symbol | #f
Each uri-regexp is matched against an incoming request’s URL in turn until one matches. Then,
if the client supplied a Sec-WebSocket-Protocol header, each token from that header is checked against the protocols in turn. If one matches, the corresponding function-expr is used as the connection handler; or,
if no such header was supplied, the first function-expr with a literal #f among its protocols is used.
The function-exprs must evaluate to connection handler procedures, each taking a ws-conn? as their only argument.
(Note: Only RFC 6455 peers support fragmentation and non-text payloads. Attempts to use these features with hybi-00 peers will signal an error. See ws-conn-supports-fragmentation? and ws-conn-supports-payload-type?.)
If payload is a string, it is converted to bytes using string->bytes/utf-8 before transmission. If it is an input-port, it is read from and streamed using multiple WebSockets message fragments to the peer until it yields eof (see also rfc6455-stream-buffer-size).
If flush? is false, the buffers of the underlying connection socket output-ports are not flushed after sending the message. Otherwise (i.e. by default), they are flushed.
If payload-type is 'text or 'binary, the appropriate WebSockets content type bit is set upon transmission.
Fragmented messages can be sent using this procedure.
The first fragment in a sequence must have payload-type set to 'text or 'binary. Every subsequent fragment in the same sequence must have payload-type set to 'continuation.
The final fragment in a sequence must have final-fragment? set to a non-false value. Every other fragment in a sequence must have final-fragment? set to #f.
For single-fragment (unfragmented) messages, the defaults are fine: a plain (ws-send! c payload) is enough. Here is an example of a multi-fragment message:
(ws-send! c #"first" #:final-fragment? #f) (ws-send! c #"second" #:final-fragment? #f #:payload-type 'continuation) (ws-send! c #"third" #:final-fragment? #t #:payload-type 'continuation)
(Note: Only RFC 6455 peers support binary payloads. Attempts to use 'binary payload-type with hybi-00 peers will signal an error. See ws-conn-supports-payload-type?.)
Returns either a string or a bytes, depending on payload-type. If a specific 'text or 'binary payload type is requested, the corresponding result type is returned, or if 'auto is requested, the message’s own text/binary indicator bit is used to decide which to return. If eof occurs mid-message, fragments so far received are discarded and eof is returned.
Multi-fragment messages are transparently reassembled into a single string or bytes.
The same caveats regarding payload-type apply here as for ws-recv.
(Note: Only RFC 6455 peers support streaming. Attempts to use this procedure with hybi-00 peers will signal an error. See ws-conn-supports-fragmentation?.)
Returns an input port from which the bytes or characters making up the message can be read. An end-of-file from the resulting input port is ambiguous: it does not separate the end of the message being read from the end of the connection itself. Use ws-conn-closed? to disambiguate, though beware of time-of-check-to-time-of-use issues.
Multi-fragment messages are transparently reassembled. Fragment boundaries are not preserved when reading from the returned input port.
(Note: hybi-00 peers do not have room in their wire protocol for the status and reason codes. See ws-conn-signals-status-on-close?.)
(rfc6455-stream-buffer-size size) → void? size : integer?
(hybi00-framing-mode mode) → void? mode : (or/c 'new 'old)
This parameter defaults to 300 seconds, i.e. five minutes.