[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] externals/websocket bc57ded 15/16: Upgrade websocket library to v
From: |
Stefan Monnier |
Subject: |
[elpa] externals/websocket bc57ded 15/16: Upgrade websocket library to version 1.11.1. |
Date: |
Fri, 27 Nov 2020 17:47:20 -0500 (EST) |
branch: externals/websocket
commit bc57ded9b33cc57e266e3905a4edd7cce3b766a6
Author: Andrew Hyatt <ahyatt@gmail.com>
Commit: Stefan Monnier <monnier@iro.umontreal.ca>
Upgrade websocket library to version 1.11.1.
The major changes here are:
- Significant performance improvements for large transfers.
- Allow calling code to handle connection issues.
- Fixed signals to be in the correct format.
- Fixed handshake issues (by https://github.com/yuya373, who has signed
FSF papers)
Specifically:
* packages/websocket/websocket.el (websocket-version): -> 1.11.1
(websocket-get-bytes, websocket-to-bytes,
websocket-verify-response-code,
websocket-parse-repeated-field, websocket-send, websocket-open,
websocket-verify-headers): fix signal
(websocket-get-opcode, websocket-get-payload-len,
websocket-read-frame): use `aref' for speed
(websocket-mask): rewrite for speed
(websocket-open): use `websocket-sentinel' for process changes, add
`websocket-ensure-handshake'
(websocket-sentinel): new function created from code that was in
`websocket-open'.
(websocket-ensure-handshake): new function to send a handshake.
(websocket-outer-filter): allowed user processing of connection errors.
---
websocket.el | 162 +++++++++++++++++++++++++++++++----------------------------
1 file changed, 86 insertions(+), 76 deletions(-)
diff --git a/websocket.el b/websocket.el
index 4c8b040..68e847c 100644
--- a/websocket.el
+++ b/websocket.el
@@ -4,7 +4,7 @@
;; Author: Andrew Hyatt <ahyatt@gmail.com>
;; Keywords: Communication, Websocket, Server
-;; Version: 1.9
+;; Version: 1.11.1
;; Package-Requires: ((cl-lib "0.5"))
;;
;; This program is free software; you can redistribute it and/or
@@ -46,6 +46,7 @@
(require 'bindat)
(require 'url-parse)
(require 'url-cookie)
+(require 'seq)
(eval-when-compile (require 'cl-lib))
;;; Code:
@@ -99,7 +100,7 @@ same for the protocols."
accept-string
(inflight-input nil))
-(defvar websocket-version "1.9"
+(defvar websocket-version "1.11.1"
"Version numbers of this version of websocket.el.")
(defvar websocket-debug nil
@@ -194,15 +195,15 @@ power of 2, up to 8.
We support getting frames up to 536870911 bytes (2^29 - 1),
approximately 537M long."
(if (= n 8)
- (let* ((32-bit-parts
- (bindat-get-field (bindat-unpack '((:val vec 2 u32)) s) :val))
- (cval
- (logior (lsh (aref 32-bit-parts 0) 32) (aref 32-bit-parts 1))))
- (if (and (= (aref 32-bit-parts 0) 0)
- (= (lsh (aref 32-bit-parts 1) -29) 0))
- cval
- (signal 'websocket-unparseable-frame
- "Frame value found too large to parse!")))
+ (let* ((32-bit-parts
+ (bindat-get-field (bindat-unpack '((:val vec 2 u32)) s) :val))
+ (cval
+ (logior (lsh (aref 32-bit-parts 0) 32) (aref 32-bit-parts 1))))
+ (if (and (= (aref 32-bit-parts 0) 0)
+ (= (lsh (aref 32-bit-parts 1) -29) 0))
+ cval
+ (signal 'websocket-unparseable-frame
+ (list "Frame value found too large to parse!"))))
;; n is not 8
(bindat-get-field
(condition-case _
@@ -217,7 +218,7 @@ approximately 537M long."
"websocket-get-bytes: Unknown N: %S" n)))))
s)
(args-out-of-range (signal 'websocket-unparseable-frame
- (format "Frame unexpectedly shortly: %s"
s))))
+ (list (format "Frame unexpectedly short: %s"
s)))))
:val)))
(defun websocket-to-bytes (val nbytes)
@@ -235,10 +236,10 @@ approximately 537M long."
(if (= nbytes 8)
(progn
(let* ((hi-32bits (lsh val -32))
- ;; This is just VAL on systems that don't have >= 32 bits.
- (low-32bits (- val (lsh hi-32bits 32))))
+ ;; This is just VAL on systems that don't have >= 32 bits.
+ (low-32bits (- val (lsh hi-32bits 32))))
(when (or (> hi-32bits 0) (> (lsh low-32bits -29) 0))
- (signal 'websocket-frame-too-large val))
+ (signal 'websocket-frame-too-large (list val)))
(bindat-pack `((:val vec 2 u32))
`((:val . [,hi-32bits ,low-32bits])))))
(bindat-pack
@@ -252,7 +253,7 @@ approximately 537M long."
(defun websocket-get-opcode (s)
"Retrieve the opcode from first byte of string S."
(websocket-ensure-length s 1)
- (let ((opcode (logand #xf (websocket-get-bytes s 1))))
+ (let ((opcode (logand #xf (aref s 0))))
(cond ((= opcode 0) 'continuation)
((= opcode 1) 'text)
((= opcode 2) 'binary)
@@ -265,7 +266,7 @@ approximately 537M long."
We start at position 0, and return a cons of the payload length and how
many bytes were consumed from the string."
(websocket-ensure-length s 1)
- (let* ((initial-val (logand 127 (websocket-get-bytes s 1))))
+ (let* ((initial-val (logand 127 (aref s 0))))
(cond ((= initial-val 127)
(websocket-ensure-length s 9)
(cons (websocket-get-bytes (substring s 1) 8) 9))
@@ -284,17 +285,13 @@ many bytes were consumed from the string."
(defun websocket-mask (key data)
"Using string KEY, mask string DATA according to the RFC.
This is used to both mask and unmask data."
- ;; If we don't make the string unibyte here, a string of bytes that should be
- ;; interpreted as a unibyte string will instead be interpreted as a multibyte
- ;; string of the same length (for example, 6 multibyte chars for 你好 instead
- ;; of the correct 6 unibyte chars, which would convert into 2 multibyte
- ;; chars).
- (apply
- #'unibyte-string
- (cl-loop for b across data
- for i from 0 to (length data)
- collect
- (logxor (websocket-get-bytes (substring key (mod i 4)) 1) b))))
+ ;; Returning the string as unibyte is important here. Because we set the
+ ;; string byte by byte, this results in a unibyte string.
+ (cl-loop
+ with result = (make-string (length data) ?x)
+ for i from 0 below (length data)
+ do (setf (seq-elt result i) (logxor (aref key (mod i 4)) (seq-elt data i)))
+ finally return result))
(defun websocket-ensure-length (s n)
"Ensure the string S has at most N bytes.
@@ -351,13 +348,13 @@ the frame finishes. If the frame is not completed,
return NIL."
(catch 'websocket-incomplete-frame
(websocket-ensure-length s 1)
(let* ((opcode (websocket-get-opcode s))
- (fin (logand 128 (websocket-get-bytes s 1)))
+ (fin (logand 128 (aref s 0)))
(payloadp (memq opcode '(continuation text binary ping pong)))
(payload-len (when payloadp
(websocket-get-payload-len (substring s 1))))
(maskp (and
payloadp
- (= 128 (logand 128 (websocket-get-bytes (substring s 1)
1)))))
+ (= 128 (logand 128 (aref s 1)))))
(payload-start (when payloadp (+ (if maskp 5 1) (cdr payload-len))))
(payload-end (when payloadp (+ payload-start (car payload-len))))
(unmasked-payload (when payloadp
@@ -460,10 +457,10 @@ The only acceptable one to websocket is responce code 101.
A t value will be returned on success, and an error thrown
if not."
(unless (string-match "^HTTP/1.1 \\([[:digit:]]+\\)" output)
- (signal 'websocket-invalid-header "Invalid HTTP status line"))
+ (signal 'websocket-invalid-header (list "Invalid HTTP status line")))
(unless (equal "101" (match-string 1 output))
(signal 'websocket-received-error-http-response
- (string-to-number (match-string 1 output))))
+ (list (string-to-number (match-string 1 output)))))
t)
(defun websocket-parse-repeated-field (output field)
@@ -555,13 +552,13 @@ The frame may be too large for this buid of Emacs, in
which case
size of the frame which was too large to process. This also has
the `websocket-error' condition."
(unless (websocket-check frame)
- (signal 'websocket-illegal-frame frame))
+ (signal 'websocket-illegal-frame (list frame)))
(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 frame))
+ (signal 'websocket-closed (list frame)))
(process-send-string (websocket-conn websocket)
;; We mask only when we're a client, following the spec.
(websocket-encode-frame frame (not (websocket-server-p
websocket)))))
@@ -603,9 +600,9 @@ the `websocket-error' condition."
;;;;;;;;;;;;;;;;;;;;;;
(cl-defun websocket-open (url &key protocols extensions (on-open 'identity)
- (on-message (lambda (_w _f))) (on-close 'identity)
- (on-error 'websocket-default-error-handler)
- (nowait nil) (custom-header-alist nil))
+ (on-message (lambda (_w _f))) (on-close
'identity)
+ (on-error 'websocket-default-error-handler)
+ (nowait nil) (custom-header-alist nil))
"Open a websocket connection to URL, returning the `websocket' struct.
The PROTOCOL argument is optional, and setting it will declare to
the server that this client supports the protocols in the list
@@ -696,14 +693,14 @@ to the websocket protocol.
(if (eq type 'tls) 443 80)
(url-port url-struct)))
(host (url-host url-struct)))
- (if (eq type 'plain)
- (make-network-process :name name :buffer nil :host
host
- :service port :nowait nowait)
- (condition-case-unless-debug nil
- (open-network-stream name nil host port :type
type :nowait nowait)
- (wrong-number-of-arguments
- (signal 'websocket-wss-needs-emacs-24 "wss")))))
- (signal 'websocket-unsupported-protocol (url-type
url-struct))))
+ (if (eq type 'plain)
+ (make-network-process :name name :buffer nil :host
host
+ :service port :nowait nowait)
+ (condition-case-unless-debug nil
+ (open-network-stream name nil host port :type type
:nowait nowait)
+ (wrong-number-of-arguments
+ (signal 'websocket-wss-needs-emacs-24 (list
"wss"))))))
+ (signal 'websocket-unsupported-protocol (list (url-type
url-struct)))))
(websocket (websocket-inner-create
:conn conn
:url url
@@ -723,26 +720,38 @@ to the websocket protocol.
(websocket-outer-filter websocket output))))
(set-process-sentinel
conn
- (lambda (process change)
- (let ((websocket (process-get process :websocket)))
- (websocket-debug websocket "State change to %s" change)
- (when (and
- (member (process-status process) '(closed failed exit signal))
- (not (eq 'closed (websocket-ready-state websocket))))
- (websocket-try-callback 'websocket-on-close 'on-close websocket)))))
+ (websocket-sentinel url conn key protocols extensions custom-header-alist
nowait))
(set-process-query-on-exit-flag conn nil)
- (process-send-string conn
- (format "GET %s HTTP/1.1\r\n"
- (let ((path (url-filename url-struct)))
- (if (> (length path) 0) path "/"))))
- (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))
- (websocket-debug websocket "Websocket opened")
+ (websocket-ensure-handshake url conn key protocols extensions
custom-header-alist)
websocket))
+(defun websocket-sentinel (url conn key protocols extensions
custom-header-alist nowait)
+ #'(lambda (process change)
+ (let ((websocket (process-get process :websocket)))
+ (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))
+
+ (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)
+ (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 "/"))))
+ (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)))))
+
(defun websocket-process-headers (url headers)
"On opening URL, process the HEADERS sent from the server."
(when (string-match "Set-Cookie: \(.*\)\r\n" headers)
@@ -774,7 +783,8 @@ connection is invalid, the connection will be closed."
(websocket-process-headers (websocket-url websocket) text))
(error
(websocket-close websocket)
- (signal (car err) (cdr err))))
+ (funcall (websocket-on-error websocket)
+ websocket 'on-open err)))
(setf (websocket-ready-state websocket) 'open)
(websocket-try-callback 'websocket-on-open 'on-open websocket))
(setf (websocket-inflight-input websocket) text)))
@@ -792,16 +802,16 @@ of populating the list of server extensions to WEBSOCKET."
(websocket-debug websocket "Checking for accept header: %s" accept-string)
(unless (string-match (regexp-quote accept-string) output)
(signal 'websocket-invalid-header
- "Incorrect handshake from websocket: is this really a websocket
connection?")))
+ (list "Incorrect handshake from websocket: is this really a
websocket connection?"))))
(let ((case-fold-search t))
(websocket-debug websocket "Checking for upgrade header")
(unless (string-match "\r\nUpgrade: websocket\r\n" output)
(signal 'websocket-invalid-header
- "No 'Upgrade: websocket' header found"))
+ (list "No 'Upgrade: websocket' header found")))
(websocket-debug websocket "Checking for connection header")
(unless (string-match "\r\nConnection: upgrade\r\n" output)
(signal 'websocket-invalid-header
- "No 'Connection: upgrade' header found"))
+ (list "No 'Connection: upgrade' header found")))
(when (websocket-protocols websocket)
(dolist (protocol (websocket-protocols websocket))
(websocket-debug websocket "Checking for protocol match: %s"
@@ -812,7 +822,7 @@ of populating the list of server extensions to WEBSOCKET."
output)
(list protocol)
(signal 'websocket-invalid-header
- "Incorrect or missing protocol returned by the
server."))))
+ (list "Incorrect or missing protocol returned by the
server.")))))
(setf (websocket-negotiated-protocols websocket) protocols))))
(let* ((extensions (websocket-parse-repeated-field
output
@@ -825,8 +835,8 @@ of populating the list of server extensions to WEBSOCKET."
(push x extra-extensions))))
(when extra-extensions
(signal 'websocket-invalid-header
- (format "Non-requested extensions returned by server: %S"
- extra-extensions)))
+ (list (format "Non-requested extensions returned by server: %S"
+ extra-extensions))))
(setf (websocket-negotiated-extensions websocket) extensions)))
t)
@@ -899,13 +909,13 @@ connection, which should be kept in order to pass to
(process-put client :websocket ws)
(set-process-coding-system client 'binary 'binary)
(set-process-sentinel client
- (lambda (process change)
- (let ((websocket (process-get process :websocket)))
- (websocket-debug websocket "State change to %s" change)
- (when (and
- (member (process-status process) '(closed failed exit signal))
- (not (eq 'closed (websocket-ready-state websocket))))
- (websocket-try-callback 'websocket-on-close 'on-close
websocket)))))))
+ (lambda (process change)
+ (let ((websocket (process-get process :websocket)))
+ (websocket-debug websocket "State change to %s"
change)
+ (when (and
+ (member (process-status process) '(closed
failed exit signal))
+ (not (eq 'closed (websocket-ready-state
websocket))))
+ (websocket-try-callback 'websocket-on-close
'on-close websocket)))))))
(defun websocket-create-headers (url key protocol extensions
custom-headers-alist)
"Create connections headers for the given URL, KEY, PROTOCOL, and EXTENSIONS.
- [elpa] externals/websocket a5a25d4 08/16: * websocket/websocket.el (websocket-server-accept): Mark arg as unused, (continued)
- [elpa] externals/websocket a5a25d4 08/16: * websocket/websocket.el (websocket-server-accept): Mark arg as unused, Stefan Monnier, 2020/11/27
- [elpa] externals/websocket 45d421d 09/16: Fix some quoting problems in doc strings, Stefan Monnier, 2020/11/27
- [elpa] externals/websocket e008e03 02/16: websocket.el: Set version to 1.2, after last set of server fixes., Stefan Monnier, 2020/11/27
- [elpa] externals/websocket 2aad0b2 03/16: Upgrade to version 1.3., Stefan Monnier, 2020/11/27
- [elpa] externals/websocket 50d62ac 05/16: Add ability to handle cookies., Stefan Monnier, 2020/11/27
- [elpa] externals/websocket 6872e74 06/16: Fix maintainer address, Stefan Monnier, 2020/11/27
- [elpa] externals/websocket 6fa9830 07/16: Version 1.6, mostly fixes for fragmented headers., Stefan Monnier, 2020/11/27
- [elpa] externals/websocket 3b21915 10/16: Update to emacs-websocket version 1.8., Stefan Monnier, 2020/11/27
- [elpa] externals/websocket ba4334b 11/16: Remove use of string-make-unibyte and other cleanups., Stefan Monnier, 2020/11/27
- [elpa] externals/websocket 65b3e1c 12/16: Port websocket to bleeding-edge 32-bit Emacs, Stefan Monnier, 2020/11/27
- [elpa] externals/websocket bc57ded 15/16: Upgrade websocket library to version 1.11.1.,
Stefan Monnier <=
- [elpa] externals/websocket 8d540d4 13/16: websocket: Version 1.9, custom header support., Stefan Monnier, 2020/11/27
- [elpa] externals/websocket c4d8d58 14/16: Fix confusing documentation string in websocket library., Stefan Monnier, 2020/11/27
- [elpa] externals/websocket f11d03a 16/16: Allow websocket accept header variants., Stefan Monnier, 2020/11/27