git: 0b731dee23f5 - main - ftp/curl: Fix HTTP2

From: Daniel Engberg <diizzy_at_FreeBSD.org>
Date: Sun, 15 Sep 2024 23:01:36 UTC
The branch main has been updated by diizzy:

URL: https://cgit.FreeBSD.org/ports/commit/?id=0b731dee23f5a6f23e7fd6e547ae42373ca0dbc9

commit 0b731dee23f5a6f23e7fd6e547ae42373ca0dbc9
Author:     Daniel Engberg <diizzy@FreeBSD.org>
AuthorDate: 2024-09-15 22:41:36 +0000
Commit:     Daniel Engberg <diizzy@FreeBSD.org>
CommitDate: 2024-09-15 23:01:21 +0000

    ftp/curl: Fix HTTP2
    
    Partially backport upstream commits
    70d3a9b6aa69ffdd9435e168463cfabd21e17cd1 and
    bef0acaf212a71c782e0b8e8e6c772cc46040356
    
    References:
    https://github.com/curl/curl/issues/14923
    https://github.com/curl/curl/commit/70d3a9b6aa69ffdd9435e168463cfabd21e17cd1
    https://github.com/curl/curl/commit/bef0acaf212a71c782e0b8e8e6c772cc46040356
    
    Approved by:    portmgr (blanket, runtime fix)
---
 ftp/curl/Makefile                                  |   1 +
 ...git-01-70d3a9b6aa69ffdd9435e168463cfabd21e17cd1 | 124 +++++++++++++++++++++
 ...git-02-bef0acaf212a71c782e0b8e8e6c772cc46040356 |  48 ++++++++
 3 files changed, 173 insertions(+)

diff --git a/ftp/curl/Makefile b/ftp/curl/Makefile
index d86c815b98e7..0eebfd2224dd 100644
--- a/ftp/curl/Makefile
+++ b/ftp/curl/Makefile
@@ -1,5 +1,6 @@
 PORTNAME=	curl
 PORTVERSION=	8.10.0
+PORTREVISION=	1
 CATEGORIES=	ftp net www
 MASTER_SITES=	https://curl.se/download/ \
 		https://github.com/curl/curl/releases/download/curl-${PORTVERSION:S|.|_|g}/
