Fossil SCM

Allow server to emit up to 4 empty lines in the header before concluding the header is finished. RFC9112 "in the interests of robustness". From libfossil.

danshearer 2026-10-12 11:08 UTC trunk
Commit 973e3e972027c5a9c59890e4cb3b1288aa61654eb64c2ee4cfa8be2a788b121a
1 file changed +13 -1
+13 -1
--- src/http.c
+++ src/http.c
@@ -487,10 +487,11 @@
487487
Blob hdr; /* The HTTP request header */
488488
int closeConnection; /* True to close the connection when done */
489489
int iLength; /* Expected length of the reply payload */
490490
int rc = 0; /* Result code */
491491
int iHttpVersion; /* Which version of HTTP protocol server uses */
492
+ int nBlank = 0; /* Empty lines to skip after an interim reply */
492493
char *zLine; /* A single line of the reply header */
493494
int i; /* Loop counter */
494495
int isError = 0; /* True if the reply is an error message */
495496
int isCompressed = 1; /* True if the reply is compressed */
496497
int isChunked = 0; /* True if Transfer-Encoding: chunked */
@@ -597,11 +598,21 @@
597598
** Read and interpret the server reply
598599
*/
599600
closeConnection = 1;
600601
iLength = -1;
601602
iHttpVersion = -1;
602
- while( (zLine = transport_receive_line(&g.url))!=0 && zLine[0]!=0 ){
603
+ while( (zLine = transport_receive_line(&g.url))!=0 ){
604
+ if( zLine[0]==0 ){
605
+ if( nBlank>0 ){
606
+ /* A server may send an empty line after an interim reply,
607
+ ** before the status line of the final reply. */
608
+ nBlank--;
609
+ continue;
610
+ }
611
+ break;
612
+ }
613
+ nBlank = 0;
603614
if( mHttpFlags & HTTP_VERBOSE ){
604615
fossil_print("Read: [%s]\n", zLine);
605616
}
606617
if( zLine[0]==' ' || zLine[0]=='\t' ){
607618
/* A line starting with a space or tab continues the previous
@@ -618,10 +629,11 @@
618629
** "100 Continue". Skip the remaining header lines of the reply.
619630
** A 1xx reply has no body.) */
620631
while( (zLine = transport_receive_line(&g.url))!=0 && zLine[0]!=0 ){}
621632
iHttpVersion = -1; /* Ensures correct error msg if connection drops */
622633
if( zLine==0 ) goto write_err;
634
+ nBlank = 4;
623635
continue;
624636
}
625637
if( rc==401 ){
626638
if( fSeenHttpAuth++ < MAX_HTTP_AUTH ){
627639
if( g.zHttpAuth ){
628640
--- src/http.c
+++ src/http.c
@@ -487,10 +487,11 @@
487 Blob hdr; /* The HTTP request header */
488 int closeConnection; /* True to close the connection when done */
489 int iLength; /* Expected length of the reply payload */
490 int rc = 0; /* Result code */
491 int iHttpVersion; /* Which version of HTTP protocol server uses */
 
492 char *zLine; /* A single line of the reply header */
493 int i; /* Loop counter */
494 int isError = 0; /* True if the reply is an error message */
495 int isCompressed = 1; /* True if the reply is compressed */
496 int isChunked = 0; /* True if Transfer-Encoding: chunked */
@@ -597,11 +598,21 @@
597 ** Read and interpret the server reply
598 */
599 closeConnection = 1;
600 iLength = -1;
601 iHttpVersion = -1;
602 while( (zLine = transport_receive_line(&g.url))!=0 && zLine[0]!=0 ){
 
 
 
 
 
 
 
 
 
 
603 if( mHttpFlags & HTTP_VERBOSE ){
604 fossil_print("Read: [%s]\n", zLine);
605 }
606 if( zLine[0]==' ' || zLine[0]=='\t' ){
607 /* A line starting with a space or tab continues the previous
@@ -618,10 +629,11 @@
618 ** "100 Continue". Skip the remaining header lines of the reply.
619 ** A 1xx reply has no body.) */
620 while( (zLine = transport_receive_line(&g.url))!=0 && zLine[0]!=0 ){}
621 iHttpVersion = -1; /* Ensures correct error msg if connection drops */
622 if( zLine==0 ) goto write_err;
 
623 continue;
624 }
625 if( rc==401 ){
626 if( fSeenHttpAuth++ < MAX_HTTP_AUTH ){
627 if( g.zHttpAuth ){
628
--- src/http.c
+++ src/http.c
@@ -487,10 +487,11 @@
487 Blob hdr; /* The HTTP request header */
488 int closeConnection; /* True to close the connection when done */
489 int iLength; /* Expected length of the reply payload */
490 int rc = 0; /* Result code */
491 int iHttpVersion; /* Which version of HTTP protocol server uses */
492 int nBlank = 0; /* Empty lines to skip after an interim reply */
493 char *zLine; /* A single line of the reply header */
494 int i; /* Loop counter */
495 int isError = 0; /* True if the reply is an error message */
496 int isCompressed = 1; /* True if the reply is compressed */
497 int isChunked = 0; /* True if Transfer-Encoding: chunked */
@@ -597,11 +598,21 @@
598 ** Read and interpret the server reply
599 */
600 closeConnection = 1;
601 iLength = -1;
602 iHttpVersion = -1;
603 while( (zLine = transport_receive_line(&g.url))!=0 ){
604 if( zLine[0]==0 ){
605 if( nBlank>0 ){
606 /* A server may send an empty line after an interim reply,
607 ** before the status line of the final reply. */
608 nBlank--;
609 continue;
610 }
611 break;
612 }
613 nBlank = 0;
614 if( mHttpFlags & HTTP_VERBOSE ){
615 fossil_print("Read: [%s]\n", zLine);
616 }
617 if( zLine[0]==' ' || zLine[0]=='\t' ){
618 /* A line starting with a space or tab continues the previous
@@ -618,10 +629,11 @@
629 ** "100 Continue". Skip the remaining header lines of the reply.
630 ** A 1xx reply has no body.) */
631 while( (zLine = transport_receive_line(&g.url))!=0 && zLine[0]!=0 ){}
632 iHttpVersion = -1; /* Ensures correct error msg if connection drops */
633 if( zLine==0 ) goto write_err;
634 nBlank = 4;
635 continue;
636 }
637 if( rc==401 ){
638 if( fSeenHttpAuth++ < MAX_HTTP_AUTH ){
639 if( g.zHttpAuth ){
640

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button