]> git.feebdaed.xyz Git - 0xmirror/curl.git/commitdiff
http: when unfolding, leave single-space for new header line
authorDaniel Stenberg <daniel@haxx.se>
Thu, 18 Dec 2025 12:58:22 +0000 (13:58 +0100)
committerDaniel Stenberg <daniel@haxx.se>
Thu, 18 Dec 2025 16:41:46 +0000 (17:41 +0100)
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
lib/urldata.h
tests/data/test1274
tests/data/test1940

index fbedeeebcf5eeafd03fc81fbc8fc2ed72ae3bf0b..ea62219542ad3c28d33161695a0c022621ef6098 100644 (file)
@@ -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'.
index 062348233a74f7f3549837d896f21bcc692278b2..f3bdf372355322dbcdd03b0bb25dda54be04e07b 100644 (file)
@@ -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
 };
 
index 99d23ad8db213b1a67b2db897e50a0346935537c..2f40b5d69df72e5c31f28c37d4fcedb5befd7de6 100644 (file)
@@ -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
 
 </file>
 </verify>
index 8f2f73437de1f99783e106f663b7cfb2aafdb1f7..597adf851ba7510a8638a4139d3e05b4f1bb6bf8 100644 (file)
@@ -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
 </stdout>