http-client, substitute: Gracefully handle GnuTLS EAGAIN/EINTR.

Partly fixes <https://bugs.gnu.org/47867>.
Reported by Florian Pelz <pelzflorian@pelzflorian.de>.

In GnuTLS up to 3.7.1 included, GNUTLS_E_AGAIN and GNUTLS_E_INTERRUPTED
are not handled by 'write_to_session_record_port' and could be thrown at
the caller.  This patch works around that by dropping connections
altogether and restarting when this happens.

* guix/http-client.scm (false-if-networking-error): Swallow ERROR/AGAIN
and ERROR/INTERRUPTED.
* guix/scripts/substitute.scm (call-with-cached-connection): Likewise.
This commit is contained in:
Ludovic Courtès 2021-04-24 17:59:14 +02:00
parent f06685a985
commit 69ffe875c3
No known key found for this signature in database
GPG key ID: 090B11993D9AEBB5
2 changed files with 18 additions and 4 deletions

View file

@ -38,7 +38,7 @@ (define-module (guix http-client)
#:use-module (guix utils) #:use-module (guix utils)
#:use-module (guix base64) #:use-module (guix base64)
#:autoload (gcrypt hash) (sha256) #:autoload (gcrypt hash) (sha256)
#:autoload (gnutls) (error/invalid-session) #:autoload (gnutls) (error/invalid-session error/again error/interrupted)
#:use-module ((guix build utils) #:use-module ((guix build utils)
#:select (mkdir-p dump-port)) #:select (mkdir-p dump-port))
#:use-module ((guix build download) #:use-module ((guix build download)
@ -163,7 +163,14 @@ (define-syntax-rule (false-if-networking-error exp)
(if (or (and (eq? key 'system-error) (if (or (and (eq? key 'system-error)
(= EPIPE (system-error-errno `(,key ,@args)))) (= EPIPE (system-error-errno `(,key ,@args))))
(and (eq? key 'gnutls-error) (and (eq? key 'gnutls-error)
(eq? (first args) error/invalid-session)) (memq (first args)
(list error/invalid-session
;; XXX: These two are not properly handled in
;; GnuTLS < 3.7.2, in
;; 'write_to_session_record_port'; see
;; <https://bugs.gnu.org/47867>.
error/again error/interrupted)))
(memq key (memq key
'(bad-response bad-header bad-header-component))) '(bad-response bad-header bad-header-component)))
#f #f

View file

@ -45,7 +45,7 @@ (define-module (guix scripts substitute)
#:select (uri-abbreviation nar-uri-abbreviation #:select (uri-abbreviation nar-uri-abbreviation
(open-connection-for-uri (open-connection-for-uri
. guix:open-connection-for-uri))) . guix:open-connection-for-uri)))
#:autoload (gnutls) (error/invalid-session) #:autoload (gnutls) (error/invalid-session error/again error/interrupted)
#:use-module (guix progress) #:use-module (guix progress)
#:use-module ((guix build syscalls) #:use-module ((guix build syscalls)
#:select (set-thread-name)) #:select (set-thread-name))
@ -417,7 +417,14 @@ (define (call-with-cached-connection uri proc)
(if (or (and (eq? key 'system-error) (if (or (and (eq? key 'system-error)
(= EPIPE (system-error-errno `(,key ,@args)))) (= EPIPE (system-error-errno `(,key ,@args))))
(and (eq? key 'gnutls-error) (and (eq? key 'gnutls-error)
(eq? (first args) error/invalid-session)) (memq (first args)
(list error/invalid-session
;; XXX: These two are not properly handled in
;; GnuTLS < 3.7.2, in
;; 'write_to_session_record_port'; see
;; <https://bugs.gnu.org/47867>.
error/again error/interrupted)))
(memq key '(bad-response bad-header bad-header-component))) (memq key '(bad-response bad-header bad-header-component)))
(proc (open-connection-for-uri/cached uri (proc (open-connection-for-uri/cached uri
#:verify-certificate? #f #:verify-certificate? #f