From 9941e7c95bf26f00fd87888a37e9f2b4f4332c9f Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 18 Dec 2025 13:58:22 +0100 Subject: [PATCH] http: when unfolding, leave single-space for new header line Restore the unfolding behavior from before 67ae101666f10232. This change (leaving more whitespace in the delivered headers) turned out causing some friction in the git project so presumably others might also find it a little surprising. Reported-by: Jeff King Ref: https://marc.info/?l=git&m=176606332701171&w=2 Closes #20016 --- lib/http.c | 48 ++++++++++++++++++++++++++++++++++++--------- lib/urldata.h | 1 + tests/data/test1274 | 2 +- tests/data/test1940 | 2 +- 4 files changed, 42 insertions(+), 11 deletions(-) diff --git a/lib/http.c b/lib/http.c index fbedeeebcf..ea62219542 100644 --- a/lib/http.c +++ b/lib/http.c @@ -4296,11 +4296,14 @@ static void unfold_header(struct Curl_easy *data) { size_t len = curlx_dyn_len(&data->state.headerb); char *hd = curlx_dyn_ptr(&data->state.headerb); - if(len && (hd[len -1] == '\n')) + if(len && (hd[len - 1] == '\n')) len--; - if(len && (hd[len -1] == '\r')) + if(len && (hd[len - 1] == '\r')) + len--; + while(len && (ISBLANK(hd[len - 1]))) /* strip off trailing whitespace */ len--; curlx_dyn_setlen(&data->state.headerb, len); + data->state.leading_unfold = TRUE; } /* @@ -4379,14 +4382,41 @@ static CURLcode http_parse_headers(struct Curl_easy *data, goto out; /* read more and try again */ } - /* decrease the size of the remaining (supposed) header line */ + /* the size of the remaining (supposed) header line */ consumed = (end_ptr - buf) + 1; - result = curlx_dyn_addn(&data->state.headerb, buf, consumed); - if(result) - return result; - blen -= consumed; - buf += consumed; - *pconsumed += consumed; + + { + /* preserve the whole original header piece size */ + size_t header_piece = consumed; + + if(data->state.leading_unfold) { + /* immediately after an unfold, keep only a single whitespace */ + const size_t iblen = blen; + while(consumed && ISBLANK(buf[0])) { + consumed--; + buf++; + blen--; + } + if(consumed) { + if(iblen > blen) { + /* take one step back */ + consumed++; + buf--; + blen++; + } + data->state.leading_unfold = FALSE; /* done now */ + } + } + + if(consumed) { + result = curlx_dyn_addn(&data->state.headerb, buf, consumed); + if(result) + return result; + blen -= consumed; + buf += consumed; + } + *pconsumed += header_piece; + } /**** * We now have a FULL header line in 'headerb'. diff --git a/lib/urldata.h b/lib/urldata.h index 062348233a..f3bdf37235 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -1135,6 +1135,7 @@ struct UrlState { BIT(http_hd_upgrade); /* Added HTTP header Upgrade: */ BIT(http_hd_h2_settings); /* Added HTTP header H2Settings: */ BIT(maybe_folded); + BIT(leading_unfold); /* unfold started, this is the leading bytes */ #endif }; diff --git a/tests/data/test1274 b/tests/data/test1274 index 99d23ad8db..2f40b5d69d 100644 --- a/tests/data/test1274 +++ b/tests/data/test1274 @@ -55,7 +55,7 @@ Server: test-server/ fake folded Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT ETag: "21025-dc7-39462498" Content-Length: 6 -Connection:%repeat[46 x ]% close +Connection: close diff --git a/tests/data/test1940 b/tests/data/test1940 index 8f2f73437d..597adf851b 100644 --- a/tests/data/test1940 +++ b/tests/data/test1940 @@ -59,7 +59,7 @@ http://%HOSTIP:%HTTPPORT/%TESTNUMBER - Set-Cookie == onecookie=data; (0/3) - Set-Cookie == secondcookie=2data; (1/3) - Set-Cookie == cookie3=data3; (2/3) - Fold == is folding a line + Fold == is folding a line Blank ==%SP Blank2 ==%SP -- 2.43.0