[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] externals/websocket 413702e: Update websocket library to version
From: |
Andrew Hyatt |
Subject: |
[elpa] externals/websocket 413702e: Update websocket library to version 1.13. |
Date: |
Sat, 9 Jan 2021 20:55:15 -0500 (EST) |
branch: externals/websocket
commit 413702e94fd95b796e2944705cbac63ca5131859
Author: Andrew Hyatt <ahyatt@gmail.com>
Commit: Andrew Hyatt <ahyatt@gmail.com>
Update websocket library to version 1.13.
The major changes are:
- Made all tests runnable via ert, and re-introduced the python-based
webserver test.
- Fixes an issue with infinite loops when websockets get an error. We now
do not attempt to reconnect when the connection is dropped.
- Fixes an issue with nowait connection timings.
- Fixes an issue with handshake protocol that was an issue on some servers.
---
testserver.py | 7 +-
websocket-functional-test.el | 227 +++++++++++-----------------
websocket-test.el | 347 ++++++++++++++++++++++++++++++-------------
websocket.el | 39 ++---
4 files changed, 343 insertions(+), 277 deletions(-)
diff --git a/testserver.py b/testserver.py
index 5cfcb96..46cf62d 100644
--- a/testserver.py
+++ b/testserver.py
@@ -1,3 +1,4 @@
+#!/usr/bin/env python3
import logging
import tornado
import tornado.web
@@ -12,8 +13,8 @@ class EchoWebSocket(websocket.WebSocketHandler):
logging.info("OPEN")
def on_message(self, message):
- logging.info(u"ON_MESSAGE: {0}".format(message))
- self.write_message(u"You said: {0}".format(message))
+ logging.info("ON_MESSAGE: {0}".format(message))
+ self.write_message(message)
def on_close(self):
logging.info("ON_CLOSE")
@@ -29,6 +30,6 @@ if __name__ == "__main__":
(r"/", EchoWebSocket),
])
server = httpserver.HTTPServer(application)
- server.listen(9999)
+ server.listen(9999, "127.0.0.1")
logging.info("STARTED: Server start listening")
ioloop.IOLoop.instance().start()
diff --git a/websocket-functional-test.el b/websocket-functional-test.el
index cc9ac70..8a599d0 100644
--- a/websocket-functional-test.el
+++ b/websocket-functional-test.el
@@ -4,7 +4,7 @@
;; This program is free software; you can redistribute it and/or
;; modify it under the terms of the GNU General Public License as
-;; published by the Free Software Foundation; either version 3 of the
+;; published by the Free Software Foundation; either version 2 of the
;; License, or (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful, but
@@ -17,147 +17,90 @@
;;; Commentary:
-;; Usage: emacs -batch -Q -L . -l websocket-functional-test.el
+;; These are functional tests that may fail for various environmental reasons,
+;; such as blocked ports. For example Windows users have to have gnutls DLLs in
+;; the Emacs bin directory for this to work. A firewall may also interfere with
+;; these tests.
;;
-;; Note: this functional tests requires that you have python with the
-;; Tornado web server. See http://www.tornadoweb.org/en/stable/ for
-;; information on aquiring.
+;; These tests are written to test the basic connectivity and message-sending.
+;; Corner-cases and error handling is tested in websocket-test.el.
-(require 'tls) ;; tests a particular bug we had on emacs 23
-(setq debug-on-error t)
+(require 'tls) ;; tests a particular bug we had on Emacs 23
(require 'websocket)
-(eval-when-compile (require 'cl))
-
-;;;;;;;;;;;;;;;;;;;;;;;
-;; Local server test ;;
-;;;;;;;;;;;;;;;;;;;;;;;
-
-(message "Testing with local server")
-
-(setq websocket-debug t)
-
-(defvar wstest-server-buffer (get-buffer-create "*wstest-server*"))
-(defvar wstest-server-name "wstest-server")
-(defvar wstest-server-proc
- (start-process wstest-server-name wstest-server-buffer
- "python" "testserver.py" "--log_to_stderr" "--logging=debug"))
-(sleep-for 1)
-
-(defvar wstest-msgs nil)
-(defvar wstest-closed nil)
-
-(message "Opening the websocket")
-
-(defvar wstest-ws
- (websocket-open
- "ws://127.0.0.1:9999"
- :on-message (lambda (_websocket frame)
- (push (websocket-frame-text frame) wstest-msgs)
- (message "ws frame: %S" (websocket-frame-text frame))
- (error "Test error (expected)"))
- :on-close (lambda (_websocket) (setq wstest-closed t))))
-
-(defun wstest-pop-to-debug ()
- "Open websocket log buffer. Not used in testing. Just for debugging."
- (interactive)
- (pop-to-buffer (websocket-get-debug-buffer-create wstest-ws)))
-
-(sleep-for 0.1)
-(assert (websocket-openp wstest-ws))
-
-(assert (null wstest-msgs))
-
-(websocket-send-text wstest-ws "你好")
-
-(sleep-for 0.1)
-(assert (equal (car wstest-msgs) "You said: 你好"))
-(setf (websocket-on-error wstest-ws) (lambda (_ws _type _err)))
-(websocket-send-text wstest-ws "Hi after error!")
-(sleep-for 0.1)
-(assert (equal (car wstest-msgs) "You said: Hi after error!"))
-
-(websocket-close wstest-ws)
-(assert (null (websocket-openp wstest-ws)))
-
-(if (not (eq system-type 'windows-nt))
- ; Windows doesn't have support for the SIGSTP signal, so we'll just kill
- ; the process.
- (stop-process wstest-server-proc))
-(kill-process wstest-server-proc)
-
-;; Make sure the processes are closed. This happens asynchronously,
-;; so let's wait for it.
-(sleep-for 1)
-(assert (null (process-list)) t)
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Remote server test, with wss ;;
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-;; echo.websocket.org has an untrusted certificate, for the test to
-;; proceed, we need to disable trust checking.
-(setq tls-checktrust nil)
-
-(when (>= (string-to-number (substring emacs-version 0 2)) 24)
- (message "Testing with wss://echo.websocket.org")
- (when (eq system-type 'windows-nt)
- (message "Windows users must have gnutls DLLs in the emacs bin
directory."))
- (setq wstest-ws
- (websocket-open
- "wss://echo.websocket.org"
- :on-open (lambda (_websocket)
- (message "Websocket opened"))
- :on-message (lambda (_websocket frame)
- (push (websocket-frame-text frame) wstest-msgs)
- (message "ws frame: %S" (websocket-frame-text frame)))
- :on-close (lambda (_websocket)
- (message "Websocket closed")
- (setq wstest-closed t)))
- wstest-msgs nil)
- (sleep-for 0.3)
- (assert (websocket-openp wstest-ws))
- (sleep-for 0.6)
- (assert (eq 'open (websocket-ready-state wstest-ws)))
- (assert (null wstest-msgs))
- (websocket-send-text wstest-ws "Hi!")
- (sleep-for 1)
- (assert (equal (car wstest-msgs) "Hi!"))
- (websocket-close wstest-ws))
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Local client and server ;;
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-(message "Testing with emacs websocket server.")
-(message "If this does not pass, make sure your firewall allows the
connection.")
-(setq wstest-closed nil)
-(let ((server-conn (websocket-server
- 9998
- :host 'local
- :on-message (lambda (ws frame)
- (message "Server received text!")
- (websocket-send-text
- ws (websocket-frame-text frame)))
- :on-open (lambda (_websocket) "Client connection opened!")
- :on-close (lambda (_websocket)
- (setq wstest-closed t)))))
- (setq wstest-msgs nil
- wstest-ws
- (websocket-open
- "ws://localhost:9998"
- :on-message (lambda (_websocket frame)
- (message "ws frame: %S" (websocket-frame-text frame))
- (push
- (websocket-frame-text frame) wstest-msgs))))
-
- (assert (websocket-openp wstest-ws))
- (websocket-send-text wstest-ws "你好")
- (sleep-for 0.3)
- (assert (equal (car wstest-msgs) "你好"))
- (websocket-server-close server-conn))
-(assert wstest-closed)
-(websocket-close wstest-ws)
-
-(sleep-for 1)
-(assert (null (process-list)) t)
-(message "\nAll tests passed!\n")
+(require 'cl)
+
+;;; Code:
+
+(defmacro websocket-test-wait-with-timeout (timeout &rest body)
+ "Run BODY until true or TIMEOUT (in seconds) is reached.
+
+Will return false if the timeout was reached. This macro is not
+written to be used widely."
+ `(let ((begin (current-time))
+ (result nil))
+ (while (and (< (- (float-time (time-subtract (current-time) begin)))
,timeout) (not result))
+ (setq result ,@body)
+ (sleep-for 0.5))
+ result))
+
+(defun websocket-functional-client-test (wstest-server-url)
+ "Run the main part of an ert test against WSTEST-SERVER-URL."
+ ;; the server may have an untrusted certificate, for the test to proceed, we
+ ;; need to disable trust checking.
+ (let* ((tls-checktrust nil)
+ (wstest-closed nil)
+ (wstest-msg)
+ (wstest-server-proc)
+ (wstest-ws
+ (websocket-open
+ wstest-server-url
+ :on-message (lambda (_websocket frame)
+ (setq wstest-msg (websocket-frame-text frame)))
+ :on-close (lambda (_websocket) (setq wstest-closed t)))))
+ (should (websocket-test-wait-with-timeout 2 (websocket-openp wstest-ws)))
+ (should (websocket-test-wait-with-timeout 2 (eq 'open
(websocket-ready-state wstest-ws))))
+ (should (null wstest-msg))
+ (websocket-send-text wstest-ws "Hi!")
+ (should (websocket-test-wait-with-timeout 5 (equal wstest-msg "Hi!")))
+ (websocket-close wstest-ws)))
+
+(ert-deftest websocket-client-with-local-server ()
+ ;; If testserver.py cannot start, this test will fail. In general, if you
+ ;; don't care about avoiding outside connections, the remote server variant
is
+ ;; usually easier to run, and tests the same things..
+ (let ((proc (start-process
+ "websocket-testserver" "*websocket-testserver*"
+ "python3" "testserver.py" "--log_to_stderr" "--logging=debug")))
+ (when proc
+ (sleep-for 1)
+ (websocket-functional-client-test "ws://127.0.0.1:9999"))))
+
+(ert-deftest websocket-client-with-remote-server ()
+ ;; Emacs previous to Emacs 24 cannot handle wss.
+ (if (>= (string-to-number (substring emacs-version 0 2)) 24)
+ (websocket-functional-client-test "wss://echo.websocket.org")
+ (websocket-functional-client-test "ws://echo.websocket.org")))
+
+(ert-deftest websocket-server ()
+ (let* ((wstest-closed)
+ (wstest-msg)
+ (server-conn (websocket-server
+ 9998
+ :host 'local
+ :on-message (lambda (ws frame)
+ (websocket-send-text
+ ws (websocket-frame-text frame)))
+ :on-close (lambda (_websocket)
+ (setq wstest-closed t))))
+ (wstest-ws (websocket-open
+ "ws://localhost:9998"
+ :on-message (lambda (_websocket frame)
+ (setq wstest-msg (websocket-frame-text
frame))))))
+ (should (websocket-test-wait-with-timeout 1 (websocket-openp wstest-ws)))
+ (websocket-send-text wstest-ws "你好")
+ (should (websocket-test-wait-with-timeout 1 (equal wstest-msg "你好")))
+ (websocket-server-close server-conn)
+ (should (websocket-test-wait-with-timeout 1 wstest-closed))))
+
+(provide 'websocket-functional-test)
+;;; websocket-functional-test.el ends here
diff --git a/websocket-test.el b/websocket-test.el
index 5de21d3..c133272 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -7,7 +7,7 @@
;;
;; This program is free software; you can redistribute it and/or
;; modify it under the terms of the GNU General Public License as
-;; published by the Free Software Foundation; either version 3 of the
+;; published by the Free Software Foundation; either version 2 of the
;; License, or (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful, but
@@ -111,32 +111,41 @@
(ert-deftest websocket-verify-response-code ()
(should (websocket-verify-response-code "HTTP/1.1 101"))
(should
- (eq 400 (cdr (should-error (websocket-verify-response-code "HTTP/1.1 400")
- :type 'websocket-received-error-http-response))))
+ (equal '(400) (cdr (should-error (websocket-verify-response-code "HTTP/1.1
400")
+ :type
'websocket-received-error-http-response))))
(should
- (eq 200 (cdr (should-error (websocket-verify-response-code "HTTP/1.1
200"))))))
+ (equal '(200) (cdr (should-error (websocket-verify-response-code "HTTP/1.1
200")))))
+ (should-error (websocket-verify-response-code "HTTP/1.")
+ :type 'websocket-invalid-header))
(ert-deftest websocket-verify-headers ()
(let ((accept "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=")
+ (accept-alt-case "Sec-Websocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=")
(invalid-accept "Sec-WebSocket-Accept: bad")
(upgrade "Upgrade: websocket")
+ (upgrade-alt-case "Upgrade: Websocket")
(connection "Connection: upgrade")
(ws (websocket-inner-create
:conn "fake-conn" :url "ws://foo/bar"
:accept-string "s3pPLMBiTxaQ9kYGzzhZRbK+xOo="))
(ws-with-protocol
(websocket-inner-create
- :conn "fake-conn" :url "ws://foo/bar"
- :accept-string "s3pPLMBiTxaQ9kYGzzhZRbK+xOo="
- :protocols '("myprotocol")))
+ :conn "fake-conn" :url "ws://foo/bar"
+ :accept-string "s3pPLMBiTxaQ9kYGzzhZRbK+xOo="
+ :protocols '("myprotocol")))
(ws-with-extensions
(websocket-inner-create
- :conn "fake-conn" :url "ws://foo/bar"
- :accept-string "s3pPLMBiTxaQ9kYGzzhZRbK+xOo="
- :extensions '("ext1" "ext2"))))
+ :conn "fake-conn" :url "ws://foo/bar"
+ :accept-string "s3pPLMBiTxaQ9kYGzzhZRbK+xOo="
+ :extensions '("ext1" "ext2"))))
(should (websocket-verify-headers
ws
(websocket-test-header-with-lines accept upgrade connection)))
+ ;; Force case sensitivity to make sure we aren't too case sensitive.
+ (let ((case-fold-search nil))
+ (should (websocket-verify-headers
+ ws
+ (websocket-test-header-with-lines accept-alt-case
upgrade-alt-case connection))))
(should-error
(websocket-verify-headers
ws
@@ -192,28 +201,86 @@
(should (equal '("ext1" "ext2; a=1")
(websocket-negotiated-extensions ws-with-extensions)))))
+(ert-deftest websocket-mask-is-unibyte ()
+ (should-not (multibyte-string-p (websocket-mask "\344\275\240\345\245\275"
"abcdef"))))
+
+(ert-deftest websocket-frame-correctly-encoded ()
+ ;; This example comes from
https://github.com/ahyatt/emacs-websocket/issues/58.
+ (cl-letf ((text
"{\"parent_header\":{},\"header\":{\"msg_id\":\"a2940bc8-619e-4872-97bd-4c8d6fb93017\",\"msg_type\":\"history_request\",\"version\":\"5.3\",\"username\":\"n\",\"session\":\"409cf442-74ba-462f-8183-6652503005af\",\"date\":\"2019-06-20T02:17:43.925049-0500\"},\"content\":{\"output\":false,\"raw\":false,\"hist_access_type\":\"tail\",\"n\":100},\"metadata\":{},\"buffers\":[],\"channel\":\"shell\"}")
+ ((symbol-function #'websocket-genbytes)
+ (lambda (&rest _) "\10\206\356\224")))
+ (let ((frame (websocket-read-frame
+ (websocket-encode-frame
+ (make-websocket-frame :opcode 'text
+ :payload (encode-coding-string text
'raw-text)
+ :completep t)
+ t))))
+ (should frame)
+ (should (equal (websocket-frame-payload frame) text)))))
+
(ert-deftest websocket-create-headers ()
- (let ((system-name "mysystem")
- (base-headers (concat "Host: www.example.com\r\n"
+ (let ((base-headers (concat "Host: www.example.com\r\n"
"Upgrade: websocket\r\n"
"Connection: Upgrade\r\n"
"Sec-WebSocket-Key: key\r\n"
- "Origin: mysystem\r\n"
"Sec-WebSocket-Version: 13\r\n")))
- (should (equal (concat base-headers "\r\n")
- (websocket-create-headers "ws://www.example.com/path"
- "key" nil nil)))
- (should (equal (concat base-headers
- "Sec-WebSocket-Protocol: protocol\r\n\r\n")
- (websocket-create-headers "ws://www.example.com/path"
- "key" '("protocol") nil)))
- (should (equal
- (concat base-headers
- "Sec-WebSocket-Extensions: ext1; a; b=2, ext2\r\n\r\n")
- (websocket-create-headers "ws://www.example.com/path"
- "key" nil
- '(("ext1" . ("a" "b=2"))
- ("ext2")))))))
+ (cl-letf (((symbol-function 'url-cookie-generate-header-lines)
+ (lambda (host localpart secure) "")))
+ (should (equal (concat base-headers "\r\n")
+ (websocket-create-headers "ws://www.example.com/path"
+ "key" nil nil nil)))
+ (should (equal (concat base-headers
+ "Sec-WebSocket-Protocol: protocol\r\n\r\n")
+ (websocket-create-headers "ws://www.example.com/path"
+ "key" '("protocol") nil nil)))
+ (should (equal
+ (concat base-headers
+ "Sec-WebSocket-Extensions: ext1; a; b=2, ext2\r\n\r\n")
+ (websocket-create-headers "ws://www.example.com/path"
+ "key" nil
+ '(("ext1" . ("a" "b=2"))
+ ("ext2")) nil)))
+ (should (equal
+ (concat base-headers "Foo: bar\r\nBaz: boo\r\n\r\n")
+ (websocket-create-headers "ws://www.example.com/path"
+ "key" nil nil '(("Foo" . "bar")
("Baz" . "boo"))))))
+ (cl-letf (((symbol-function 'url-cookie-generate-header-lines)
+ (lambda (host localpart secure)
+ (should (equal host "www.example.com:123"))
+ (should (equal localpart "/path"))
+ (should secure)
+ "Cookie: foo=bar\r\n")))
+ (should (equal (websocket-create-headers "wss://www.example.com:123/path"
+ "key" nil nil nil)
+ (concat
+ "Host: www.example.com:123\r\n"
+ "Upgrade: websocket\r\n"
+ "Connection: Upgrade\r\n"
+ "Sec-WebSocket-Key: key\r\n"
+ "Sec-WebSocket-Version: 13\r\n"
+ "Cookie: foo=bar\r\n\r\n"))))
+ (should
+ (string-match
+ "Host: www.example.com:123\r\n"
+ (websocket-create-headers "ws://www.example.com:123/path" "key" nil nil
nil)))))
+
+(ert-deftest websocket-process-headers ()
+ (cl-flet ((url-cookie-handle-set-cookie
+ (text)
+ (should (equal text "foo=bar;"))
+ ;; test that we have set the implicit buffer variable needed
+ ;; by url-cookie-handle-set-cookie
+ (should (equal url-current-object
+ (url-generic-parse-url "ws://example.com/path")))))
+ (websocket-process-headers "ws://example.com/path"
+ (concat
+ "HTTP/1.1 101 Switching Protocols\r\n"
+ "Upgrade: websocket\r\n"
+ "Connection: Upgrade\r\n"
+ "Set-Cookie: foo=bar;\r\n\r\n")))
+ (cl-flet ((url-cookie-handle-set-cookie (text) (should nil)))
+ (websocket-process-headers "ws://example.com/path"
+ "HTTP/1.1 101 Switching Protocols\r\n")))
(ert-deftest websocket-process-frame ()
(let* ((sent)
@@ -236,14 +303,17 @@
(make-websocket-frame :opcode opcode :payload "hello")))
processed))))
(setq sent nil)
- (flet ((websocket-send (websocket content) (setq sent content)))
+ (cl-letf (((symbol-function 'websocket-send)
+ (lambda (websocket content) (setq sent content))))
(should (equal
- (make-websocket-frame :opcode 'pong :completep t)
+ (make-websocket-frame :opcode 'pong :payload "data" :completep
t)
(progn
(funcall (websocket-process-frame websocket
- (make-websocket-frame :opcode
'ping)))
+ (make-websocket-frame
:opcode 'ping
+
:payload "data")))
sent))))
- (flet ((delete-process (conn) (setq deleted t)))
+ (cl-letf (((symbol-function 'delete-process)
+ (lambda (conn) (setq deleted t))))
(should (progn
(funcall
(websocket-process-frame websocket
@@ -271,7 +341,11 @@
(should (equal 30 (websocket-get-bytes (websocket-to-bytes 30 1) 1)))
(should (equal 300 (websocket-get-bytes (websocket-to-bytes 300 2) 2)))
(should (equal 70000 (websocket-get-bytes (websocket-to-bytes 70000 8) 8)))
- (should-error (websocket-to-bytes 536870912 8) :type
'websocket-frame-too-large)
+ ;; Only run if the number we're testing with is not more than the system can
+ ;; handle.
+ (if (equal "1" (calc-eval (format "536870912 < %d" most-positive-fixnum)))
+ (should-error (websocket-to-bytes 536870912 8)
+ :type 'websocket-frame-too-large))
(should-error (websocket-to-bytes 30 3))
(should-error (websocket-to-bytes 300 1))
;; I'd like to test the error for 32-byte systems on 8-byte lengths,
@@ -287,15 +361,16 @@
(websocket-encode-frame
(make-websocket-frame :opcode 'text :payload "Hello" :completep
t) nil)))
(dolist (len '(200 70000))
- (let ((long-string (make-string len ?x)))
- (should (equal long-string
- (websocket-frame-payload
- (websocket-read-frame
- (websocket-encode-frame
- (make-websocket-frame :opcode 'text
- :payload long-string)
t)))))))
- (flet ((websocket-genbytes (n) (substring websocket-test-masked-hello 2 6)))
- (should (equal websocket-test-masked-hello
+ (let ((long-string (make-string len ?x)))
+ (should (equal long-string
+ (websocket-frame-payload
+ (websocket-read-frame
+ (websocket-encode-frame
+ (make-websocket-frame :opcode 'text
+ :payload long-string) t)))))))
+ (cl-letf (((symbol-function 'websocket-genbytes)
+ (lambda (n) (substring websocket-test-masked-hello 2 6))))
+ (should (equal websocket-test-masked-hello
(websocket-encode-frame
(make-websocket-frame :opcode 'text :payload "Hello"
:completep t) t))))
@@ -305,22 +380,53 @@
(websocket-encode-frame (make-websocket-frame :opcode 'text
:payload "Hello"
:completep nil) t))))
- (dolist (opcode '(close ping pong))
- (should (equal
- opcode
- (websocket-frame-opcode
- (websocket-read-frame
- (websocket-encode-frame (make-websocket-frame :opcode opcode
- :completep t)
t)))))))
+ (should (equal 'close (websocket-frame-opcode
+ (websocket-read-frame
+ (websocket-encode-frame
+ (make-websocket-frame :opcode 'close :completep t)
t)))))
+ (dolist (opcode '(ping pong))
+ (let ((read-frame (websocket-read-frame
+ (websocket-encode-frame
+ (make-websocket-frame :opcode opcode
+ :payload "data"
+ :completep t) t))))
+ (should read-frame)
+ (should (equal
+ opcode
+ (websocket-frame-opcode read-frame)))
+ (should (equal
+ "data" (websocket-frame-payload read-frame)))))
+ ;; A frame should be four bytes, even for no-data pings.
+ (should (equal 2 (websocket-frame-length
+ (websocket-read-frame
+ (websocket-encode-frame
+ (make-websocket-frame :opcode 'ping :completep t) t))))))
+
+(ert-deftest websocket-check ()
+ (should (websocket-check (make-websocket-frame :opcode 'close :completep t)))
+ (should-not
+ (websocket-check (make-websocket-frame :opcode 'close :completep nil)))
+ (should-not
+ (websocket-check (make-websocket-frame :opcode 'close :completep t :payload
"")))
+ (should (websocket-check (make-websocket-frame :opcode 'text :completep nil
+ :payload "incompl")))
+ (should (websocket-check (make-websocket-frame :opcode 'ping :completep t)))
+ (should (websocket-check (make-websocket-frame :opcode 'ping :completep t
+ :payload "")))
+ (should (websocket-check (make-websocket-frame :opcode 'pong :completep t
+ :payload "")))
+ (should-not (websocket-check (make-websocket-frame :opcode 'text))))
(ert-deftest websocket-close ()
(let ((sent-frames)
(processes-deleted))
- (flet ((websocket-send (websocket frame) (push frame sent-frames))
- (websocket-openp (websocket) t)
- (kill-buffer (buffer))
- (delete-process (proc))
- (process-buffer (conn) (add-to-list 'processes-deleted conn)))
+ (cl-letf (((symbol-function 'websocket-send)
+ (lambda (websocket frame) (push frame sent-frames)))
+ ((symbol-function 'websocket-openp)
+ (lambda (websocket) t))
+ ((symbol-function 'kill-buffer) (lambda (buffer) t))
+ ((symbol-function 'delete-process)
+ (lambda (proc) (add-to-list 'processes-deleted proc))))
(websocket-close (websocket-inner-create
:conn "fake-conn"
:url t
@@ -350,12 +456,14 @@
(concat
(websocket-encode-frame frame1 t)
(websocket-encode-frame frame2 t))))
- (flet ((websocket-process-frame
- (websocket frame)
- (lexical-let ((frame frame))
- (lambda () (push frame processed-frames))))
- (websocket-verify-response-code (output) t)
- (websocket-verify-headers (websocket output) t))
+ (cl-letf (((symbol-function 'websocket-process-frame)
+ (lambda (websocket frame)
+ (lexical-let ((frame frame))
+ (lambda () (push frame processed-frames)))))
+ ((symbol-function 'websocket-verify-headers)
+ (lambda (websocket output) t))
+ ((symbol-function 'websocket-close) (lambda (websocket) t)))
+ (websocket-outer-filter fake-ws "HTTP/1.1 101 Switching Protocols\r\n")
(websocket-outer-filter fake-ws "Sec-")
(should (eq (websocket-ready-state fake-ws) 'connecting))
(should-not open-callback-called)
@@ -368,11 +476,17 @@
(websocket-outer-filter fake-ws (substring websocket-frames 2))
(should (equal (list frame2 frame1) processed-frames))
(should-not (websocket-inflight-input fake-ws)))
- (flet ((websocket-close (websocket)))
- (setf (websocket-ready-state fake-ws) 'connecting)
- (should (eq 500 (cdr (should-error
- (websocket-outer-filter fake-ws "HTTP/1.1
500\r\n\r\n")
- :type
'websocket-received-error-http-response)))))))
+ (cl-letf (((symbol-function 'websocket-close) (lambda (websocket) t)))
+ (let ((on-error-called))
+ (setf (websocket-ready-state fake-ws) 'connecting)
+ (setf (websocket-on-open fake-ws) (lambda (ws &rest _) t))
+ (setf (websocket-on-error fake-ws)
+ (lambda (_ type err)
+ (should (eq type 'on-open))
+ (should (equal '(websocket-received-error-http-response 500)
err))
+ (setq on-error-called t)))
+ (websocket-outer-filter fake-ws "HTTP/1.1 500\r\n\r\n")
+ (should on-error-called)))))
(ert-deftest websocket-outer-filter-bad-connection ()
(let* ((on-open-calledp)
@@ -381,9 +495,12 @@
:conn t :url t :accept-string t
:on-open (lambda (websocket)
(setq on-open-calledp t)))))
- (flet ((websocket-verify-response-code (output) t)
- (websocket-verify-headers (websocket output) (error "Bad headers!"))
- (websocket-close (websocket) (setq websocket-closed-calledp t)))
+ (cl-letf (((symbol-function 'websocket-verify-response-code)
+ (lambda (output) t))
+ ((symbol-function 'websocket-verify-headers)
+ (lambda (websocket output) (error "Bad headers!")))
+ ((symbol-function 'websocket-close)
+ (lambda (websocket) (setq websocket-closed-calledp t))))
(condition-case err
(progn (websocket-outer-filter fake-ws "HTTP/1.1 101\r\n\r\n")
(error "Should have thrown an error!"))
@@ -391,18 +508,34 @@
(should-not on-open-calledp)
(should websocket-closed-calledp))))))
+(ert-deftest websocket-outer-filter-fragmented-header ()
+ (let* ((on-open-calledp)
+ (websocket-closed-calledp)
+ (fake-ws (websocket-inner-create
+ :protocols '("websocket")
+ :conn t :url t :accept-string "17hG/VoPPd14L9xPSI7LtEr7PQc="
+ :on-open (lambda (websocket)
+ (setq on-open-calledp t)))))
+ (cl-letf (((symbol-function 'websocket-close) (lambda (websocket) t)))
+ (websocket-outer-filter fake-ws "HTTP/1.1 101 Web Socket Protocol
Handsh")
+ (websocket-outer-filter fake-ws "ake\r\nConnection: Upgrade\r\n")
+ (websocket-outer-filter fake-ws "Upgrade: websocket\r\n")
+ (websocket-outer-filter fake-ws "Sec-websocket-Protocol: websocket\r\n")
+ (websocket-outer-filter fake-ws "Sec-WebSocket-Accept:
17hG/VoPPd14L9xPSI7LtEr7PQc=\r\n\r\n"))))
+
(ert-deftest websocket-send-text ()
- (flet ((websocket-send (ws frame)
- (should (equal
- (websocket-frame-payload frame)
- "\344\275\240\345\245\275"))))
+ (cl-letf (((symbol-function 'websocket-send)
+ (lambda (ws frame)
+ (should (equal
+ (websocket-frame-payload frame)
+ "\344\275\240\345\245\275")))))
(websocket-send-text nil "你好")))
(ert-deftest websocket-send ()
(let ((ws (websocket-inner-create :conn t :url t :accept-string t)))
- (flet ((websocket-ensure-connected (websocket))
- (websocket-openp (websocket) t)
- (process-send-string (conn string)))
+ (cl-letf (((symbol-function 'websocket-ensure-connected) (lambda
(websocket) t))
+ ((symbol-function 'websocket-openp) (lambda (websocket) t))
+ ((symbol-function 'process-send-string) (lambda (conn string)
t)))
;; Just make sure there is no error.
(websocket-send ws (make-websocket-frame :opcode 'ping
:completep t)))
@@ -423,7 +556,6 @@
(upgrade "Upgrade: websocket")
(key (format "Sec-Websocket-Key: %s" "key"))
(version "Sec-Websocket-Version: 13")
- (origin "Origin: origin")
(protocol "Sec-Websocket-Protocol: protocol")
(extensions1 "Sec-Websocket-Extensions: foo")
(extensions2 "Sec-Websocket-Extensions: bar; baz=2")
@@ -485,11 +617,12 @@
(closed)
(response)
(processed))
- (flet ((process-send-string (p text) (setq response text))
- (websocket-close (ws) (setq closed t))
- (process-get (process sym) ws))
+ (cl-letf (((symbol-function 'process-send-string) (lambda (p text) (setq
response text)))
+ ((symbol-function 'websocket-close) (lambda (ws) (setq closed
t)))
+ ((symbol-function 'process-get) (lambda (process sym) ws)))
;; Bad request, in two parts
- (flet ((websocket-verify-client-headers (text) nil))
+ (cl-letf (((symbol-function 'websocket-verify-client-headers)
+ (lambda (text) nil)))
(websocket-server-filter nil "HTTP/1.0 GET /foo \r\n")
(should-not closed)
(websocket-server-filter nil "\r\n")
@@ -499,13 +632,16 @@
(setq closed nil
response nil)
(setf (websocket-inflight-input ws) nil)
- (flet ((websocket-verify-client-headers (text) t)
- (websocket-get-server-response (ws protocols extensions)
- "response")
- (websocket-process-input-on-open-ws (ws text)
- (setq processed t)
- (should
- (equal text
websocket-test-hello))))
+ (cl-letf (((symbol-function 'websocket-verify-client-headers)
+ (lambda (text) t))
+ ((symbol-function 'websocket-get-server-response)
+ (lambda (ws protocols extensions)
+ "response"))
+ ((symbol-function 'websocket-process-input-on-open-ws)
+ (lambda (ws text)
+ (setq processed t)
+ (should
+ (equal text websocket-test-hello)))))
(websocket-server-filter nil
(concat "\r\n\r\n" websocket-test-hello))
(should (equal (websocket-ready-state ws) 'open))
@@ -529,7 +665,6 @@
"Upgrade: websocket\r\n"
"Connection: Upgrade\r\n"
"Sec-WebSocket-Key:
dGhlIHNhbXBsZSBub25jZQ==\r\n"
- "Origin: http://example.com\r\n"
"Sec-WebSocket-Protocol: chat,
superchat\r\n"
"Sec-WebSocket-Version: 13\r\n"))))
(should header-info)
@@ -556,14 +691,16 @@
:ready-state 'closed)))
(deleted-processes)
(closed-websockets))
- (flet ((delete-process (conn) (add-to-list 'deleted-processes conn))
- (websocket-close (ws)
- ;; we always remove on closing in the
- ;; actual code.
- (setq websocket-server-websockets
- (remove ws websocket-server-websockets))
- (should-not (eq (websocket-ready-state ws)
'closed))
- (add-to-list 'closed-websockets ws)))
+ (cl-letf (((symbol-function 'delete-process)
+ (lambda (conn) (add-to-list 'deleted-processes conn)))
+ ((symbol-function 'websocket-close)
+ (lambda (ws)
+ ;; we always remove on closing in the
+ ;; actual code.
+ (setq websocket-server-websockets
+ (remove ws websocket-server-websockets))
+ (should-not (eq (websocket-ready-state ws) 'closed))
+ (add-to-list 'closed-websockets ws))))
(websocket-server-close 'b))
(should (equal deleted-processes '(b)))
(should (eq 1 (length closed-websockets)))
@@ -572,16 +709,16 @@
(should (eq 'conn-a (websocket-conn (car websocket-server-websockets))))))
(ert-deftest websocket-default-error-handler ()
- (flet ((try-error
- (callback-type err expected-message)
- (flet ((display-warning
- (type message &optional level buffer-name)
- (should (eq type 'websocket))
- (should (eq level :error))
- (should (string= message expected-message))))
- (websocket-default-error-handler nil
- callback-type
- err))))
+ (cl-letf (((symbol-function 'try-error)
+ (lambda (callback-type err expected-message)
+ (cl-flet ((display-warning
+ (type message &optional level buffer-name)
+ (should (eq type 'websocket))
+ (should (eq level :error))
+ (should (string= message expected-message))))
+ (websocket-default-error-handler nil
+ callback-type
+ err)))))
(try-error
'on-message
'(end-of-buffer)
diff --git a/websocket.el b/websocket.el
index 1d69508..3424852 100644
--- a/websocket.el
+++ b/websocket.el
@@ -3,8 +3,9 @@
;; Copyright (c) 2013, 2016-2017 Free Software Foundation, Inc.
;; Author: Andrew Hyatt <ahyatt@gmail.com>
+;; Homepage: https://github.com/ahyatt/emacs-websocket
;; Keywords: Communication, Websocket, Server
-;; Version: 1.12
+;; Version: 1.13
;; Package-Requires: ((cl-lib "0.5"))
;;
;; This program is free software; you can redistribute it and/or
@@ -556,7 +557,6 @@ the `websocket-error' condition."
(websocket-debug websocket "Sending frame, opcode: %s payload: %s"
(websocket-frame-opcode frame)
(websocket-frame-payload frame))
- (websocket-ensure-connected websocket)
(unless (websocket-openp websocket)
(signal 'websocket-closed (list frame)))
(process-send-string (websocket-conn websocket)
@@ -580,21 +580,6 @@ the `websocket-error' condition."
(setf (websocket-ready-state websocket) 'closed))
(delete-process (websocket-conn websocket)))
-(defun websocket-ensure-connected (websocket)
- "If the WEBSOCKET connection is closed, open it."
- (unless (and (websocket-conn websocket)
- (cl-ecase (process-status (websocket-conn websocket))
- ((run open listen) t)
- ((stop exit signal closed connect failed nil) nil)))
- (websocket-close websocket)
- (websocket-open (websocket-url websocket)
- :protocols (websocket-protocols websocket)
- :extensions (websocket-extensions websocket)
- :on-open (websocket-on-open websocket)
- :on-message (websocket-on-message websocket)
- :on-close (websocket-on-close websocket)
- :on-error (websocket-on-error websocket))))
-
;;;;;;;;;;;;;;;;;;;;;;
;; Websocket client ;;
;;;;;;;;;;;;;;;;;;;;;;
@@ -722,7 +707,7 @@ to the websocket protocol.
conn
(websocket-sentinel url conn key protocols extensions custom-header-alist
nowait))
(set-process-query-on-exit-flag conn nil)
- (websocket-ensure-handshake url conn key protocols extensions
custom-header-alist)
+ (websocket-ensure-handshake url conn key protocols extensions
custom-header-alist nowait)
websocket))
(defun websocket-sentinel (url conn key protocols extensions
custom-header-alist nowait)
@@ -731,26 +716,26 @@ to the websocket protocol.
(websocket-debug websocket "State change to %s" change)
(let ((status (process-status process)))
(when (and nowait (eq status 'open))
- (websocket-ensure-handshake url conn key protocols extensions
custom-header-alist))
+ (websocket-ensure-handshake url conn key protocols extensions
custom-header-alist nowait))
(when (and (member status '(closed failed exit signal))
(not (eq 'closed (websocket-ready-state websocket))))
(websocket-try-callback 'websocket-on-close 'on-close
websocket))))))
-(defun websocket-ensure-handshake (url conn key protocols extensions
custom-header-alist)
+(defun websocket-ensure-handshake (url conn key protocols extensions
custom-header-alist nowait)
(let ((url-struct (url-generic-parse-url url))
(websocket (process-get conn :websocket)))
(when (and (eq 'connecting (websocket-ready-state websocket))
- (eq 'open (process-status conn)))
- (process-send-string conn
- (format "GET %s HTTP/1.1\r\n"
- (let ((path (url-filename url-struct)))
- (if (> (length path) 0) path "/"))))
+ (memq (process-status conn)
+ (list 'run (if nowait 'connect 'open))))
(websocket-debug websocket "Sending handshake, key: %s, acceptance: %s"
key (websocket-accept-string websocket))
(process-send-string conn
- (websocket-create-headers
- url key protocols extensions
custom-header-alist)))))
+ (format "GET %s HTTP/1.1\r\n%s"
+ (let ((path (url-filename url-struct)))
+ (if (> (length path) 0) path "/"))
+ (websocket-create-headers
+ url key protocols extensions
custom-header-alist))))))
(defun websocket-process-headers (url headers)
"On opening URL, process the HEADERS sent from the server."
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [elpa] externals/websocket 413702e: Update websocket library to version 1.13.,
Andrew Hyatt <=