Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Difference From 052390edaf04a5f5 To 9b686daeeda7b4ca
|
2026-07-25
| ||
| 13:00 | When fossil is behaving as an HTTP client, it always uses HTTP/1.1 and it is able to understand the "chunked" transfer-encoding. Also add support for URI values of the form "file://NAME.http-test" which read the HTTP reply text out of the file "NAME.http-test" in the local filesystem, for testing purposes. check-in: c3bd7c3a0e user: drh tags: trunk | |
| 12:57 | Enhance the transport layer such that on an HTTP request to file:// where the pathname ends with ".http-test" and a file with that pathname exists in the local filesystem, then the content of that file becomes the HTTP reply. Used for testing. Closed-Leaf check-in: b708acd2b8 user: drh tags: http1-1-chunked | |
| 11:11 | Fix an off-by-one error in the previous check-in check-in: 9b686daeed user: drh tags: http1-1-chunked | |
| 11:04 | Fix an integer overflow vulnerability. Shorten all source code lines to be no more than 80 characters. Do not select the "chunked" transfer encoding, if the last token of the transfer-encoding is some keyword that has "chunked" as a suffix, ex: "superchunked". check-in: 82723bf87c user: drh tags: http1-1-chunked | |
| 10:45 | Merge improved Blob overflow defensive code from trunk. check-in: 109a5e1a04 user: drh tags: http1-1-chunked | |
| 10:25 | Detect integer overflow in the blob_is_int() and blob_is_int64() routines. check-in: 052390edaf user: drh tags: trunk | |
| 10:04 | Harden the Blob object against integer overflow attacks. check-in: 4816e03320 user: drh tags: trunk | |
Changes to src/http.c.
| ︙ | |||
149 150 151 152 153 154 155 | 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 | - + + |
if( g.url.subpath ){
zPath = g.url.subpath;
}else if( g.url.path==0 || g.url.path[0]==0 ){
zPath = "/";
}else{
zPath = g.url.path;
}
|
| ︙ | |||
453 454 455 456 457 458 459 460 461 462 463 464 465 466 | 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 | + |
int iLength; /* Expected length of the reply payload */
int rc = 0; /* Result code */
int iHttpVersion; /* Which version of HTTP protocol server uses */
char *zLine; /* A single line of the reply header */
int i; /* Loop counter */
int isError = 0; /* True if the reply is an error message */
int isCompressed = 1; /* True if the reply is compressed */
int isChunked = 0; /* True if Transfer-Encoding: chunked */
if( g.zHttpCmd!=0 ){
/* Handle the --transport-command option for "fossil sync" and similar */
return http_exchange_external(pSend,pReply,mHttpFlags,zAltMimetype);
}
/* Activate the PATH= auxiliary argument to the ssh command if that
|
| ︙ | |||
603 604 605 606 607 608 609 610 611 612 613 614 615 616 | 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 | + + + + + + + |
goto write_err;
}
if( iHttpVersion<0 ) iHttpVersion = 1;
closeConnection = 0;
}else if( fossil_strnicmp(zLine, "content-length:", 15)==0 ){
for(i=15; fossil_isspace(zLine[i]); i++){}
iLength = atoi(&zLine[i]);
}else if( fossil_strnicmp(zLine, "transfer-encoding:", 18)==0 ){
/* RFC 7230: "chunked" must be the final transfer-coding so only
** match when it appears at the end of the line. */
if( sqlite3_strlike("%chunked", &zLine[18], 0)==0 ){
size_t nx = strlen(&zLine[18]);
if( !fossil_isalnum(zLine[nx+10]) ) isChunked = 1;
}
}else if( fossil_strnicmp(zLine, "connection:", 11)==0 ){
if( sqlite3_strlike("%close%", &zLine[11], 0)==0 ){
closeConnection = 1;
}else if( sqlite3_strlike("%keep-alive%", &zLine[11], 0)==0 ){
closeConnection = 0;
}
}else if( ( rc==301 || rc==302 || rc==307 || rc==308 ) &&
|
| ︙ | |||
733 734 735 736 737 738 739 | 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 | + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + |
goto write_err;
}
/*
** Extract the reply payload that follows the header
*/
blob_zero(pReply);
if( isChunked ){
/* Decode an HTTP/1.1 "Transfer-Encoding: chunked" reply body. Each
** chunk is a hex length on its own line (optionally followed by a
** ";extension" that is ignored), then that many payload bytes, then a
** bare CRLF. A zero-length chunk terminates the body, after which any
** trailer header lines are read and discarded up to the blank line. */
char *zChunk;
int sawTerminator = 0; /* True once the 0-length chunk is seen */
while( (zChunk = transport_receive_line(&g.url))!=0 && zChunk[0]!=0 ){
i64 nChunk; /* Size of this chunk in bytes (wide, unclamped) */
i64 nPrior; /* Bytes already in pReply (matches blob nUsed) */
char *zEnd = 0; /* End of the hex digits actually parsed */
while( fossil_isspace(zChunk[0]) ) zChunk++;
nChunk = strtoll(zChunk, &zEnd, 16);
if( zEnd==zChunk ){
/* No hex digit consumed: a blank or malformed chunk-size line, which
** is the symptom of a connection that closed mid-stream. Treat it as
** a truncated (failed) */
fossil_warning("chunked reply: missing or malformed chunk size");
goto write_err;
}
if( nChunk<0 || nChunk>0x7fffffff ){
/* Negative, or larger than we will ever accept in one chunk. */
fossil_warning("chunked reply: invalid chunk size");
goto write_err;
}
if( nChunk==0 ){
/* Final chunk: consume trailer lines up to the terminating blank. */
sawTerminator = 1;
while( (zChunk = transport_receive_line(&g.url))!=0 && zChunk[0]!=0 ){}
break;
}
nPrior = blob_size(pReply);
/* Reserve space without advancing nUsed, so that on error
** the blob's reported size equals the bytes actually
** received rather the claimed chunk length */
blob_reserve(pReply, (u64)(nPrior+nChunk));
{
unsigned int nRemaining = (unsigned int)nChunk;
/* transport_receive() may return short; loop until the chunk is
** full. */
while( nRemaining>0 ){
int nGot;
nGot = transport_receive(&g.url, &pReply->aData[nPrior], nRemaining);
if( nGot<=0 ){
fossil_warning("chunked reply truncated");
goto write_err;
}
nPrior += nGot;
nRemaining -= nGot;
pReply->nUsed = (unsigned int)nPrior;
}
}
transport_receive_line(&g.url); /* CRLF that follows the chunk data */
}
if( !sawTerminator ){
/* The loop exited without ever seeing the 0-length terminator chunk,
** meaning the peer closed before the body was complete. A truncated
** sync must be an error, never silent success. */
fossil_warning("chunked reply ended without terminator");
goto write_err;
}
|
| ︙ |