diff --git a/net-doc/net/scribblings/net.scrbl b/net-doc/net/scribblings/net.scrbl index 6c7ecd2e7f..7f31fb982f 100644 --- a/net-doc/net/scribblings/net.scrbl +++ b/net-doc/net/scribblings/net.scrbl @@ -8,7 +8,6 @@ @include-section["http-client.scrbl"] @include-section["url.scrbl"] @include-section["uri-codec.scrbl"] -@include-section["websocket.scrbl"] @include-section["ftp.scrbl"] @include-section["sendurl.scrbl"] @include-section["smtp.scrbl"] diff --git a/net-doc/net/scribblings/websocket.scrbl b/net-doc/net/scribblings/websocket.scrbl deleted file mode 100644 index d9d1304f1e..0000000000 --- a/net-doc/net/scribblings/websocket.scrbl +++ /dev/null @@ -1,120 +0,0 @@ -#lang scribble/doc -@(require "common.rkt" - scribble/bnf - (for-label net/url unstable/contract web-server/http racket/list - racket/async-channel - (prefix-in raw: (for-label net/tcp-unit)) - net/websocket - net/websocket/client - net/websocket/server - net/websocket/conn)) - -@title[#:tag "websocket"]{WebSocket} - -@defmodule[net/websocket] - -The @racketmodname[net/websocket] library provides -utilities to run and communicate with WebSocket servers, -as specified in @link["http://www.whatwg.org/specs/web-socket-protocol/"]{the WebSocket protocol} IETF draft -as of August 16th, 2010. - -This module provides the exports from @racketmodname[net/websocket/client] and @racketmodname[net/websocket/server]. - -@section{Client API} - -@defmodule[net/websocket/client] - -@defproc[(ws-url? [x any/c]) boolean?]{ Returns true if @racket[x] is a @racket[url?] and has a @racket[url-scheme] equal to @litchar["ws"] or @litchar["wss"]. } - -@defproc[(wss-url? [x any/c]) boolean?]{ Returns true if @racket[x] is a @racket[url?] and has a @racket[url-scheme] equal to @litchar["wss"]. } - -@defproc[(ws-connect [u ws-url?] - [#:headers headers (listof header?) empty]) - open-ws-conn?]{ - Connects to the WebSocket server specified by @racket[u], providing @racket[headers] as additional headers. - Returns the connection handle. -} - -This module also provides the exports from @racketmodname[net/websocket/conn]. - -@section{Server API} - -@defmodule[net/websocket/server] - -@defproc[(ws-serve [conn-handle (open-ws-conn? any/c . -> . void)] - [#:conn-headers - conn-headers - (bytes? (listof header?) . -> . (values (listof header?) any/c)) - (λ (b hs) (values empty (void)))] - [#:tcp@ tcp@ (unit/c (import) (export tcp^)) raw:tcp@] - [#:port port tcp-listen-port? 80] - [#:listen-ip listen-ip (or/c string? false/c) #f] - [#:max-waiting max-waiting integer? 4] - [#:timeout timeout integer? (* 60 60)] - [#:confirmation-channel - confirm-ch - (or/c false/c async-channel?) - #f]) - (-> void)]{ - - Starts a WebSocket server where each new connection uses @racket[conn-headers] to compute - what headers the client receives based on the client's request line and headers. @racket[conn-headers] - also returns a piece of state that will be passed to @racket[conn-handle] as its second argument. - After the connection handshake is finished, @racket[conn-handle] receives the connection and is in - sole control until the WebSocket connection completes. - - All other arguments are used as in a @secref["dispatch-server-unit" #:doc '(lib "web-server/scribblings/web-server-internal.scrbl")]. Similarly, the return result is a function that shuts down the server, just like a dispatch server. - - The @racket[#:tcp@] keyword is provided for building an SSL server. -} - -This module also provides the exports from @racketmodname[net/websocket/conn]. - -@section{Connections} - -@defmodule[net/websocket/conn] - -WebSocket connection are synchronizable events. - -@defparam[framing-mode mode (symbols 'old 'new)]{ Controls whether framing is as before August 16th, 2010 or after. (Most Web browsers currently support only @racket['old] and they are incompatible, so you must choose the correct one.) Defaults to @racket['old].} - -@defproc[(ws-conn? [x any/c]) boolean?]{ Returns true if @racket[x] is a WebSocket connection. } - -@defproc[(open-ws-conn? [x any/c]) boolean?]{ Returns true if @racket[x] is an open WebSocket connection. } - -@defproc[(ws-conn-line [ws ws-conn?]) bytes?]{ Returns the request/response line of the WebSocket connection. } -@defproc[(ws-conn-closed? [ws ws-conn?]) boolean?]{ Returns true if the WebSocket connection has been closed. } -@defproc[(ws-conn-headers [ws ws-conn?]) (listof header?)]{ Returns the headers of the WebSocket connection. } - -WebSocket connection support only blocking calls: - -@defproc[(ws-send! [ws open-ws-conn?] [s string?]) void]{ Sends @racket[s] over @racket[ws]. } -@defproc[(ws-recv [ws open-ws-conn?]) (or/c string? eof-object?)]{ Receives a string from @racket[ws]. Returns @racket[eof] if the other end closes the connection. } - -@defproc[(ws-close! [ws open-ws-conn?]) void]{ Closes @racket[ws]. } - -@section{Example} - -This is a WebSocket echo server compatible with the browser origin security model: - -@racketblock[ -(ws-serve - #:port 8080 - (λ (wsc _) - (let loop () - (define m (ws-recv wsc)) - (printf "~a\n" m) - (unless (eof-object? m) - (ws-send! wsc m) - (loop)))) - #:conn-headers - (λ (_ hs) - (define origin - (header-value (headers-assq* #"Origin" hs))) - (values - (list - (make-header #"Sec-WebSocket-Origin" origin) - (make-header #"Sec-WebSocket-Location" - #"ws://localhost:8080/")) - #f))) -] diff --git a/net-test/tests/net/info.rkt b/net-test/tests/net/info.rkt index 5550a5749e..1c4d8ecbf5 100644 --- a/net-test/tests/net/info.rkt +++ b/net-test/tests/net/info.rkt @@ -1,4 +1,3 @@ #lang info -(define test-responsibles '(("websocket.rkt" jay) - ("url-port.rkt" jay))) +(define test-responsibles '(("url-port.rkt" jay))) diff --git a/net-test/tests/net/main.rkt b/net-test/tests/net/main.rkt index ec19dfc969..8a9866b7fd 100644 --- a/net-test/tests/net/main.rkt +++ b/net-test/tests/net/main.rkt @@ -14,8 +14,7 @@ (prefix-in cookie: "cookie.rkt") (prefix-in encoders: "encoders.rkt") (prefix-in mime: "mime.rkt") - (prefix-in url-port: "url-port.rkt") - (prefix-in websocket: "websocket.rkt")) + (prefix-in url-port: "url-port.rkt")) (define (tests) (test do (ip:tests) @@ -28,7 +27,6 @@ do (cookie:tests) do (encoders:tests) do (mime:tests) - do (url-port:tests) - do (websocket:tests))) + do (url-port:tests))) (tests) diff --git a/net-test/tests/net/stress/websocket.rkt b/net-test/tests/net/stress/websocket.rkt deleted file mode 100644 index c4c9a31919..0000000000 --- a/net-test/tests/net/stress/websocket.rkt +++ /dev/null @@ -1,38 +0,0 @@ -#lang racket/base -(require tests/stress - net/websocket - net/url - racket/async-channel) - -(fit "websocket echo server" - 500 - (λ (n) - (define confirm (make-async-channel)) - (define shutdown! - (ws-serve #:port 0 - #:confirmation-channel confirm - (λ (wsc _) - (let loop () - (define m (ws-recv wsc)) - (unless (eof-object? m) - (ws-send! wsc m) - (loop)))))) - (define port (async-channel-get confirm)) - - (define THREADS 10) - (define REQS n) - - (for-each thread-wait - (for/list ([t (in-range THREADS)]) - (thread - (λ () - (define conn (ws-connect (string->url (format "ws://localhost:~a" port)))) - (for ([r (in-range REQS)]) - (ws-send! conn "ping") - (ws-recv conn)))))) - - (shutdown!))) - -(module+ test - (module config info - (define random? #t))) diff --git a/net-test/tests/net/websocket.rkt b/net-test/tests/net/websocket.rkt deleted file mode 100644 index 9da949228d..0000000000 --- a/net-test/tests/net/websocket.rkt +++ /dev/null @@ -1,97 +0,0 @@ -#lang racket -(require net/websocket/client - net/websocket/server - net/websocket/conn - net/websocket/handshake - racket/async-channel - net/url - rackunit - tests/net/available - tests/eli-tester) - -(define RANDOM-K 100) - -(provide tests) -(module+ main (tests)) -(define (tests) - (test - (for ([i (in-range RANDOM-K)]) - (define o (random 256)) - (define t (random 256)) - (define bot (if (o . < . t) o t)) - (define top (if (o . < . t) t o)) - (define botc (integer->char bot)) - (define topc (integer->char top)) - (test #:failure-prefix (format "~a / ~a" botc topc) - (<= bot (char->integer (random-char-between botc topc)) top))) - - (for ([i (in-range RANDOM-K)]) - (test (char-alphabetic? (random-alpha-char)))) - - (count-spaces "") => 0 - (count-spaces " ") => 3 - (count-spaces (make-string RANDOM-K #\space)) => RANDOM-K - - (count-spaces "18x 6]8vM;54 *(5: { U1]8 z [ 8") => 12 - (count-spaces "1_ tx7X d < nw 334J702) 7]o}` 0") => 10 - - (for ([i (in-range RANDOM-K)]) - (define len (add1 i)) - (define s (make-string len #\0)) - (define how-many (random len)) - (test (count-spaces (add-spaces how-many s)) => how-many)) - - (remove-alphas "A0A") => "0" - (remove-alphas "0") => "0" - (remove-alphas (make-string RANDOM-K #\A)) => "" - - (remove-alphas "18x 6]8vM;54 *(5: { U1]8 z [ 8") => "1868545188" - (remove-alphas "1_ tx7X d < nw 334J702) 7]o}` 0") => "1733470270" - - (for ([i (in-range RANDOM-K)]) - (define s (number->string i)) - (test (remove-alphas (add-alphas s)) => s)) - - (key->number "18x 6]8vM;54 *(5: { U1]8 z [ 8") => 155712099 - (key->number "1_ tx7X d < nw 334J702) 7]o}` 0") => 173347027 - - (for ([i (in-range RANDOM-K)]) - (test (key->number (number->key i)) => i)) - - (for ([i (in-range RANDOM-K)]) - (define-values (k1 k2 k3 ans) (generate-key)) - (test (handshake-solution k1 k2 k3) => ans)) - - (handshake-solution "18x 6]8vM;54 *(5: { U1]8 z [ 8" - "1_ tx7X d < nw 334J702) 7]o}` 0" - #"Tm[K T2u") - => #"fQJ,fN/4F4!~K~MH" - - (local [(define (test-echo-server) - (define r (number->string (random 1000))) - (define confirm (make-async-channel)) - (define shutdown! - (ws-serve #:port 0 - #:confirmation-channel confirm - (λ (wsc _) - (let loop () - (define m (ws-recv wsc)) - (unless (eof-object? m) - (ws-send! wsc m) - (loop)))))) - (define p (async-channel-get confirm)) - (define conn - (ws-connect (string->url (format "ws://localhost:~a" p)))) - (test (ws-send! conn r) - (ws-recv conn) => r - (ws-send! conn "a") - (ws-recv conn) => "a" - (ws-close! conn)) - (test (shutdown!)))] - (when (tcp-localhost-available?) - (test #:failure-prefix "old" - (parameterize ([framing-mode 'old]) (test-echo-server)) - #:failure-prefix "new" - (parameterize ([framing-mode 'new]) (test-echo-server))))))) - -(module+ test (require (submod ".." main))) ; for raco test & drdr diff --git a/net-test/tests/net/websocket/example.rkt b/net-test/tests/net/websocket/example.rkt deleted file mode 100644 index 48f20a9b48..0000000000 --- a/net-test/tests/net/websocket/example.rkt +++ /dev/null @@ -1,38 +0,0 @@ -#lang racket -(require net/websocket - web-server/http - racket/runtime-path - web-server/templates - web-server/servlet-env) - -(module test racket/base) - -(framing-mode 'old) - -(define stop-ws! - (ws-serve (λ (wsc _) - (let loop () - (define m (ws-recv wsc)) - (printf "~a\n" m) - (unless (eof-object? m) - (ws-send! wsc m) - (loop)))) - #:conn-headers - (λ (_ hs) - (define origin (header-value (headers-assq* #"Origin" hs))) - (values (list (make-header #"Sec-WebSocket-Origin" origin) - (make-header #"Sec-WebSocket-Location" #"ws://localhost:8080/")) - #f)) - #:port 8080)) - -(define-runtime-path example-pth ".") - -(serve/servlet (λ (req) - (response/full - 200 #"Okay" - (current-seconds) TEXT/HTML-MIME-TYPE - empty - (list (string->bytes/utf-8 (include-template "index.html"))))) - #:servlet-path "/" - #:port 8081 - #:extra-files-paths (list example-pth)) diff --git a/net-test/tests/net/websocket/index.html b/net-test/tests/net/websocket/index.html deleted file mode 100644 index 11da6ed2b8..0000000000 --- a/net-test/tests/net/websocket/index.html +++ /dev/null @@ -1,25 +0,0 @@ - - -
- -" + message + "
"); - node.hide(); - $("#inbox").append(node); - node.show(); -} - -jQuery.fn.enable = function(opt_enable) { - if (arguments.length && !opt_enable) { - this.attr("disabled", "disabled"); - } else { - this.removeAttr("disabled"); - } - return this; -}; - -jQuery.fn.disable = function() { - this.enable(false); - return this; -}; diff --git a/net-test/tests/net/websocket/style.css b/net-test/tests/net/websocket/style.css deleted file mode 100644 index 1c40ba43b0..0000000000 --- a/net-test/tests/net/websocket/style.css +++ /dev/null @@ -1,48 +0,0 @@ -body { - background: white; - margin: 10px; -} - -body, -input { - font-family: sans-serif; - font-size: 10pt; - color: black; -} - -table { - border-collapse: collapse; - border: 0; -} - -td { - border: 0; - padding: 0; -} - -#body { - position: absolute; - bottom: 10px; - left: 10px; -} - -#input { - margin-top: 0.5em; -} - -#inbox div { - padding-top: 0.25em; -} - -#nav { - float: right; - z-index: 99; -} - -legend { - display: none; -} - -fieldset { - border: none; -}