unofficial mirror of guix-patches@gnu.org 
 help / color / mirror / code / Atom feed
From: Christopher Baines <mail@cbaines.net>
To: 45409@debbugs.gnu.org
Subject: [bug#45409] [PATCH v5 05/14] http-client: Add error handling to http-multiple-get.
Date: Sat, 13 Feb 2021 13:47:10 +0000	[thread overview]
Message-ID: <20210213134719.19625-5-mail@cbaines.net> (raw)
In-Reply-To: <20210213134719.19625-1-mail@cbaines.net>

Making sure to close the port if it looks to be unusable. This closing of the
port will allow for caching connections, without caching broken connections,
as the cache can avoid handing out closed ports.

* guix/http-client.scm (http-multiple-get): Try to catch exceptions that
happen if the port is unusable, this is a adaptation of code within the (guix
scripts substitute) module.
---
 guix/http-client.scm | 74 +++++++++++++++++++++++++++++++++-----------
 1 file changed, 56 insertions(+), 18 deletions(-)

diff --git a/guix/http-client.scm b/guix/http-client.scm
index 7ead493633..3aba3b28c1 100644
--- a/guix/http-client.scm
+++ b/guix/http-client.scm
@@ -38,6 +38,7 @@
   #:use-module (guix utils)
   #:use-module (guix base64)
   #:autoload   (gcrypt hash) (sha256)
+  #:autoload   (gnutls) (error/invalid-session)
   #:use-module ((guix build utils)
                 #:select (mkdir-p dump-port))
   #:use-module ((guix build download)
@@ -180,10 +181,25 @@ returning."
         ;; Inherit the HTTP proxying property from P.
         (set-http-proxy-port?! buffer (http-proxy-port? p))
 
-        (for-each (cut write-request <> buffer)
-                  batch)
-        (put-bytevector p (get))
-        (force-output p))
+        (catch #t
+          (lambda ()
+            (for-each (cut write-request <> buffer)
+                      batch)
+            (put-bytevector p (get))
+            (force-output p))
+          (lambda (key . args)
+            ;; If PORT becomes unusable, open a fresh connection and
+            ;; retry.
+            (if (or (and (eq? key 'system-error)
+                         (= EPIPE (system-error-errno `(,key ,@args))))
+                    (and (eq? key 'gnutls-error)
+                         (eq? (first args) error/invalid-session)))
+                (begin
+                  (close-port p)    ; close the broken port
+                  (connect #f
+                           requests
+                           result))
+                (apply throw key args)))))
 
       ;; Now start processing responses.
       (let loop ((sent      batch)
@@ -199,20 +215,42 @@ returning."
              (remainder
               (connect p remainder result))))
           ((head tail ...)
-           (let* ((resp   (read-response p))
-                  (body   (response-body-port resp))
-                  (result (proc head resp body result)))
-             ;; The server can choose to stop responding at any time, in which
-             ;; case we have to try again.  Check whether that is the case.
-             ;; Note that even upon "Connection: close", we can read from BODY.
-             (match (assq 'connection (response-headers resp))
-               (('connection 'close)
-                (close-port p)
-                (connect #f                       ;try again
-                         (drop requests (+ 1 processed))
-                         result))
-               (_
-                (loop tail (+ 1 processed) result)))))))))) ;keep going
+           (catch #t
+             (lambda ()
+               (let* ((resp   (read-response p))
+                      (body   (response-body-port resp))
+                      (result (proc head resp body result)))
+                 ;; The server can choose to stop responding at any time,
+                 ;; in which case we have to try again.  Check whether
+                 ;; that is the case.  Note that even upon "Connection:
+                 ;; close", we can read from BODY.
+                 (match (assq 'connection (response-headers resp))
+                   (('connection 'close)
+                    (close-port p)
+                    (connect #f                       ;try again
+                             (drop requests (+ 1 processed))
+                             result))
+                   (_
+                    (loop tail (+ 1 processed) result))))) ;keep going
+             (lambda (key . args)
+               ;; If PORT was cached and the server closed the connection
+               ;; in the meantime, we get EPIPE.  In that case, open a
+               ;; fresh connection and retry.  We might also get
+               ;; 'bad-response or a similar exception from (web response)
+               ;; later on, once we've sent the request, or a
+               ;; ERROR/INVALID-SESSION from GnuTLS.
+               (if (or (and (eq? key 'system-error)
+                            (= EPIPE (system-error-errno `(,key ,@args))))
+                       (and (eq? key 'gnutls-error)
+                            (eq? (first args) error/invalid-session))
+                       (memq key
+                             '(bad-response bad-header bad-header-component)))
+                   (begin
+                     (close-port p)
+                     (connect #f      ; try again
+                              (drop requests (+ 1 processed))
+                              result))
+                   (apply throw key args))))))))))
 
 \f
 ;;;
