Common Lisp WebSocket client using usocket library
I am trying to upgrade the protocol going from HTTP 1.1 to WebSockets. I have tried using usocket . My code still follows (and is available as a GitHub gist ). After reading the handshake, the functions return an error NIL
or unexpected EOF
.
;; Define parameter sock for usocket stream
;; echo.websocket.org is a site for testing websockets
(defparameter sock (usocket:socket-connect "echo.websocket.org" 80))
;; Output confirms WebSocket protocol handshake as this implemented in browsers
(format (usocket:socket-stream sock) "~A~%~A~%~A~%~A~%~A~A~%~A~%~A~%~%"
"GET /?encoding=text HTTP/1.1"
"Connection: Upgrade"
"Host: echo.websocket.org"
"Origin: http://www.websocket.org"
"Sec-WebSocket-Key: " (generate-websocket-key)
"Sec-WebSocket-Version: 13"
"Upgrade: websocket")
;; Write output to stream
(force-output (usocket:socket-stream sock))
;; Returns NIL
(do ((line
(read-line (usocket:socket-stream sock) nil)
(read-line (usocket:socket-stream sock) nil)))
((not line))
(format t "~A" line))
;; Returns error: unexpected EOF
(read-line (usocket:socket-stream sock))
;; Returns NIL
(listen (usocket:socket-stream sock))
source to share
~%
the instructions FORMAT
do not carry over for HTTP protocols. It outputs the newline character #\newline
. The newline depends on the platform the code is running on: cr (old Macs, Lisp), crlf (Windows), or lf (Unix). Thus, if you write a newline to a stream, the result depends on the platform you are running on (or what the Lisp system thinks it should do). Windows has the same end-of-line convention as HTTP.
Note:
- on Unix is usually the
#\newline
same as#\linefeed
. One character. - in Windows is often the
#\newline
same as the sequence#\return
#\linefeed
. Two symbols. Some Lisp systems may ignore this and use Unix conventions.
HTTP uses crlf. In order to reliably write crlf, you need to write code #\return
, and #\linefeed
: (format stream "~a~a" #\return #\linefeed)
.
(defun write-crlf (stream)
(write-char #\return stream)
(write-char #\linefeed stream))
Some servers might be dumb enough to read input that doesn't follow the standard HTTP crlf conventions.
When opening a stream, there may be ways to specify a line termination convention. usocket
does not provide this functionality.
I would also use finish-output
(waits for completion) rather than force-output
(DOES NOT wait for I / O to complete).
source to share