X-Git-Url: https://code.delx.au/gnu-emacs-elpa/blobdiff_plain/7a47daeb4e9c229c332bf6d270576726b9188367..23a624ca1d40fa9cefd7229ac6152b79278a6517:/packages/websocket/websocket.el diff --git a/packages/websocket/websocket.el b/packages/websocket/websocket.el index 7ea9c933b..969e70b26 100644 --- a/packages/websocket/websocket.el +++ b/packages/websocket/websocket.el @@ -5,7 +5,7 @@ ;; Author: Andrew Hyatt ;; Maintainer: Andrew Hyatt ;; Keywords: Communication, Websocket, Server -;; Version: 1.1 +;; Version: 1.3 ;; ;; This program is free software; you can redistribute it and/or ;; modify it under the terms of the GNU General Public License as @@ -99,7 +99,7 @@ same for the protocols. accept-string (inflight-input nil)) -(defvar websocket-version "1.1" +(defvar websocket-version "1.3" "Version numbers of this version of websocket.el.") (defvar websocket-debug nil @@ -111,11 +111,6 @@ URL of the connection.") "The websocket GUID as defined in RFC 6455. Do not change unless the RFC changes.") -(defvar websocket-mask-frames t - "If true, we mask frames as defined in the spec. -This is recommended to be true, and some servers will refuse to -communicate with unmasked clients.") - (defvar websocket-callback-debug-on-error nil "If true, when an error happens in a client callback, invoke the debugger. Having this on can cause issues with missing frames if the debugger is @@ -295,13 +290,14 @@ Otherwise we throw the error `websocket-incomplete-frame'." (when (< (length s) n) (throw 'websocket-incomplete-frame nil))) -(defun websocket-encode-frame (frame) - "Encode the FRAME struct to the binary representation." +(defun websocket-encode-frame (frame should-mask) + "Encode the FRAME struct to the binary representation. +We mask the frame or not, depending on SHOULD-MASK." (let* ((opcode (websocket-frame-opcode frame)) (payload (websocket-frame-payload frame)) (fin (websocket-frame-completep frame)) (payloadp (memq opcode '(continuation text binary))) - (mask-key (when websocket-mask-frames (websocket-genbytes 4)))) + (mask-key (when should-mask (websocket-genbytes 4)))) (apply 'unibyte-string (append (list (logior (cond ((eq opcode 'continuation) 0) @@ -314,7 +310,7 @@ Otherwise we throw the error `websocket-incomplete-frame'." (when payloadp (list (logior - (if websocket-mask-frames 128 0) + (if should-mask 128 0) (cond ((< (length payload) 126) (length payload)) ((< (length payload) 65536) 126) (t 127))))) @@ -323,11 +319,10 @@ Otherwise we throw the error `websocket-incomplete-frame'." (cond ((< (length payload) 126) 1) ((< (length payload) 65536) 2) (t 8))) nil)) - (when (and payloadp websocket-mask-frames) + (when (and payloadp should-mask) (append mask-key nil)) (when payloadp - (append (if websocket-mask-frames - (websocket-mask mask-key payload) + (append (if should-mask (websocket-mask mask-key payload) payload) nil)))))) @@ -542,7 +537,8 @@ the `websocket-error' condition." (unless (websocket-openp websocket) (signal 'websocket-closed frame)) (process-send-string (websocket-conn websocket) - (websocket-encode-frame frame))) + ;; We mask only when we're a client, following the spec. + (websocket-encode-frame frame (not (websocket-server-p websocket))))) (defun websocket-openp (websocket) "Check WEBSOCKET and return non-nil if it is open, and either @@ -554,14 +550,13 @@ connecting or open." (defun websocket-close (websocket) "Close WEBSOCKET and erase all the old websocket data." (websocket-debug websocket "Closing websocket") + (websocket-try-callback 'websocket-on-close 'on-close websocket) (when (websocket-openp websocket) (websocket-send websocket (make-websocket-frame :opcode 'close :completep t)) (setf (websocket-ready-state websocket) 'closed)) - (let ((buf (process-buffer (websocket-conn websocket)))) - (delete-process (websocket-conn websocket)) - (kill-buffer buf))) + (delete-process (websocket-conn websocket))) (defun websocket-ensure-connected (websocket) "If the WEBSOCKET connection is closed, open it." @@ -653,7 +648,6 @@ describing the problem with the frame. (let* ((name (format "websocket to %s" url)) (url-struct (url-generic-parse-url url)) (key (websocket-genkey)) - (buf-name (format " *%s*" name)) (coding-system-for-read 'binary) (coding-system-for-write 'binary) (conn (if (member (url-type url-struct) '("ws" "wss")) @@ -662,13 +656,12 @@ describing the problem with the frame. (port (if (= 0 (url-port url-struct)) (if (eq type 'tls) 443 80) (url-port url-struct))) - (host (url-host url-struct)) - (buf (get-buffer-create buf-name))) + (host (url-host url-struct))) (if (eq type 'plain) - (make-network-process :name name :buffer buf :host host + (make-network-process :name name :buffer nil :host host :service port :nowait nil) (condition-case-unless-debug nil - (open-network-stream name buf host port :type type :nowait nil) + (open-network-stream name nil host port :type type :nowait nil) (wrong-number-of-arguments (signal 'websocket-wss-needs-emacs-24 "wss"))))) (signal 'websocket-unsupported-protocol (url-type url-struct)))) @@ -683,6 +676,7 @@ describing the problem with the frame. :extensions (mapcar 'car extensions) :accept-string (websocket-calculate-accept key)))) + (unless conn (error "Could not establish the websocket connection to %s" url)) (process-put conn :websocket websocket) (set-process-filter conn (lambda (process output) @@ -692,9 +686,10 @@ describing the problem with the frame. conn (lambda (process change) (let ((websocket (process-get process :websocket))) - (websocket-debug websocket - "State change to %s" change) - (unless (eq 'closed (websocket-ready-state 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))))) (set-process-query-on-exit-flag conn nil) (process-send-string conn @@ -799,9 +794,10 @@ in the websocket client function `websocket-open'. Returns the connection, which should be kept in order to pass to `websocket-server-close'." (let* ((conn (make-network-process - :name (format "websocket server on port %d" port) + :name (format "websocket server on port %s" port) :server t :family 'ipv4 + :filter 'websocket-server-filter :log 'websocket-server-accept :filter-multibyte nil :plist plist @@ -827,6 +823,7 @@ connection, which should be kept in order to pass to :server-conn server :conn client :url client + :server-p t :on-open (or (process-get server :on-open) 'identity) :on-message (or (process-get server :on-message) (lambda (_ws _frame))) :on-close (lexical-let ((user-method @@ -841,15 +838,15 @@ connection, which should be kept in order to pass to :extensions (mapcar 'car (process-get server :extensions))))) (unless (member ws websocket-server-websockets) (push ws websocket-server-websockets)) - (set-process-coding-system client 'unix 'unix) (process-put client :websocket ws) - (set-process-filter client 'websocket-server-filter) - (set-process-coding-system client 'binary) + (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) - (unless (eq 'closed (websocket-ready-state websocket)) + (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) @@ -859,7 +856,6 @@ These are defined as in `websocket-open'." "Upgrade: websocket\r\n" "Connection: Upgrade\r\n" "Sec-WebSocket-Key: %s\r\n" - "Origin: %s\r\n" "Sec-WebSocket-Version: 13\r\n" (when protocol (concat @@ -879,7 +875,6 @@ These are defined as in `websocket-open'." "\r\n") (url-host (url-generic-parse-url url)) key - system-name protocol)) (defun websocket-get-server-response (websocket client-protocols client-extensions)