Created
August 23, 2014 18:04
-
-
Save snmsts/532ca05abb28f03163e5 to your computer and use it in GitHub Desktop.
websocket test implementation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ql:quickload '(:clack :cl-async)) | |
(defpackage websocket.test | |
(:use :cl | |
:clack)) | |
(in-package :websocket.test) | |
(defvar *handler* | |
(clackup | |
(lambda (env) | |
(lambda (f) | |
(cond | |
((string= "/s" (getf env :request-uri)) | |
(let ((accept (let ((k (getf env :http-sec-websocket-key)) | |
(o7-guid "258EAFA5-E914-47DA-95CA-C5AB0DC85B11")) | |
(cl-base64:usb8-array-to-base64-string | |
(ironclad:digest-sequence | |
:sha1 (map '(vector (unsigned-byte 8)) #'char-code | |
(concatenate 'string k o7-guid))))))) | |
#+nil(funcall f `(101 (:upgrade "websocket" | |
:connection "Upgrade" | |
"Sec-WebSocket-Accept" ,accept))) ;; I can't cancel chunked encoding | |
(as:write-socket-data | |
(getf env :clack.io) | |
(babel:string-to-octets (format nil "HTTP/1.1 101 Switching Protocols | |
Upgrade: websocket | |
Connection: Upgrade | |
Sec-Websocket-Accept: ~A | |
" accept)) | |
:read-cb (lambda (socket data) | |
(let* ((offset 2) | |
fin mask | |
(opcode (aref data 0)) | |
(payloadlen (aref data 1))) | |
(setq fin (not (zerop (logand #x80 opcode))) | |
opcode (logand #x0f opcode) | |
mask (not (zerop (logand #x80 payloadlen))) | |
payloadlen (logand #x7f payloadlen) | |
payloadlen (if (<= 126 payloadlen) | |
(+ (if (= payloadlen 127) | |
(+ (ash (prog1 (aref data offset) | |
(incf offset)) 24) | |
(ash (prog1 (aref data offset) | |
(incf offset)) 16)) 0) | |
(ash (prog1 (aref data offset) | |
(incf offset)) 8) | |
(prog1 (aref data offset) | |
(incf offset))) | |
payloadlen)) | |
(when mask | |
(setq mask (make-array 4 :element-type '(unsigned-byte 8) :initial-contents | |
(loop :repeat 4 :collect (prog1 (aref data offset) | |
(incf offset)))))) | |
(let ((ar (subseq data offset) | |
#+nil(make-array payloadlen :element-type '(unsigned-byte 8)))) | |
(when mask | |
(loop :for i :from 0 | |
:for v :across ar | |
:do (setf (aref ar i) (logxor v (aref mask (mod i 4)))))) | |
(when (= 1 opcode) | |
'(setf ar (babel:octets-to-string ar :encoding :utf-8))) | |
(case opcode ;;forget opcode | |
((#x1 #x2 #xA) | |
(let* ((octets ar) | |
(len (length octets))) | |
(as:write-socket-data | |
socket | |
(flexi-streams:with-output-to-sequence (out) | |
(write-byte (+ (if fin #x80 0) (logand opcode #xf)) out) | |
(if (> 126 len) (write-byte len out) | |
(let ((4byte (<= (ash 1 16) len))) | |
(write-byte (if 4byte 127 126) out) | |
(when 4byte | |
(write-byte (ash len -24) out) | |
(write-byte (logand (ash len -16) #xff) out)) | |
(write-byte (logand (ash len -8) #xff) out) | |
(write-byte (logand len #xff) out))) | |
(write-sequence octets out))))) | |
((#x8) | |
;;(close-connection% stream nil nil) | |
) | |
((#x9))))))))) | |
(t | |
(funcall f `(200 (:content-type "text/html") | |
("<html> | |
<head> | |
<script> | |
function c() { | |
a=new WebSocket(\"ws://localhost:5000/s\"); | |
a.onmessage=function(evt){console.log(evt.data)} | |
} | |
function s() { | |
a.send(\"hoge*\") | |
} | |
</script> | |
</head> | |
<body> | |
hoge | |
</body> | |
</html> | |
"))))))) | |
:server :wookie)) | |
;;(clack:stop *handler*) | |
#+debug | |
(progn | |
(ql:quickload :usocket) | |
(usocket:with-client-socket (sock stream "localhost" 5000) | |
(format stream "GET /s HTTP/1.1~A~A" #\cr #\lf) | |
(format stream "Host: localhost:5000~A~A" #\cr #\lf) | |
(format stream "~A~A" #\cr #\lf) | |
(force-output stream) | |
#+nil(print (list (read-line stream) | |
(read-line stream) | |
(read-line stream) | |
(read-line stream))) | |
(loop :while t | |
:do (print (read-char stream)) | |
))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment