0

I want to use url-file-exists-p (or more precisely, the underlying url-https-file-exists-p) to detect possible broken links. However, some https link makes url-file-exists-p require interaction (This even happens when url-file-exists-p is called programmatically):

  1. when the TLS connection is insecure: a buffer named *Network Security Manager* pop up to show certificate information and a prompt is waiting for input as below; enter image description here (below is the result of the help). enter image description here
  2. ask for user-name and password.

I'm looking for a way to

  1. prevent the buffer *Network Security Manager* pop up
  2. send input to the prompt whenever is needed
  3. return different values/symbols depending on the context
    • t: secure connection, no prompt showed up
    • nil: connection failure
    • TLS: 'always, 'session and 'no: depending on the input (2.) sent whenever a prompt requires one
    • username/password: 'ignored if username/password are not sent to the prompt causing failure.
0

I list below several attempts I tried.

  1. Associate display-buffer-no-window to the buffer *Network Security Manager*. This prevent the buffer to pop up, and since url-file-exists-p fails to receive input, an error is throw. Finally, intepret the "pop up" as 'no.
(let ((display-buffer-alist
     (cons display-buffer-alist
           (cons "\\*Network Security Manager\\*"
             (cons #'display-buffer-no-window nil))))) 
    (condition-case nil
    (url-file-exists-p url)
      (error 'no)))
  1. Bound (minibuffer-message-timeout 0) in a let-in form.

For whatever reason, the two first attempts fail to deal with the prompt asking for authentification. By inspecting the source code of url-* packages, I found a workaround:

Send a GET request instead of a HEAD request as url-http-file-exists-p do (url-http-head).

  1. Strangely, the website requiring authentification doesn't require one when is a GET request in contrast to HEAD request. Obviously, this is just a workaround as a GET request may take much more resource than a HEAD one.
  (defun my/url-http-file-exists-p (url)
    (let ((buffer (url-retrieve-synchronously url t t)))
      (when buffer
    (let ((status (url-http-symbol-value-in-buffer 'url-http-response-status
                               buffer
                               500)))
      (prog1
          (and (integerp status)
         (>= status 200) (< status 300))
        (kill-buffer buffer))))))
  1. Use the auto-answer package where it is illustrated in this answer. To do this, we need to enhance it so that it supports read-multiple-choice (the function called when there is an insecure TLS connection).
(defun rmc-auto-answer (oldfun &rest args)
  (let ((prompt (car args)))
    (let*
        ((matcher-answer (and (stringp prompt)
                              (--first (string-match (car it) prompt) auto-answer)))
         (dontask (and matcher-answer (cdr matcher-answer))))
      (if dontask
          (--first (eq (car it) dontask) (cadr args))
        (apply oldfun args)))))

(advice-add #'read-multiple-choice :around #'rmc-auto-answer)

Finally, by binding the variable auto-answer, we can feed the input automatically whenever there is an insecure TLS connection asking for input

(let ((auto-answer (list (cons "Continue connecting\\?" ?s))))
             (url-http-file-exists-p url))

However, the authentification prompt occurs in an endless loop which means that this attempt is not sufficient (even if we can auto-answer username/password).

  1. TODO Use Request.el instead of url.el.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.