From: Stefan Eissing Date: Mon, 26 Aug 2024 08:56:28 +0000 (+0200) Subject: transfer: skip EOS read when download done X-Git-Tag: curl-8_10_0~103 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=29610e5f3d0c9f2643e098585be47d3fa8a86eea;p=thirdparty%2Fcurl.git transfer: skip EOS read when download done When we downloaded all we wanted, and we did not want a response body, and no Trailer: has been announced, and the receive gives EAGAIN, do not hang around unnecessarily. Some servers are buggy in HEAD processing and fail to send the HTTP/2 EOS. Since we do not need any more data, end the request right there. This will cause us to send a RST_STREAM to the server. Fixes #14670 Reported-by: Gruber Glass Closes #14685 --- diff --git a/lib/http.c b/lib/http.c index 15ca8fca84..e748aa55b0 100644 --- a/lib/http.c +++ b/lib/http.c @@ -3154,6 +3154,11 @@ CURLcode Curl_http_header(struct Curl_easy *data, } return CURLE_OK; } + v = HD_VAL(hd, hdlen, "Trailer:"); + if(v) { + data->req.resp_trailer = TRUE; + return CURLE_OK; + } break; case 'w': case 'W': diff --git a/lib/request.h b/lib/request.h index c1cf5f21fc..aba56be714 100644 --- a/lib/request.h +++ b/lib/request.h @@ -135,6 +135,7 @@ struct SingleRequest { BIT(http_bodyless); /* HTTP response status code is between 100 and 199, 204 or 304 */ BIT(chunk); /* if set, this is a chunked transfer-encoding */ + BIT(resp_trailer); /* response carried 'Trailer:' header field */ BIT(ignore_cl); /* ignore content-length */ BIT(upload_chunky); /* set TRUE if we are doing chunked transfer-encoding on upload */ diff --git a/lib/transfer.c b/lib/transfer.c index 360dfd887e..4c1cba1d21 100644 --- a/lib/transfer.c +++ b/lib/transfer.c @@ -306,11 +306,18 @@ static CURLcode sendrecv_dl(struct Curl_easy *data, nread = Curl_xfer_recv_resp(data, buf, bytestoread, is_multiplex, &result); if(nread < 0) { - if(CURLE_AGAIN == result) { - result = CURLE_OK; - break; /* get out of loop */ + if(CURLE_AGAIN != result) + goto out; /* real error */ + result = CURLE_OK; + if(data->req.download_done && data->req.no_body && + !data->req.resp_trailer) { + DEBUGF(infof(data, "EAGAIN, download done, no trailer announced, " + "not waiting for EOS")); + nread = 0; + /* continue as if we read the EOS */ } - goto out; /* real error */ + else + break; /* get out of loop */ } /* We only get a 0-length read on EndOfStream */