branch: externals/websocket
commit 0bf139ff46b8a01ae071099c9d5c28b44f07d4dd
Author: Andrew Hyatt <[email protected]>
Commit: Andrew Hyatt <[email protected]>

    Fix tests and behavior
    
    With the new bindat code, we don't need to error on certain things that we 
can
    now handle.
    
    The code itself had a few issues - one where we were losing the header 
match,
    and the other where the code didn't multiply the length of the bindat uint 
by 8.
    
    Also added a few more checks.
---
 websocket-test.el | 27 +++++++++++++++++----------
 websocket.el      | 35 +++++++++++++++++++++++++++--------
 2 files changed, 44 insertions(+), 18 deletions(-)

diff --git a/websocket-test.el b/websocket-test.el
index 2e71e9093d..d9d6976180 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -49,7 +49,10 @@
   (should (equal #x101 (websocket-get-bytes "\x1\x1" 2)))
   (should (equal #xffffff
                  (websocket-get-bytes "\x0\x0\x0\x0\x0\xFF\xFF\xFF" 8)))
-  (should-error (websocket-get-bytes "\x0\x0\x0\x1\x0\x0\x0\x1" 8)
+  (unless (fboundp 'bindat-type)
+    (should-error (websocket-get-bytes "\x0\x0\x0\x1\x0\x0\x0\x1" 8)
+                  :type 'websocket-unparseable-frame))
+  (should-error (websocket-get-bytes "\x80\x0\x0\x0\x0\x0\x0\x0" 8)
                 :type 'websocket-unparseable-frame)
   (should-error (websocket-get-bytes "\x0\x0\x0" 3))
   (should-error (websocket-get-bytes "\x0" 2) :type 
'websocket-unparseable-frame))
@@ -266,20 +269,21 @@
       (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")))))
+  (cl-letf (((symbol-function 'url-cookie-handle-set-cookie)
+             (lambda (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)))
+  (cl-letf (((symbol-function 'url-cookie-handle-set-cookie)
+             (lambda (_text) (should nil))))
     (websocket-process-headers "ws://example.com/path"
                                "HTTP/1.1 101 Switching Protocols\r\n")))
 
@@ -344,9 +348,12 @@
   (should (equal 70000 (websocket-get-bytes (websocket-to-bytes 70000 8) 8)))
   ;; 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)))
+  (if (and (not (fboundp 'bindat-type))
+           (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 (expt 2 63) 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,
diff --git a/websocket.el b/websocket.el
index a601ab569c..5f2b745d60 100644
--- a/websocket.el
+++ b/websocket.el
@@ -200,8 +200,17 @@ power of 2, up to 8.
 
 In Emacs<28, we support getting frames only up to 536870911 bytes (2^29 - 1),
 approximately 537M long."
+  (unless (memq n '(1 2 4 8))
+    (error "websocket-get-bytes: Unknown N: %S" n))
   (websocket--if-when-compile (fboundp 'bindat-type) ;Emacs≄28
-      (bindat-unpack (bindat-type uint (* 8 n)) s)
+      (condition-case nil
+          (let ((val (bindat-unpack (bindat-type uint (* 8 n)) s)))
+            (if (and (= n 8) (> (ash val -63) 0))
+                (signal 'websocket-unparseable-frame
+                        (list "Frame value found too large to parse!"))
+              val))
+        (args-out-of-range (signal 'websocket-unparseable-frame
+                                   (list "Frame ended before all bytes were 
read!"))))
     (if (= n 8)
         (let* ((32-bit-parts
                 (bindat-get-field (bindat-unpack '((:val vec 2 u32)) s) :val))
@@ -236,13 +245,18 @@ NBYTES much be a power of 2, up to 8.
 
 In Emacs<28, this supports encoding values only up to 536870911 bytes
 \(2^29 - 1), approximately 537M long."
+  (unless (memq nbytes '(1 2 4 8))
+    (error "websocket-to-bytes: Unknown NBYTES: %S" nbytes))
   (unless (= 0 (ash val (- (* 8 nbytes))))
     ;; not a user-facing error, this must be caused from an error in
     ;; this library
     (error "websocket-to-bytes: Value %d could not be expressed in %d bytes"
            val nbytes))
   (websocket--if-when-compile (fboundp 'bindat-type)
-      (bindat-pack (bindat-type uint (* 8 nbytes)) val)
+      (progn
+        (if (and (= nbytes 8) (> (ash val -63) 0))
+            (signal 'websocket-frame-too-large (list val)))
+        (bindat-pack (bindat-type uint (* 8 nbytes)) val))
     (if (= nbytes 8)
         (progn
           (let* ((hi-32bits (ash val -32))
@@ -284,8 +298,12 @@ many bytes were consumed from the string."
          (len2len unit (pcase len1 (127 8) (126 2) (_ 0)))
          (len2 uint (progn
                       (websocket-ensure-length s (1+ len2len))
-                      len2len))
-         :unpack-val (cons (if (zerop len2) len1 len2) (1+ len2len)))
+                      (* 8 len2len)))
+         :unpack-val (cons (if (< len1 126) len1
+                             (if (and (= len2len 8) (> (ash len2 -63) 0))
+                                 (signal 'websocket-unparseable-frame (list 
"MSB must be 0 for 64-bit length"))
+                               len2))
+                           (1+ len2len)))
        s)
     (let* ((initial-val (logand 127 (aref s 0))))
       (cond ((= initial-val 127)
@@ -766,10 +784,11 @@ to the websocket protocol.
 (defun websocket-process-headers (url headers)
   "On opening URL, process the HEADERS sent from the server."
   (when (string-match "Set-Cookie: \\(.*\\)\r\n" headers)
-    ;; The url-current-object is assumed to be set by
-    ;; url-cookie-handle-set-cookie.
-    (let ((url-current-object (url-generic-parse-url url)))
-      (url-cookie-handle-set-cookie (match-string 1 headers)))))
+    (let ((cookie (match-string 1 headers))
+          ;; The url-current-object is assumed to be set by
+          ;; url-cookie-handle-set-cookie.
+          (url-current-object (url-generic-parse-url url)))
+      (url-cookie-handle-set-cookie cookie))))
 
 (defun websocket-outer-filter (websocket output)
   "Filter the WEBSOCKET server's OUTPUT.

Reply via email to