diff --git a/ftp/curl/files/patch-git-01-70d3a9b6aa69ffdd9435e168463cfabd21e17cd1 b/ftp/curl/files/patch-git-01-70d3a9b6aa69ffdd9435e168463cfabd21e17cd1
new file mode 100644
index 000000000000..aab6f77b6221
--- /dev/null
+++ b/ftp/curl/files/patch-git-01-70d3a9b6aa69ffdd9435e168463cfabd21e17cd1
@@ -0,0 +1,124 @@
+From 70d3a9b6aa69ffdd9435e168463cfabd21e17cd1 Mon Sep 17 00:00:00 2001
+From: Stefan Eissing <stefan@eissing.org>
+Date: Thu, 12 Sep 2024 10:03:33 +0200
+Subject: [PATCH] http2: when uploading data from stdin, fix eos forwarding
+
+When uploading data from stdin ('-T -'), and the EOS was only detected
+on a 0-length read, the EOS was not forwarded to the filters. This led
+HTTP/2 to hang on not forwarding this to the server.
+
+Added test_07_14 to reproduce and verify.
+
+Fixes #14870
+Reported-by: nekopsykose on github
+Closes #14877
+---
+ lib/http2.c                  |  9 ++++-----
+ lib/request.c                | 35 +++++++++++++++++++++++-----------
+ lib/request.h                |  1 +
+ lib/transfer.c               |  4 ++--
+ tests/http/test_07_upload.py | 37 ++++++++++++++++++++++++++++++++++++
+ 5 files changed, 68 insertions(+), 18 deletions(-)
+
+diff --git a/lib/http2.c b/lib/http2.c
+index bc50a2f7a7fe43..df3e6f0df38fbf 100644
+--- lib/http2.c
++++ lib/http2.c
+@@ -1679,12 +1679,11 @@ static ssize_t req_body_read_callback(nghttp2_session *session,
+   CURL_TRC_CF(data_s, cf, "[%d] req_body_read(len=%zu) eos=%d -> %zd, %d",
+               stream_id, length, stream->body_eos, nread, result);
+ 
+-  if(nread == 0)
+-    return NGHTTP2_ERR_DEFERRED;
+-  if(stream->body_eos && Curl_bufq_is_empty(&stream->sendbuf))
++  if(stream->body_eos && Curl_bufq_is_empty(&stream->sendbuf)) {
+     *data_flags = NGHTTP2_DATA_FLAG_EOF;
+-
+-  return nread;
++    return nread;
++  }
++  return (nread == 0)? NGHTTP2_ERR_DEFERRED : nread;
+ }
+ 
+ #if !defined(CURL_DISABLE_VERBOSE_STRINGS)
+diff --git a/lib/request.c b/lib/request.c
+index fb75e5577cdbb2..6b2784c3ff08e6 100644
+--- lib/request.c
++++ lib/request.c
+@@ -214,15 +214,19 @@ static CURLcode xfer_send(struct Curl_easy *data,
+     eos = TRUE;
+   }
+   result = Curl_xfer_send(data, buf, blen, eos, pnwritten);
+-  if(!result && *pnwritten) {
+-    if(hds_len)
+-      Curl_debug(data, CURLINFO_HEADER_OUT, (char *)buf,
+-                 CURLMIN(hds_len, *pnwritten));
+-    if(*pnwritten > hds_len) {
+-      size_t body_len = *pnwritten - hds_len;
+-      Curl_debug(data, CURLINFO_DATA_OUT, (char *)buf + hds_len, body_len);
+-      data->req.writebytecount += body_len;
+-      Curl_pgrsSetUploadCounter(data, data->req.writebytecount);
++  if(!result) {
++    if(eos && (blen == *pnwritten))
++      data->req.eos_sent = TRUE;
++    if(*pnwritten) {
++      if(hds_len)
++        Curl_debug(data, CURLINFO_HEADER_OUT, (char *)buf,
++                   CURLMIN(hds_len, *pnwritten));
++      if(*pnwritten > hds_len) {
++        size_t body_len = *pnwritten - hds_len;
++        Curl_debug(data, CURLINFO_DATA_OUT, (char *)buf + hds_len, body_len);
++        data->req.writebytecount += body_len;
++        Curl_pgrsSetUploadCounter(data, data->req.writebytecount);
++      }
+     }
+   }
+   return result;
+@@ -304,8 +308,17 @@ static CURLcode req_flush(struct Curl_easy *data)
+     return Curl_xfer_flush(data);
+   }
+ 
+-  if(!data->req.upload_done && data->req.eos_read &&
+-     Curl_bufq_is_empty(&data->req.sendbuf)) {
++  if(data->req.eos_read && !data->req.eos_sent) {
++    char tmp;
++    size_t nwritten;
++    result = xfer_send(data, &tmp, 0, 0, &nwritten);
++    if(result)
++      return result;
++    DEBUGASSERT(data->req.eos_sent);
++  }
++
++  if(!data->req.upload_done && data->req.eos_read && data->req.eos_sent) {
++    DEBUGASSERT(Curl_bufq_is_empty(&data->req.sendbuf));
+     if(data->req.shutdown) {
+       bool done;
+       result = Curl_xfer_send_shutdown(data, &done);
+diff --git a/lib/request.h b/lib/request.h
+index fb3f9f116815cd..c53c3eb5ae7e7f 100644
+--- lib/request.h
++++ lib/request.h
+@@ -130,6 +130,7 @@ struct SingleRequest {
+   BIT(download_done); /* set to TRUE when download is complete */
+   BIT(eos_written);   /* iff EOS has been written to client */
+   BIT(eos_read);      /* iff EOS has been read from the client */
++  BIT(eos_sent);      /* iff EOS has been sent to the server */
+   BIT(rewind_read);   /* iff reader needs rewind at next start */
+   BIT(upload_done);   /* set to TRUE when all request data has been sent */
+   BIT(upload_aborted); /* set to TRUE when upload was aborted. Will also
+diff --git a/lib/transfer.c b/lib/transfer.c
+index 0f42b3f2b4ddd6..ab8fd724314e4e 100644
+--- lib/transfer.c
++++ lib/transfer.c
+@@ -1253,8 +1253,8 @@ CURLcode Curl_xfer_send(struct Curl_easy *data,
+   else if(!result && *pnwritten)
+     data->info.request_size += *pnwritten;
+ 
+-  DEBUGF(infof(data, "Curl_xfer_send(len=%zu) -> %d, %zu",
+-               blen, result, *pnwritten));
++  DEBUGF(infof(data, "Curl_xfer_send(len=%zu, eos=%d) -> %d, %zu",
++               blen, eos, result, *pnwritten));
+   return result;
+ }
+ 
+
diff --git a/ftp/curl/files/patch-git-02-bef0acaf212a71c782e0b8e8e6c772cc46040356 b/ftp/curl/files/patch-git-02-bef0acaf212a71c782e0b8e8e6c772cc46040356
new file mode 100644
index 000000000000..ed3a5a0958bd
--- /dev/null
+++ b/ftp/curl/files/patch-git-02-bef0acaf212a71c782e0b8e8e6c772cc46040356
@@ -0,0 +1,48 @@
+From bef0acaf212a71c782e0b8e8e6c772cc46040356 Mon Sep 17 00:00:00 2001
+From: Stefan Eissing <stefan@eissing.org>
+Date: Fri, 13 Sep 2024 09:58:16 +0200
+Subject: [PATCH] request: correctly reset the eos_sent flag
+
+Add test cases
+
+Bug: https://marc.info/?l=git&m=172620452502747&w=2
+Reported-by: Patrick Steinhardt
+Closes #14895
+---
+ lib/request.c                                 |   5 +
+ tests/http/clients/.gitignore                 |   3 +-
+ tests/http/clients/Makefile.inc               |   3 +-
+ .../clients/{h2-download.c => hx-download.c}  |   0
+ tests/http/clients/hx-upload.c                | 568 ++++++++++++++++++
+ tests/http/test_02_download.py                |  12 +-
+ tests/http/test_07_upload.py                  |  61 ++
+ tests/http/test_19_shutdown.py                |   2 +-
+ 8 files changed, 645 insertions(+), 9 deletions(-)
+ rename tests/http/clients/{h2-download.c => hx-download.c} (100%)
+ create mode 100644 tests/http/clients/hx-upload.c
+
+diff --git a/lib/request.c b/lib/request.c
+index 6b2784c3ff08e6..1ddbdc9d0f1680 100644
+--- lib/request.c
++++ lib/request.c
+@@ -52,7 +52,11 @@ CURLcode Curl_req_soft_reset(struct SingleRequest *req,
+ 
+   req->done = FALSE;
+   req->upload_done = FALSE;
++  req->upload_aborted = FALSE;
+   req->download_done = FALSE;
++  req->eos_written = FALSE;
++  req->eos_read = FALSE;
++  req->eos_sent = FALSE;
+   req->ignorebody = FALSE;
+   req->shutdown = FALSE;
+   req->bytecount = 0;
+@@ -146,6 +150,7 @@ void Curl_req_hard_reset(struct SingleRequest *req, struct Curl_easy *data)
+   req->download_done = FALSE;
+   req->eos_written = FALSE;
+   req->eos_read = FALSE;
++  req->eos_sent = FALSE;
+   req->upload_done = FALSE;
+   req->upload_aborted = FALSE;
+   req->ignorebody = FALSE;
+