diff options
Diffstat (limited to 'lisp/url')
-rw-r--r-- | lisp/url/url-auth.el | 6 | ||||
-rw-r--r-- | lisp/url/url-cache.el | 12 | ||||
-rw-r--r-- | lisp/url/url-cookie.el | 106 | ||||
-rw-r--r-- | lisp/url/url-dav.el | 26 | ||||
-rw-r--r-- | lisp/url/url-dired.el | 5 | ||||
-rw-r--r-- | lisp/url/url-file.el | 26 | ||||
-rw-r--r-- | lisp/url/url-gw.el | 8 | ||||
-rw-r--r-- | lisp/url/url-handlers.el | 18 | ||||
-rw-r--r-- | lisp/url/url-http.el | 130 | ||||
-rw-r--r-- | lisp/url/url-methods.el | 4 | ||||
-rw-r--r-- | lisp/url/url-privacy.el | 6 | ||||
-rw-r--r-- | lisp/url/url-queue.el | 18 | ||||
-rw-r--r-- | lisp/url/url-util.el | 28 | ||||
-rw-r--r-- | lisp/url/url-vars.el | 28 | ||||
-rw-r--r-- | lisp/url/url.el | 3 |
15 files changed, 300 insertions, 124 deletions
diff --git a/lisp/url/url-auth.el b/lisp/url/url-auth.el index c3714f26562..1ef73a62c02 100644 --- a/lisp/url/url-auth.el +++ b/lisp/url/url-auth.el @@ -192,9 +192,11 @@ key cache `url-digest-auth-storage'." (defun url-digest-auth-make-cnonce () "Compute a new unique client nonce value." (base64-encode-string - (apply 'format "%016x%04x%04x%05x%05x" (random) (current-time)) t)) + (apply #'format "%016x%08x%08x" (random) + (read (format-time-string "(%s %N)"))) + t)) -(defun url-digest-auth-nonce-count (nonce) +(defun url-digest-auth-nonce-count (_nonce) "The number requests sent to server with the given NONCE. This count includes the request we're preparing here. diff --git a/lisp/url/url-cache.el b/lisp/url/url-cache.el index 01e57799cc6..66a7223bc89 100644 --- a/lisp/url/url-cache.el +++ b/lisp/url/url-cache.el @@ -86,10 +86,10 @@ FILE can be created or overwritten." The actual return value is the last modification time of the cache file." (let* ((fname (url-cache-create-filename url)) (attribs (file-attributes fname))) - (and fname ; got a filename - (file-exists-p fname) ; file exists - (not (eq (nth 0 attribs) t)) ; Its not a directory - (nth 5 attribs)))) ; Can get last mod-time + (and fname + (file-exists-p fname) + (not (eq (file-attribute-type attribs) t)) + (file-attribute-modification-time attribs)))) (defun url-cache-create-filename-human-readable (url) "Return a filename in the local cache for URL." @@ -206,7 +206,7 @@ If `url-standalone-mode' is non-nil, cached items never expire." (time-add cache-time (seconds-to-time (or expire-time url-cache-expire-time))) - (current-time)))))) + nil))))) (defun url-cache-prune-cache (&optional directory) "Remove all expired files from the cache. @@ -226,7 +226,7 @@ considered \"expired\"." (setq deleted-files (1+ deleted-files)))) ((time-less-p (time-add - (nth 5 (file-attributes file)) + (file-attribute-modification-time (file-attributes file)) (seconds-to-time url-cache-expire-time)) now) (delete-file file) diff --git a/lisp/url/url-cookie.el b/lisp/url/url-cookie.el index 61fd85bbf1e..0c276388185 100644 --- a/lisp/url/url-cookie.el +++ b/lisp/url/url-cookie.el @@ -74,6 +74,55 @@ telling Microsoft that." ;; It's completely normal for the cookies file not to exist yet. (load (or fname url-cookie-file) t t)) +(defun url-cookie-parse-file-netscape (filename &optional long-session) + "Load cookies from FILENAME in Netscape/Mozilla format. +When LONG-SESSION is non-nil, session cookies (expiring at t=0 +i.e. 1970-1-1) are loaded as expiring one year from now instead." + (interactive "fLoad Netscape/Mozilla cookie file: ") + (let ((n 0)) + (with-temp-buffer + (insert-file-contents-literally filename) + (goto-char (point-min)) + (when (not (looking-at-p "# Netscape HTTP Cookie File\n")) + (error (format "File %s doesn't look like a netscape cookie file" filename))) + (while (not (eobp)) + (when (not (looking-at-p (rx bol (* space) "#"))) + (let* ((line (buffer-substring (point) (save-excursion (end-of-line) (point)))) + (fields (split-string line "\t"))) + (cond + ;;((>= 1 (length line) 0) + ;; (message "skipping empty line")) + ((= (length fields) 7) + (let ((dom (nth 0 fields)) + ;; (match (nth 1 fields)) + (path (nth 2 fields)) + (secure (string= (nth 3 fields) "TRUE")) + ;; session cookies (expire time = 0) are supposed + ;; to be removed when the browser is closed, but + ;; the main point of loading external cookie is to + ;; reuse a browser session, so to prevent the + ;; cookie from being detected as expired straight + ;; away, make it expire a year from now + (expires (format-time-string + "%d %b %Y %T [GMT]" + (seconds-to-time + (let ((s (string-to-number (nth 4 fields)))) + (if (and (= s 0) long-session) + (seconds-to-time (+ (* 365 24 60 60) (float-time))) + s))))) + (key (nth 5 fields)) + (val (nth 6 fields))) + (cl-incf n) + ;;(message "adding <%s>=<%s> exp=<%s> dom=<%s> path=<%s> sec=%S" key val expires dom path secure) + (url-cookie-store key val expires dom path secure) + )) + (t + (message "ignoring malformed cookie line <%s>" line))))) + (forward-line)) + (when (< 0 n) + (setq url-cookies-changed-since-last-save t)) + (message "added %d cookies from file %s" n filename)))) + (defun url-cookie-clean-up (&optional secure) (let ((var (if secure 'url-cookie-secure-storage 'url-cookie-storage)) new new-cookies) @@ -90,7 +139,8 @@ telling Microsoft that." (set var new))) (defun url-cookie-write-file (&optional fname) - (when url-cookies-changed-since-last-save + (when (and url-cookies-changed-since-last-save + url-cookie-file) (or fname (setq fname (expand-file-name url-cookie-file))) (if (condition-case nil (progn @@ -345,6 +395,8 @@ instead delete all cookies that do not match REGEXP." ;;; Mode for listing and editing cookies. +(defvar url-cookie--deleted-cookies nil) + (defun url-cookie-list () "Display a buffer listing the current URL cookies, if there are any. Use \\<url-cookie-mode-map>\\[url-cookie-delete] to remove cookies." @@ -354,6 +406,11 @@ Use \\<url-cookie-mode-map>\\[url-cookie-delete] to remove cookies." (error "No cookies are defined")) (pop-to-buffer "*url cookies*") + (url-cookie-mode) + (url-cookie--generate-buffer) + (goto-char (point-min))) + +(defun url-cookie--generate-buffer () (let ((inhibit-read-only t) (domains (sort (copy-sequence @@ -364,7 +421,6 @@ Use \\<url-cookie-mode-map>\\[url-cookie-delete] to remove cookies." (domain-length 0) start name format domain) (erase-buffer) - (url-cookie-mode) (dolist (elem domains) (setq domain-length (max domain-length (length (car elem))))) (setq format (format "%%-%ds %%-20s %%s" domain-length) @@ -376,16 +432,15 @@ Use \\<url-cookie-mode-map>\\[url-cookie-delete] to remove cookies." (lambda (c1 c2) (string< (url-cookie-name c1) (url-cookie-name c2))))) - (setq start (point) + (setq start (point) name (url-cookie-name cookie)) - (when (> (length name) 20) + (when (> (length name) 20) (setq name (substring name 0 20))) - (insert (format format domain name - (url-cookie-value cookie)) - "\n") - (setq domain "") - (put-text-property start (1+ start) 'url-cookie cookie))) - (goto-char (point-min)))) + (insert (format format domain name + (url-cookie-value cookie)) + "\n") + (setq domain "") + (put-text-property start (1+ start) 'url-cookie cookie))))) (defun url-cookie-delete () "Delete the cookie on the current line." @@ -409,12 +464,41 @@ Use \\<url-cookie-mode-map>\\[url-cookie-delete] to remove cookies." (delete-region (line-beginning-position) (progn (forward-line 1) - (point))))) + (point))) + (let ((point (point))) + (erase-buffer) + (url-cookie--generate-buffer) + (goto-char point)) + (push cookie url-cookie--deleted-cookies))) + +(defun url-cookie-undo () + "Undo deletion of a cookie." + (interactive) + (unless url-cookie--deleted-cookies + (error "No cookie deletions to undo")) + (let* ((cookie (pop url-cookie--deleted-cookies)) + (variable (if (url-cookie-secure cookie) + 'url-cookie-secure-storage + 'url-cookie-storage)) + (list (symbol-value variable)) + (elem (assoc (url-cookie-domain cookie) list))) + (if elem + (nconc elem (list cookie)) + (setq elem (list (url-cookie-domain cookie) cookie)) + (set variable (cons elem list))) + (setq url-cookies-changed-since-last-save t) + (url-cookie-write-file) + (let ((point (point)) + (inhibit-read-only t)) + (erase-buffer) + (url-cookie--generate-buffer) + (goto-char point)))) (defvar url-cookie-mode-map (let ((map (make-sparse-keymap))) (define-key map [delete] 'url-cookie-delete) (define-key map [(control k)] 'url-cookie-delete) + (define-key map [(control _)] 'url-cookie-undo) map)) (define-derived-mode url-cookie-mode special-mode "URL Cookie" diff --git a/lisp/url/url-dav.el b/lisp/url/url-dav.el index f2182e39e65..2cc2b189a1d 100644 --- a/lisp/url/url-dav.el +++ b/lisp/url/url-dav.el @@ -204,22 +204,22 @@ Returns nil if WebDAV is not supported." value nil) (pcase node-type - ((or `dateTime.iso8601tz - `dateTime.iso8601 - `dateTime.tz - `dateTime.rfc1123 - `dateTime - `date) ; date is our 'special' one... + ((or 'dateTime.iso8601tz + 'dateTime.iso8601 + 'dateTime.tz + 'dateTime.rfc1123 + 'dateTime + 'date) ; date is our 'special' one... ;; Some type of date/time string. (setq value (url-dav-process-date-property node))) - (`int + ('int ;; Integer type... (setq value (url-dav-process-integer-property node))) - ((or `number `float) + ((or 'number 'float) (setq value (url-dav-process-number-property node))) - (`boolean + ('boolean (setq value (url-dav-process-boolean-property node))) - (`uri + ('uri (setq value (url-dav-process-uri-property node))) (_ (if (not (eq node-type 'unknown)) @@ -611,11 +611,11 @@ Returns t if the lock was successfully released." (setq lock (car supported-locks) supported-locks (cdr supported-locks)) (pcase (car lock) - (`DAV:write + ('DAV:write (pcase (cdr lock) - (`DAV:shared ; group permissions (possibly world) + ('DAV:shared ; group permissions (possibly world) (aset modes 5 ?w)) - (`DAV:exclusive + ('DAV:exclusive (aset modes 2 ?w)) ; owner permissions? (_ (url-debug 'dav "Unrecognized DAV:lockscope (%S)" (cdr lock))))) diff --git a/lisp/url/url-dired.el b/lisp/url/url-dired.el index 0d7f22b61c5..a665db86fef 100644 --- a/lisp/url/url-dired.el +++ b/lisp/url/url-dired.el @@ -43,10 +43,7 @@ (url-dired-find-file)) (define-minor-mode url-dired-minor-mode - "Minor mode for directory browsing. -With a prefix argument ARG, enable the mode if ARG is positive, -and disable it otherwise. If called from Lisp, enable the mode -if ARG is omitted or nil." + "Minor mode for directory browsing." :lighter " URL" :keymap url-dired-minor-mode-map) (defun url-find-file-dired (dir) diff --git a/lisp/url/url-file.el b/lisp/url/url-file.el index 23fc97828ff..b953ce76940 100644 --- a/lisp/url/url-file.el +++ b/lisp/url/url-file.el @@ -1,4 +1,4 @@ -;;; url-file.el --- File retrieval code +;;; url-file.el --- File retrieval code -*- lexical-binding:t -*- ;; Copyright (C) 1996-1999, 2004-2019 Free Software Foundation, Inc. @@ -33,7 +33,7 @@ (defconst url-file-asynchronous-p t "FTP transfers are asynchronous.") (defalias 'url-file-expand-file-name 'url-default-expander) -(defun url-file-find-possibly-compressed-file (fname &rest args) +(defun url-file-find-possibly-compressed-file (fname &rest _) "Find the exact file referenced by `fname'. This tries the common compression extensions, because things like ange-ftp and efs are not quite smart enough to realize when a server @@ -63,14 +63,14 @@ to them." (match-beginning 0)) (system-name))))))) -(defun url-file-asynch-callback (x y name buff func args &optional efs) +(defun url-file-asynch-callback (_x _y name buff func args &optional efs) (if (not (featurep 'ange-ftp)) ;; EFS passes us an extra argument (setq name buff buff func func args args efs)) - (let ((size (nth 7 (file-attributes name)))) + (let ((size (file-attribute-size (file-attributes name)))) (with-current-buffer buff (goto-char (point-max)) (if (/= -1 size) @@ -114,8 +114,7 @@ to them." ((string-match "\\`/[^/]+:/" file) (concat "/:" file)) (t - file))) - pos-index) + file)))) (and user pass (cond @@ -142,17 +141,6 @@ to them." (not (string-match "/\\'" filename))) (setf (url-filename url) (format "%s/" filename))) - - ;; If it is a directory, look for an index file first. - (if (and (file-directory-p filename) - url-directory-index-file - (setq pos-index (expand-file-name url-directory-index-file filename)) - (file-exists-p pos-index) - (file-readable-p pos-index)) - (setq filename pos-index)) - - ;; Find the (possibly compressed) file - (setq filename (url-file-find-possibly-compressed-file filename)) filename)) ;;;###autoload @@ -211,7 +199,7 @@ to them." (if (featurep 'ange-ftp) (ange-ftp-copy-file-internal filename (expand-file-name new) t nil t - (list 'url-file-asynch-callback + (list #'url-file-asynch-callback new (current-buffer) callback cbargs) t) @@ -220,7 +208,7 @@ to them." (efs-copy-file-internal filename (efs-ftp-path filename) new (efs-ftp-path new) t nil 0 - (list 'url-file-asynch-callback + (list #'url-file-asynch-callback new (current-buffer) callback cbargs) 0 nil))))))) diff --git a/lisp/url/url-gw.el b/lisp/url/url-gw.el index c62e813b663..54360840784 100644 --- a/lisp/url/url-gw.el +++ b/lisp/url/url-gw.el @@ -239,7 +239,7 @@ overriding the value of `url-gateway-method'." (let ((coding-system-for-read 'binary) (coding-system-for-write 'binary)) (setq conn (pcase gw-method - ((or `tls `ssl `native) + ((or 'tls 'ssl 'native) (if (eq gw-method 'native) (setq gw-method 'plain)) (open-network-stream @@ -249,11 +249,11 @@ overriding the value of `url-gateway-method'." :nowait (and (featurep 'make-network-process) (url-asynchronous url-current-object) '(:nowait t)))) - (`socks + ('socks (socks-open-network-stream name buffer host service)) - (`telnet + ('telnet (url-open-telnet name buffer host service)) - (`rlogin + ('rlogin (url-open-rlogin name buffer host service)) (_ (error "Bad setting of url-gateway-method: %s" diff --git a/lisp/url/url-handlers.el b/lisp/url/url-handlers.el index 3af4e9e7b19..2d0a4a21c44 100644 --- a/lisp/url/url-handlers.el +++ b/lisp/url/url-handlers.el @@ -28,6 +28,7 @@ ;; (require 'url-util) (eval-when-compile (require 'mm-decode)) ;; (require 'mailcap) +(eval-when-compile (require 'subr-x)) ;; The following are autoloaded instead of `require'd to avoid eagerly ;; loading all of URL when turning on url-handler-mode in the .emacs. (autoload 'url-expand-file-name "url-expand" "Convert url to a fully specified url, and canonicalize it.") @@ -41,6 +42,9 @@ (declare-function mm-decode-string "mm-bodies" (string charset)) ;; mm-decode loads mail-parse. (declare-function mail-content-type-get "mail-parse" (ct attribute)) +;; mm-decode loads mm-bodies, which loads mm-util. +(declare-function mm-charset-to-coding-system "mm-util" + (charset &optional lbt allow-override silent)) ;; Implementation status ;; --------------------- @@ -98,10 +102,7 @@ ;;;###autoload (define-minor-mode url-handler-mode - "Toggle using `url' library for URL filenames (URL Handler mode). -With a prefix argument ARG, enable URL Handler mode if ARG is -positive, and disable it otherwise. If called from Lisp, enable -the mode if ARG is omitted or nil." + "Toggle using `url' library for URL filenames (URL Handler mode)." :global t :group 'url ;; Remove old entry, if any. (setq file-name-handler-alist @@ -183,6 +184,7 @@ the arguments that would have been passed to OPERATION." (put 'file-name-absolute-p 'url-file-handlers (lambda (&rest ignored) t)) (put 'expand-file-name 'url-file-handlers 'url-handler-expand-file-name) (put 'directory-file-name 'url-file-handlers 'url-handler-directory-file-name) +(put 'file-name-directory 'url-file-handlers 'url-handler-file-name-directory) (put 'unhandled-file-name-directory 'url-file-handlers 'url-handler-unhandled-file-name-directory) (put 'file-remote-p 'url-file-handlers 'url-handler-file-remote-p) ;; (put 'file-name-as-directory 'url-file-handlers 'url-handler-file-name-as-directory) @@ -228,6 +230,14 @@ the arguments that would have been passed to OPERATION." ;; a local process. nil))) +(defun url-handler-file-name-directory (dir) + (let ((url (url-generic-parse-url dir))) + ;; Do not attempt to handle `file' URLs which are local. + (if (and (not (equal (url-type url) "file")) + (string-empty-p (url-filename url))) + (url-handler-file-name-directory (concat dir "/")) + (url-run-real-handler 'file-name-directory (list dir))))) + (defun url-handler-file-remote-p (filename &optional identification _connected) (let ((url (url-generic-parse-url filename))) (if (and (url-type url) (not (equal (url-type url) "file"))) diff --git a/lisp/url/url-http.el b/lisp/url/url-http.el index 1bcfc10645d..76faac13808 100644 --- a/lisp/url/url-http.el +++ b/lisp/url/url-http.el @@ -54,6 +54,7 @@ (defvar url-http-target-url) (defvar url-http-transfer-encoding) (defvar url-show-status) +(defvar url-http-referer) (require 'url-gw) (require 'url-parse) @@ -238,6 +239,35 @@ request.") emacs-info os-info)) " "))) +(defun url-http--get-referer (url) + (url-http-debug "getting referer from buffer: buffer:%S target-url:%S lastloc:%S" (current-buffer) url url-current-lastloc) + (when url-current-lastloc + (if (not (url-p url-current-lastloc)) + (setq url-current-lastloc (url-generic-parse-url url-current-lastloc))) + (let ((referer (copy-sequence url-current-lastloc))) + (setf (url-host referer) (puny-encode-domain (url-host referer))) + (let ((referer-string (url-recreate-url referer))) + (when (and (not (memq url-privacy-level '(low high paranoid))) + (not (and (listp url-privacy-level) + (memq 'lastloc url-privacy-level)))) + ;; url-privacy-level allows referer. But url-lastloc-privacy-level + ;; may restrict who we send it to. + (cl-case url-lastloc-privacy-level + (host-match + (let ((referer-host (url-host referer)) + (url-host (url-host url))) + (when (string= referer-host url-host) + referer-string))) + (domain-match + (let ((referer-domain (url-domain referer)) + (url-domain (url-domain url))) + (when (and referer-domain + url-domain + (string= referer-domain url-domain)) + referer-string))) + (otherwise + referer-string))))))) + ;; Building an HTTP request (defun url-http-user-agent-string () "Compute a User-Agent string. @@ -254,8 +284,9 @@ The string is based on `url-privacy-level' and `url-user-agent'." ((eq url-user-agent 'default) (url-http--user-agent-default-string)))))) (if ua-string (format "User-Agent: %s\r\n" (string-trim ua-string)) ""))) -(defun url-http-create-request (&optional ref-url) - "Create an HTTP request for `url-http-target-url', referred to by REF-URL." +(defun url-http-create-request () + "Create an HTTP request for `url-http-target-url'. +Use `url-http-referer' as the Referer-header (subject to `url-privacy-level')." (let* ((extra-headers) (request nil) (no-cache (cdr-safe (assoc "Pragma" url-http-extra-headers))) @@ -268,13 +299,14 @@ The string is based on `url-privacy-level' and `url-user-agent'." 'url-http-proxy-basic-auth-storage)) (url-get-authentication url-http-proxy nil 'any nil)))) (real-fname (url-filename url-http-target-url)) - (host (url-http--encode-string (url-host url-http-target-url))) + (host (url-host url-http-target-url)) (auth (if (cdr-safe (assoc "Authorization" url-http-extra-headers)) nil (url-get-authentication (or (and (boundp 'proxy-info) proxy-info) - url-http-target-url) nil 'any nil)))) + url-http-target-url) nil 'any nil))) + (ref-url (url-http--encode-string url-http-referer))) (if (equal "" real-fname) (setq real-fname "/")) (setq no-cache (and no-cache (string-match "no-cache" no-cache))) @@ -288,12 +320,6 @@ The string is based on `url-privacy-level' and `url-user-agent'." (string= ref-url ""))) (setq ref-url nil)) - ;; We do not want to expose the referrer if the user is paranoid. - (if (or (memq url-privacy-level '(low high paranoid)) - (and (listp url-privacy-level) - (memq 'lastloc url-privacy-level))) - (setq ref-url nil)) - ;; url-http-extra-headers contains an assoc-list of ;; header/value pairs that we need to put into the request. (setq extra-headers (mapconcat @@ -329,9 +355,11 @@ The string is based on `url-privacy-level' and `url-user-agent'." (url-scheme-get-property (url-type url-http-target-url) 'default-port)) (format - "Host: %s:%d\r\n" (puny-encode-domain host) + "Host: %s:%d\r\n" (url-http--encode-string + (puny-encode-domain host)) (url-port url-http-target-url)) - (format "Host: %s\r\n" (puny-encode-domain host))) + (format "Host: %s\r\n" + (url-http--encode-string (puny-encode-domain host)))) ;; Who its from (if url-personal-mail-address (concat @@ -585,7 +613,7 @@ should be shown to the user." ;; 206 Partial content ;; 207 Multi-status (Added by DAV) (pcase status-symbol - ((or `no-content `reset-content) + ((or 'no-content 'reset-content) ;; No new data, just stay at the same document (url-mark-buffer-as-dead buffer)) (_ @@ -606,7 +634,7 @@ should be shown to the user." (let ((redirect-uri (or (mail-fetch-field "Location") (mail-fetch-field "URI")))) (pcase status-symbol - (`multiple-choices ; 300 + ('multiple-choices ; 300 ;; Quoth the spec (section 10.3.1) ;; ------------------------------- ;; The requested resource corresponds to any one of a set of @@ -623,20 +651,26 @@ should be shown to the user." ;; We do not support agent-driven negotiation, so we just ;; redirect to the preferred URI if one is provided. nil) - (`see-other ; 303 + ('found ; 302 + ;; 302 Found was ambiguously defined in the standards, but + ;; it's now recommended that it's treated like 303 instead + ;; of 307, since that's what most servers expect. + (setq url-http-method "GET" + url-http-data nil)) + ('see-other ; 303 ;; The response to the request can be found under a different ;; URI and SHOULD be retrieved using a GET method on that ;; resource. (setq url-http-method "GET" url-http-data nil)) - (`not-modified ; 304 + ('not-modified ; 304 ;; The 304 response MUST NOT contain a message-body. (url-http-debug "Extracting document from cache... (%s)" (url-cache-create-filename (url-view-url t))) (url-cache-extract (url-cache-create-filename (url-view-url t))) (setq redirect-uri nil success t)) - (`use-proxy ; 305 + ('use-proxy ; 305 ;; The requested resource MUST be accessed through the ;; proxy given by the Location field. The Location field ;; gives the URI of the proxy. The recipient is expected @@ -734,50 +768,50 @@ should be shown to the user." ;; 424 Failed Dependency (setq success (pcase status-symbol - (`unauthorized ; 401 + ('unauthorized ; 401 ;; The request requires user authentication. The response ;; MUST include a WWW-Authenticate header field containing a ;; challenge applicable to the requested resource. The ;; client MAY repeat the request with a suitable ;; Authorization header field. (url-http-handle-authentication nil)) - (`payment-required ; 402 + ('payment-required ; 402 ;; This code is reserved for future use (url-mark-buffer-as-dead buffer) (error "Somebody wants you to give them money")) - (`forbidden ; 403 + ('forbidden ; 403 ;; The server understood the request, but is refusing to ;; fulfill it. Authorization will not help and the request ;; SHOULD NOT be repeated. t) - (`not-found ; 404 + ('not-found ; 404 ;; Not found t) - (`method-not-allowed ; 405 + ('method-not-allowed ; 405 ;; The method specified in the Request-Line is not allowed ;; for the resource identified by the Request-URI. The ;; response MUST include an Allow header containing a list of ;; valid methods for the requested resource. t) - (`not-acceptable ; 406 + ('not-acceptable ; 406 ;; The resource identified by the request is only capable of ;; generating response entities which have content ;; characteristics not acceptable according to the accept ;; headers sent in the request. t) - (`proxy-authentication-required ; 407 + ('proxy-authentication-required ; 407 ;; This code is similar to 401 (Unauthorized), but indicates ;; that the client must first authenticate itself with the ;; proxy. The proxy MUST return a Proxy-Authenticate header ;; field containing a challenge applicable to the proxy for ;; the requested resource. (url-http-handle-authentication t)) - (`request-timeout ; 408 + ('request-timeout ; 408 ;; The client did not produce a request within the time that ;; the server was prepared to wait. The client MAY repeat ;; the request without modifications at any later time. t) - (`conflict ; 409 + ('conflict ; 409 ;; The request could not be completed due to a conflict with ;; the current state of the resource. This code is only ;; allowed in situations where it is expected that the user @@ -786,11 +820,11 @@ should be shown to the user." ;; information for the user to recognize the source of the ;; conflict. t) - (`gone ; 410 + ('gone ; 410 ;; The requested resource is no longer available at the ;; server and no forwarding address is known. t) - (`length-required ; 411 + ('length-required ; 411 ;; The server refuses to accept the request without a defined ;; Content-Length. The client MAY repeat the request if it ;; adds a valid Content-Length header field containing the @@ -800,29 +834,29 @@ should be shown to the user." ;; `url-http-create-request' automatically calculates the ;; content-length. t) - (`precondition-failed ; 412 + ('precondition-failed ; 412 ;; The precondition given in one or more of the ;; request-header fields evaluated to false when it was ;; tested on the server. t) - ((or `request-entity-too-large `request-uri-too-large) ; 413 414 + ((or 'request-entity-too-large 'request-uri-too-large) ; 413 414 ;; The server is refusing to process a request because the ;; request entity|URI is larger than the server is willing or ;; able to process. t) - (`unsupported-media-type ; 415 + ('unsupported-media-type ; 415 ;; The server is refusing to service the request because the ;; entity of the request is in a format not supported by the ;; requested resource for the requested method. t) - (`requested-range-not-satisfiable ; 416 + ('requested-range-not-satisfiable ; 416 ;; A server SHOULD return a response with this status code if ;; a request included a Range request-header field, and none ;; of the range-specifier values in this field overlap the ;; current extent of the selected resource, and the request ;; did not include an If-Range request-header field. t) - (`expectation-failed ; 417 + ('expectation-failed ; 417 ;; The expectation given in an Expect request-header field ;; could not be met by this server, or, if the server is a ;; proxy, the server has unambiguous evidence that the @@ -849,16 +883,16 @@ should be shown to the user." ;; 507 Insufficient storage (setq success t) (pcase url-http-response-status - (`not-implemented ; 501 + ('not-implemented ; 501 ;; The server does not support the functionality required to ;; fulfill the request. nil) - (`bad-gateway ; 502 + ('bad-gateway ; 502 ;; The server, while acting as a gateway or proxy, received ;; an invalid response from the upstream server it accessed ;; in attempting to fulfill the request. nil) - (`service-unavailable ; 503 + ('service-unavailable ; 503 ;; The server is currently unable to handle the request due ;; to a temporary overloading or maintenance of the server. ;; The implication is that this is a temporary condition @@ -867,19 +901,19 @@ should be shown to the user." ;; header. If no Retry-After is given, the client SHOULD ;; handle the response as it would for a 500 response. nil) - (`gateway-timeout ; 504 + ('gateway-timeout ; 504 ;; The server, while acting as a gateway or proxy, did not ;; receive a timely response from the upstream server ;; specified by the URI (e.g. HTTP, FTP, LDAP) or some other ;; auxiliary server (e.g. DNS) it needed to access in ;; attempting to complete the request. nil) - (`http-version-not-supported ; 505 + ('http-version-not-supported ; 505 ;; The server does not support, or refuses to support, the ;; HTTP protocol version that was used in the request ;; message. nil) - (`insufficient-storage ; 507 (DAV) + ('insufficient-storage ; 507 (DAV) ;; The method could not be performed on the resource ;; because the server is unable to store the representation ;; needed to successfully complete the request. This @@ -1258,7 +1292,8 @@ The return value of this function is the retrieval buffer." (mime-accept-string url-mime-accept-string) (buffer (or retry-buffer (generate-new-buffer - (format " *http %s:%d*" (url-host url) (url-port url)))))) + (format " *http %s:%d*" (url-host url) (url-port url))))) + (referer (url-http--encode-string (url-http--get-referer url)))) (if (not connection) ;; Failed to open the connection for some reason (progn @@ -1293,7 +1328,8 @@ The return value of this function is the retrieval buffer." url-http-no-retry url-http-connection-opened url-mime-accept-string - url-http-proxy)) + url-http-proxy + url-http-referer)) (set (make-local-variable var) nil)) (setq url-http-method (or url-request-method "GET") @@ -1311,15 +1347,16 @@ The return value of this function is the retrieval buffer." url-http-no-retry retry-buffer url-http-connection-opened nil url-mime-accept-string mime-accept-string - url-http-proxy url-using-proxy) + url-http-proxy url-using-proxy + url-http-referer referer) (set-process-buffer connection buffer) (set-process-filter connection 'url-http-generic-filter) (pcase (process-status connection) - (`connect + ('connect ;; Asynchronous connection (set-process-sentinel connection 'url-http-async-sentinel)) - (`failed + ('failed ;; Asynchronous connection failed (error "Could not create connection to %s:%d" (url-host url) (url-port url))) @@ -1375,7 +1412,9 @@ The return value of this function is the retrieval buffer." 'url-http-wait-for-headers-change-function) (set-process-filter tls-connection 'url-http-generic-filter) (process-send-string tls-connection - (url-http-create-request))) + ;; Use the non-proxy form of the request + (let (url-http-proxy) + (url-http-create-request)))) (gnutls-error (url-http-activate-callback) (error "gnutls-error: %s" e)) @@ -1563,7 +1602,6 @@ p3p ;; HTTPS. This used to be in url-https.el, but that file collides ;; with url-http.el on systems with 8-character file names. -(require 'tls) (defconst url-https-asynchronous-p t "HTTPS retrievals are asynchronous.") diff --git a/lisp/url/url-methods.el b/lisp/url/url-methods.el index 456be7ed4f7..1c0c5af86ac 100644 --- a/lisp/url/url-methods.el +++ b/lisp/url/url-methods.el @@ -134,11 +134,11 @@ it has not already been loaded." (type (cdr cell))) (if symbol (pcase type - (`function + ('function ;; Store the symbol name of a function (if (fboundp symbol) (setq desc (plist-put desc (car cell) symbol)))) - (`variable + ('variable ;; Store the VALUE of a variable (if (boundp symbol) (setq desc (plist-put desc (car cell) diff --git a/lisp/url/url-privacy.el b/lisp/url/url-privacy.el index 994ae6ac5da..ef9ff84d56e 100644 --- a/lisp/url/url-privacy.el +++ b/lisp/url/url-privacy.el @@ -45,9 +45,9 @@ ((memq (url-device-type) '(win32 w32)) "Windows; 32bit") (t (pcase (url-device-type) - (`x "X11") - (`ns "OpenStep") - (`tty "TTY") + ('x "X11") + ('ns "OpenStep") + ('tty "TTY") (_ nil))))) (setq url-personal-mail-address (or url-personal-mail-address diff --git a/lisp/url/url-queue.el b/lisp/url/url-queue.el index 38137b85e40..6350081b1a3 100644 --- a/lisp/url/url-queue.el +++ b/lisp/url/url-queue.el @@ -52,7 +52,7 @@ (cl-defstruct url-queue url callback cbargs silentp buffer start-time pre-triggered - inhibit-cookiesp) + inhibit-cookiesp context-buffer) ;;;###autoload (defun url-queue-retrieve (url callback &optional cbargs silent inhibit-cookies) @@ -67,7 +67,8 @@ The variable `url-queue-timeout' sets a timeout." :callback callback :cbargs cbargs :silentp silent - :inhibit-cookiesp inhibit-cookies)))) + :inhibit-cookiesp inhibit-cookies + :context-buffer (current-buffer))))) (url-queue-setup-runners)) ;; To ensure asynch behavior, we start the required number of queue @@ -147,11 +148,14 @@ The variable `url-queue-timeout' sets a timeout." (defun url-queue-start-retrieve (job) (setf (url-queue-buffer job) (ignore-errors - (let ((url-request-noninteractive t)) - (url-retrieve (url-queue-url job) - #'url-queue-callback-function (list job) - (url-queue-silentp job) - (url-queue-inhibit-cookiesp job)))))) + (with-current-buffer (if (buffer-live-p (url-queue-context-buffer job)) + (url-queue-context-buffer job) + (current-buffer)) + (let ((url-request-noninteractive t)) + (url-retrieve (url-queue-url job) + #'url-queue-callback-function (list job) + (url-queue-silentp job) + (url-queue-inhibit-cookiesp job))))))) (defun url-queue-prune-old-entries () (let (dead-jobs) diff --git a/lisp/url/url-util.el b/lisp/url/url-util.el index 11ee15fdd4e..1ca257210aa 100644 --- a/lisp/url/url-util.el +++ b/lisp/url/url-util.el @@ -627,6 +627,34 @@ Creates FILE and its parent directories if they do not exist." (error "Danger: `%s' is a symbolic link" file)) (set-file-modes file #o0600)))) +(autoload 'puny-encode-domain "puny") +(autoload 'url-domsuf-cookie-allowed-p "url-domsuf") + +;;;###autoload +(defun url-domain (url) + "Return the domain of the host of the URL. +Return nil if this can't be determined. + +For instance, this function will return \"fsf.co.uk\" if the host in URL +is \"www.fsf.co.uk\"." + (let* ((host (puny-encode-domain (url-host url))) + (parts (nreverse (split-string host "\\."))) + (candidate (pop parts)) + found) + ;; IP addresses aren't domains. + (when (string-match "\\`[0-9.]+\\'" host) + (setq parts nil)) + ;; We assume that the top-level domain is never an appropriate + ;; thing as "the domain", so we start at the next one (eg. + ;; "fsf.org"). + (while (and parts + (not (setq found + (url-domsuf-cookie-allowed-p + (setq candidate (concat (pop parts) "." + candidate)))))) + ) + (and found candidate))) + (provide 'url-util) ;;; url-util.el ends here diff --git a/lisp/url/url-vars.el b/lisp/url/url-vars.el index a5d80ff1518..ae1d6e54391 100644 --- a/lisp/url/url-vars.el +++ b/lisp/url/url-vars.el @@ -60,10 +60,18 @@ (defvar url-current-mime-headers nil "A parsed representation of the MIME headers for the current URL.") +(defvar url-current-lastloc nil + "A parsed representation of the URL to be considered as the last location. +Use of this value on outbound connections is subject to +`url-privacy-level' and `url-lastloc-privacy-level'. This is never set +by the url library, applications are expected to set this +variable in buffers representing a displayed location.") + (mapc 'make-variable-buffer-local '( url-current-object url-current-mime-headers + url-current-lastloc )) (defcustom url-honor-refresh-requests t @@ -117,7 +125,7 @@ Valid symbols are: email -- the email address os -- the operating system info emacs -- the version of Emacs -lastloc -- the last location +lastloc -- the last location (see also `url-lastloc-privacy-level') agent -- do not send the User-Agent string cookies -- never accept HTTP cookies @@ -150,6 +158,24 @@ variable." (const :tag "No cookies" :value cookie))) :group 'url) +(defcustom url-lastloc-privacy-level 'domain-match + "Further restrictions on sending the last location. +This value is only consulted if `url-privacy-level' permits +sending last location in the first place. + +Valid values are: +none -- Always send last location. +domain-match -- Send last location if the new location is within the + same domain +host-match -- Send last location if the new location is on the + same host +" + :version "27.1" + :type '(radio (const :tag "Always send" none) + (const :tag "Domains match" domain-match) + (const :tag "Hosts match" host-match)) + :group 'url) + (defvar url-inhibit-uncompression nil "Do not do decompression if non-nil.") (defcustom url-uncompressor-alist '((".z" . "x-gzip") diff --git a/lisp/url/url.el b/lisp/url/url.el index fbf31d420cb..101c2b2c541 100644 --- a/lisp/url/url.el +++ b/lisp/url/url.el @@ -259,8 +259,7 @@ how long to wait for a response before giving up." ;; process output. (while (and (not retrieval-done) (or (not timeout) - (< (float-time (time-subtract - (current-time) start-time)) + (< (float-time (time-subtract nil start-time)) timeout))) (url-debug 'retrieval "Spinning in url-retrieve-synchronously: %S (%S)" |