|
|
|
@@ -8,7 +8,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
; high level API
|
|
|
|
; high level API
|
|
|
|
with-websocket with-concurrent-websocket
|
|
|
|
with-websocket with-concurrent-websocket
|
|
|
|
send-message receive-message
|
|
|
|
send-message receive-message current-websocket
|
|
|
|
|
|
|
|
|
|
|
|
; low level API
|
|
|
|
; low level API
|
|
|
|
;; send-frame read-frame read-frame-payload
|
|
|
|
;; send-frame read-frame read-frame-payload
|
|
|
|
@@ -166,6 +166,7 @@
|
|
|
|
outbound-port)
|
|
|
|
outbound-port)
|
|
|
|
|
|
|
|
|
|
|
|
(write-string data len outbound-port)
|
|
|
|
(write-string data len outbound-port)
|
|
|
|
|
|
|
|
(flush-output outbound-port)
|
|
|
|
#t))
|
|
|
|
#t))
|
|
|
|
|
|
|
|
|
|
|
|
(define (send-message data #!optional (optype 'text) (ws (current-websocket)))
|
|
|
|
(define (send-message data #!optional (optype 'text) (ws (current-websocket)))
|
|
|
|
@@ -182,36 +183,28 @@
|
|
|
|
(u8vector-set! tmaskkey 1 (vector-ref frame-masking-key 1))
|
|
|
|
(u8vector-set! tmaskkey 1 (vector-ref frame-masking-key 1))
|
|
|
|
(u8vector-set! tmaskkey 2 (vector-ref frame-masking-key 2))
|
|
|
|
(u8vector-set! tmaskkey 2 (vector-ref frame-masking-key 2))
|
|
|
|
(u8vector-set! tmaskkey 3 (vector-ref frame-masking-key 3))
|
|
|
|
(u8vector-set! tmaskkey 3 (vector-ref frame-masking-key 3))
|
|
|
|
(define-external wsmaskkey blob (u8vector->blob/shared tmaskkey))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(define-external wslen int len)
|
|
|
|
((foreign-lambda* void ((blob wsmaskkey) (size_t wslen) (scheme-pointer wsv))
|
|
|
|
|
|
|
|
|
|
|
|
; TODO handle -1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(define-external wsv scheme-pointer payload)
|
|
|
|
|
|
|
|
((foreign-lambda* void ()
|
|
|
|
|
|
|
|
"
|
|
|
|
"
|
|
|
|
if (wslen > UINT_MAX) { return -1; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const unsigned char* maskkey2 = wsmaskkey;
|
|
|
|
const unsigned char* maskkey2 = wsmaskkey;
|
|
|
|
const unsigned int kd = *(unsigned int*)maskkey2;
|
|
|
|
const unsigned int kd = *(unsigned int*)maskkey2;
|
|
|
|
const unsigned char* __restrict kb = maskkey2;
|
|
|
|
const unsigned char* __restrict kb = maskkey2;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int i;
|
|
|
|
size_t i;
|
|
|
|
for (i = wslen >> 2; i != 0; --i)
|
|
|
|
for (i = wslen >> 2; i != 0; --i)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
*((unsigned int*)wsv) ^= kd;
|
|
|
|
*((unsigned int*)wsv) ^= kd;
|
|
|
|
wsv += 4;
|
|
|
|
wsv += 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const int rem = wslen & 3;
|
|
|
|
const size_t rem = wslen & 3;
|
|
|
|
for (i = 0; i < rem; ++i)
|
|
|
|
for (i = 0; i < rem; ++i)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
*((unsigned int*)wsv++) ^= kb[i];
|
|
|
|
*((unsigned int*)wsv++) ^= kb[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
"
|
|
|
|
"
|
|
|
|
))
|
|
|
|
) (u8vector->blob/shared tmaskkey) len payload)
|
|
|
|
payload)
|
|
|
|
payload)
|
|
|
|
|
|
|
|
|
|
|
|
(define (unmask fragment)
|
|
|
|
(define (unmask fragment)
|
|
|
|
@@ -227,46 +220,7 @@
|
|
|
|
(define (read-frame-payload inbound-port frame-payload-length)
|
|
|
|
(define (read-frame-payload inbound-port frame-payload-length)
|
|
|
|
(let ((masked-data (make-string frame-payload-length)))
|
|
|
|
(let ((masked-data (make-string frame-payload-length)))
|
|
|
|
(read-string! frame-payload-length masked-data inbound-port)
|
|
|
|
(read-string! frame-payload-length masked-data inbound-port)
|
|
|
|
masked-data)
|
|
|
|
masked-data))
|
|
|
|
;; (let* ((masked-data (make-string frame-payload-length)))
|
|
|
|
|
|
|
|
;; (read-string! frame-payload-length masked-data inbound-port)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;; (define tmaskkey (make-u8vector 4 #f #t #t))
|
|
|
|
|
|
|
|
;; (u8vector-set! tmaskkey 0 (vector-ref frame-masking-key 0))
|
|
|
|
|
|
|
|
;; (u8vector-set! tmaskkey 1 (vector-ref frame-masking-key 1))
|
|
|
|
|
|
|
|
;; (u8vector-set! tmaskkey 2 (vector-ref frame-masking-key 2))
|
|
|
|
|
|
|
|
;; (u8vector-set! tmaskkey 3 (vector-ref frame-masking-key 3))
|
|
|
|
|
|
|
|
;; (define-external wsmaskkey blob (u8vector->blob/shared tmaskkey))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;; (define-external wslen int frame-payload-length)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;; (define-external wsv scheme-pointer masked-data)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;; (if frame-masked
|
|
|
|
|
|
|
|
;; (begin
|
|
|
|
|
|
|
|
;; ((foreign-lambda* void ()
|
|
|
|
|
|
|
|
;; "
|
|
|
|
|
|
|
|
;; const unsigned char* maskkey2 = wsmaskkey;
|
|
|
|
|
|
|
|
;; const unsigned int kd = *(unsigned int*)maskkey2;
|
|
|
|
|
|
|
|
;; const unsigned char* __restrict kb = maskkey2;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;; for (int i = wslen >> 2; i != 0; --i)
|
|
|
|
|
|
|
|
;; {
|
|
|
|
|
|
|
|
;; *((unsigned int*)wsv) ^= kd;
|
|
|
|
|
|
|
|
;; wsv += 4;
|
|
|
|
|
|
|
|
;; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;; const int rem = wslen & 3;
|
|
|
|
|
|
|
|
;; for (int i = 0; i < rem; ++i)
|
|
|
|
|
|
|
|
;; {
|
|
|
|
|
|
|
|
;; *((unsigned int*)wsv++) ^= kb[i];
|
|
|
|
|
|
|
|
;; }
|
|
|
|
|
|
|
|
;; "
|
|
|
|
|
|
|
|
;; ))
|
|
|
|
|
|
|
|
;; masked-data)
|
|
|
|
|
|
|
|
;; masked-data))
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(define (read-frame total-size ws)
|
|
|
|
(define (read-frame total-size ws)
|
|
|
|
(let* ((inbound-port (websocket-inbound-port ws))
|
|
|
|
(let* ((inbound-port (websocket-inbound-port ws))
|
|
|
|
@@ -337,10 +291,8 @@
|
|
|
|
; Try to validate as an ascii string first. Its essentially
|
|
|
|
; Try to validate as an ascii string first. Its essentially
|
|
|
|
; free, doesn't generate garbage and is many, many times
|
|
|
|
; free, doesn't generate garbage and is many, many times
|
|
|
|
; faster than the general purpose validator.
|
|
|
|
; faster than the general purpose validator.
|
|
|
|
(define-external ws_utlen int len)
|
|
|
|
|
|
|
|
(define-external ws_uts scheme-pointer s)
|
|
|
|
|
|
|
|
(= 1
|
|
|
|
(= 1
|
|
|
|
((foreign-lambda* int ()
|
|
|
|
((foreign-lambda* int ((size_t ws_utlen) (scheme-pointer ws_uts))
|
|
|
|
"
|
|
|
|
"
|
|
|
|
if (ws_utlen > UINT_MAX) { return -1; }
|
|
|
|
if (ws_utlen > UINT_MAX) { return -1; }
|
|
|
|
|
|
|
|
|
|
|
|
@@ -354,7 +306,7 @@
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
C_return(1);
|
|
|
|
C_return(1);
|
|
|
|
"))))
|
|
|
|
") len s)))
|
|
|
|
(parse utf8-string (->parser-input s))))
|
|
|
|
(parse utf8-string (->parser-input s))))
|
|
|
|
|
|
|
|
|
|
|
|
(define (close-code->integer s)
|
|
|
|
(define (close-code->integer s)
|
|
|
|
@@ -570,7 +522,7 @@
|
|
|
|
"ping thread")))
|
|
|
|
"ping thread")))
|
|
|
|
|
|
|
|
|
|
|
|
; make sure the request meets the spec for websockets
|
|
|
|
; make sure the request meets the spec for websockets
|
|
|
|
(cond ((not (and (eq? (header-value 'connection headers #f) 'upgrade)
|
|
|
|
(cond ((not (and (member 'upgrade (header-values 'connection headers))
|
|
|
|
(string-ci= (car (header-value 'upgrade headers '(""))) "websocket")))
|
|
|
|
(string-ci= (car (header-value 'upgrade headers '(""))) "websocket")))
|
|
|
|
(signal (make-websocket-exception
|
|
|
|
(signal (make-websocket-exception
|
|
|
|
(make-property-condition 'missing-upgrade-header))))
|
|
|
|
(make-property-condition 'missing-upgrade-header))))
|
|
|
|
|