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))

      

+3


source to share


1 answer


~%

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).

+8


source







All Articles