[emacs-berlin] Code review for a simple HTTP async client

jman emacs-berlin at city17.xyz
Tue Jan 2 15:18:25 UTC 2024

Today I decided to get to the bottom of it, so here we are with what I
believe is the correct solution :-)

Due to the single-threaded nature of Emacs, handling async tasks is
unwieldy. Opting for a sync HTTP client is equally not great because the
entire UI would block until the operation completes. And since this
involves a remote server, the waiting is undefined (could even timeout
at 30 seconds).

The only way I could make it work reliably was to remove the global
variable and put the Location URL from the header into the kill ring.

(defun jman/http-head-no-redirect (url)
  "Sends an HTTP HEAD request to URL, don't follow redirects.
Parse the response headers and put the Location into the kill ring."
  (defvar url-request-method "HEAD")
  (defvar url-user-agent "User-Agent: Mozilla/5.0 (compatible; Googlebot/2.1; +google.com/bot.html)")
  (let ()
     (lambda (status)
       (when (eq (car status) :redirect)
         (let ((location (cadr status)))
           (message "URL: %s" location)
           (kill-new location)))))))

The caller of the async function should not attempt to do anything with
the result because it will always finish ealier.

(defun jman/clean-links (url)
  (interactive (list (shr-url-at-point current-prefix-arg)))
  (jman/http-head-no-redirect url)
  ;; This point is reached before the task above line has finished

By the way, Doom Emacs ships with async.el[0] but I prefer a solution
that works with the Emacs standard library.

[0]: https://github.com/jwiegley/emacs-async

More information about the emacs-berlin mailing list