-- 
2.30.0





  parent reply	other threads:[~2021-02-13 13:49 UTC|newest]

Thread overview: 56+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-12-24 17:17 [bug#45409] [PATCH 0/3] Move some (guix scripts substitute) code to two new modules Christopher Baines
2020-12-24 17:22 ` [bug#45409] [PATCH 1/3] guix: Move narinfo code from substitute script to module Christopher Baines
2020-12-24 17:22   ` [bug#45409] [PATCH 2/3] guix: Untangle (guix narinfo) from (guix scripts substitute) Christopher Baines
2020-12-24 17:22   ` [bug#45409] [PATCH 3/3] guix: Split (guix substitute) " Christopher Baines
2021-01-03 15:08     ` Ludovic Courtès
2021-01-03 18:19       ` Christopher Baines
2021-01-03 15:03   ` [bug#45409] [PATCH 1/3] guix: Move narinfo code from substitute script to module Ludovic Courtès
2021-01-03 18:16     ` Christopher Baines
2021-01-04 21:24       ` Christopher Baines
2021-01-03 17:59 ` [bug#45409] [PATCH v2 1/3] substitute: Untangle skipping authentication from valid-narinfo? Christopher Baines
2021-01-03 17:59   ` [bug#45409] [PATCH v2 2/3] guix: Move narinfo code from substitute script to module Christopher Baines
2021-01-03 17:59   ` [bug#45409] [PATCH v2 3/3] guix: Split (guix substitutes) from (guix scripts substitute) Christopher Baines
2021-01-04 21:19 ` [bug#45409] [PATCH v3 1/3] substitute: Untangle skipping authentication from valid-narinfo? Christopher Baines
2021-01-04 21:19   ` [bug#45409] [PATCH v3 2/3] guix: Move narinfo code from substitute script to module Christopher Baines
2021-01-05 21:58     ` Ludovic Courtès
2021-01-04 21:19   ` [bug#45409] [PATCH v3 3/3] guix: Split (guix substitutes) from (guix scripts substitute) Christopher Baines
2021-01-05 22:03     ` Ludovic Courtès
2021-01-07 22:29       ` Christopher Baines
2021-01-11 13:26         ` Ludovic Courtès
2021-01-16 14:18           ` Christopher Baines
2021-02-13 13:56             ` Christopher Baines
2021-02-22 22:21               ` Christopher Baines
2021-02-23 20:46                 ` Christopher Baines
2021-01-05 21:57   ` [bug#45409] [PATCH v3 1/3] substitute: Untangle skipping authentication from valid-narinfo? Ludovic Courtès
2021-01-05 22:58     ` Christopher Baines
2021-01-06  8:37       ` Ludovic Courtès
2021-01-16 13:57 ` [bug#45409] [PATCH v4 01/13] substitute: Remove buffer handling from fetch Christopher Baines
2021-01-16 13:57   ` [bug#45409] [PATCH v4 02/13] substitute: Remove connection " Christopher Baines
2021-01-16 13:57   ` [bug#45409] [PATCH v4 03/13] substitute: Remove redundant let block " Christopher Baines
2021-01-16 13:57   ` [bug#45409] [PATCH v4 04/13] guix: Move http-multiple-get to (guix http-client) Christopher Baines
2021-01-16 13:57   ` [bug#45409] [PATCH v4 05/13] http-client: Add error handling to http-multiple-get Christopher Baines
2021-01-16 13:57   ` [bug#45409] [PATCH v4 06/13] substitute: open-connection-for-uri/maybe add #:verify-certificate? Christopher Baines
2021-01-16 13:57   ` [bug#45409] [PATCH v4 07/13] substitute: Stop using call-with-cached-connection in fetch-narinfos Christopher Baines
2021-01-16 13:57   ` [bug#45409] [PATCH v4 08/13] http-client: Accept #:open-connection in http-fetch Christopher Baines
2021-01-16 13:57   ` [bug#45409] [PATCH v4 09/13] substitute: Change connection cache handling in process-substitution Christopher Baines
2021-01-16 13:58   ` [bug#45409] [PATCH v4 10/13] substitute: Remove now redundant connection caching helpers Christopher Baines
2021-01-16 13:58   ` [bug#45409] [PATCH v4 11/13] substitute: Remove redundant fetch arguments Christopher Baines
2021-01-16 13:58   ` [bug#45409] [PATCH v4 12/13] substitute: Inline fetch in to process-substitutes Christopher Baines
2021-01-16 13:58   ` [bug#45409] [PATCH v4 13/13] substitute: Remove fetch-narinfos use open-connection-for-uri/maybe Christopher Baines
2021-02-13 13:47 ` [bug#45409] [PATCH v5 01/14] substitute: Remove buffer handling from fetch Christopher Baines
2021-02-13 13:47   ` [bug#45409] [PATCH v5 02/14] substitute: Remove connection " Christopher Baines
2021-02-13 13:47   ` [bug#45409] [PATCH v5 03/14] substitute: Remove redundant let block " Christopher Baines
2021-02-13 13:47   ` [bug#45409] [PATCH v5 04/14] guix: Move http-multiple-get to (guix http-client) Christopher Baines
2021-02-13 13:47   ` Christopher Baines [this message]
2021-02-13 13:47   ` [bug#45409] [PATCH v5 06/14] substitute: open-connection-for-uri/maybe add #:verify-certificate? Christopher Baines
2021-02-13 13:47   ` [bug#45409] [PATCH v5 07/14] substitute: Stop using call-with-cached-connection in fetch-narinfos Christopher Baines
2021-02-13 13:47   ` [bug#45409] [PATCH v5 08/14] http-client: Accept #:open-connection in http-fetch Christopher Baines
2021-02-13 13:47   ` [bug#45409] [PATCH v5 09/14] substitute: Change connection cache handling in process-substitution Christopher Baines
2021-02-13 13:47   ` [bug#45409] [PATCH v5 10/14] substitute: Remove now redundant connection caching helpers Christopher Baines
2021-02-13 13:47   ` [bug#45409] [PATCH v5 11/14] substitute: Remove redundant fetch arguments Christopher Baines
2021-02-13 13:47   ` [bug#45409] [PATCH v5 12/14] substitute: Inline fetch in to process-substitutes Christopher Baines
2021-02-13 13:47   ` [bug#45409] [PATCH v5 13/14] substitute: Remove fetch-narinfos use open-connection-for-uri/maybe Christopher Baines
2021-02-13 13:47   ` [bug#45409] [PATCH v5 14/14] substitute: Rework connection error handling Christopher Baines
2021-02-23 19:59 ` [bug#45409] [PATCH 1/2] guix: Split (guix substitutes) from (guix scripts substitute) Christopher Baines
2021-02-23 19:59   ` [bug#45409] [PATCH 2/2] substitute: Print backtraces to (current-error-port) Christopher Baines
2021-03-06  0:57 ` bug#45409: [PATCH 0/3] Move some (guix scripts substitute) code to two new modules Christopher Baines

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://guix.gnu.org/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210213134719.19625-5-mail@cbaines.net \
    --to=mail@cbaines.net \
    --cc=45409@debbugs.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/guix.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).