mirror of
https://github.com/curl/curl.git
synced 2026-08-26 05:43:31 +03:00
transfer: cleanup done+excess handling
- add `SingleRequest->download_done` as indicator that all download bytes have been received - remove `stop_reading` bool from readwrite functions - move excess body handling into client download writer Closes #12371
This commit is contained in:
parent
03cb1ff4d6
commit
5b65e7d1ae
7 changed files with 121 additions and 128 deletions
122
lib/transfer.c
122
lib/transfer.c
|
|
@ -413,28 +413,6 @@ bool Curl_meets_timecondition(struct Curl_easy *data, time_t timeofdoc)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static size_t get_max_body_write_len(struct Curl_easy *data)
|
||||
{
|
||||
if(data->req.maxdownload != -1) {
|
||||
/* How much more are we allowed to write? */
|
||||
curl_off_t remain_diff;
|
||||
remain_diff = data->req.maxdownload - data->req.bytecount;
|
||||
if(remain_diff < 0) {
|
||||
/* already written too much! */
|
||||
return 0;
|
||||
}
|
||||
#if SIZEOF_CURL_OFF_T > SIZEOF_SIZE_T
|
||||
else if(remain_diff > SSIZE_T_MAX) {
|
||||
return SIZE_T_MAX;
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
return (size_t)remain_diff;
|
||||
}
|
||||
}
|
||||
return SIZE_T_MAX;
|
||||
}
|
||||
|
||||
/*
|
||||
* Go ahead and do a read if we have a readable socket or if
|
||||
* the stream was rewound (in which case we have data in a
|
||||
|
|
@ -450,8 +428,8 @@ static CURLcode readwrite_data(struct Curl_easy *data,
|
|||
bool *comeback)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
char *buf, *excess_data;
|
||||
size_t blen, hd_data_len, excess_len;
|
||||
char *buf;
|
||||
size_t blen;
|
||||
size_t consumed;
|
||||
int maxloops = 100;
|
||||
curl_off_t max_recv = data->set.max_recv_speed?
|
||||
|
|
@ -479,8 +457,6 @@ static CURLcode readwrite_data(struct Curl_easy *data,
|
|||
* all data read into it. */
|
||||
buf = data->state.buffer;
|
||||
blen = 0;
|
||||
excess_data = NULL;
|
||||
excess_len = 0;
|
||||
|
||||
/* If we are reading BODY data and the connection does NOT handle EOF
|
||||
* and we know the size of the BODY data, limit the read amount */
|
||||
|
|
@ -553,17 +529,28 @@ static CURLcode readwrite_data(struct Curl_easy *data,
|
|||
break;
|
||||
buf += consumed;
|
||||
blen -= consumed;
|
||||
if(k->download_done) {
|
||||
/* We've stopped dealing with input, get out of the do-while loop */
|
||||
if(blen > 0) {
|
||||
infof(data,
|
||||
"Excess found:"
|
||||
" excess = %zu"
|
||||
" url = %s (zero-length body)",
|
||||
blen, data->state.up.path);
|
||||
}
|
||||
|
||||
/* we make sure that this socket isn't read more now */
|
||||
k->keepon &= ~KEEP_RECV;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef CURL_DISABLE_HTTP
|
||||
/* Since this is a two-state thing, we check if we are parsing
|
||||
headers at the moment or not. */
|
||||
if(k->header) {
|
||||
bool stop_reading = FALSE;
|
||||
|
||||
consumed = 0;
|
||||
result = Curl_http_readwrite_headers(data, conn, buf, blen,
|
||||
&consumed, &stop_reading);
|
||||
result = Curl_http_readwrite_headers(data, conn, buf, blen, &consumed);
|
||||
if(result)
|
||||
goto out;
|
||||
buf += consumed;
|
||||
|
|
@ -583,7 +570,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
|
|||
blen -= consumed;
|
||||
}
|
||||
|
||||
if(stop_reading) {
|
||||
if(k->download_done) {
|
||||
/* We've stopped dealing with input, get out of the do-while loop */
|
||||
if(blen > 0) {
|
||||
infof(data,
|
||||
|
|
@ -593,6 +580,8 @@ static CURLcode readwrite_data(struct Curl_easy *data,
|
|||
blen, data->state.up.path);
|
||||
}
|
||||
|
||||
/* we make sure that this socket isn't read more now */
|
||||
k->keepon &= ~KEEP_RECV;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -671,56 +660,6 @@ static CURLcode readwrite_data(struct Curl_easy *data,
|
|||
}
|
||||
#endif /* CURL_DISABLE_HTTP */
|
||||
|
||||
/* If we know how much to download, have we reached the last bytes? */
|
||||
if(-1 != k->maxdownload) {
|
||||
size_t max_write_len = get_max_body_write_len(data);
|
||||
|
||||
/* Account for body content stillin the header buffer */
|
||||
hd_data_len = k->badheader? Curl_dyn_len(&data->state.headerb) : 0;
|
||||
if(blen + hd_data_len >= max_write_len) {
|
||||
/* We have all download bytes, but do we have too many? */
|
||||
excess_len = (blen + hd_data_len) - max_write_len;
|
||||
if(excess_len > 0 && !k->ignorebody) {
|
||||
infof(data,
|
||||
"Excess found in a read:"
|
||||
" excess = %zu"
|
||||
", size = %" CURL_FORMAT_CURL_OFF_T
|
||||
", maxdownload = %" CURL_FORMAT_CURL_OFF_T
|
||||
", bytecount = %" CURL_FORMAT_CURL_OFF_T,
|
||||
excess_len, k->size, k->maxdownload, k->bytecount);
|
||||
connclose(conn, "excess found in a read");
|
||||
}
|
||||
|
||||
if(!excess_len) {
|
||||
/* no excess bytes, perfect! */
|
||||
excess_data = NULL;
|
||||
}
|
||||
else if(hd_data_len >= excess_len) {
|
||||
/* uh oh, header body data already exceeds, the whole `buf`
|
||||
* is excess data */
|
||||
excess_len = blen;
|
||||
excess_data = buf;
|
||||
blen = 0;
|
||||
}
|
||||
else {
|
||||
/* `buf` bytes exceed, shorten and set `excess_data` */
|
||||
excess_len -= hd_data_len;
|
||||
DEBUGASSERT(blen >= excess_len);
|
||||
blen -= excess_len;
|
||||
excess_data = buf + blen;
|
||||
}
|
||||
|
||||
/* HTTP/3 over QUIC should keep reading until QUIC connection
|
||||
is closed. In contrast to HTTP/2 which can stop reading
|
||||
from TCP connection, HTTP/3 over QUIC needs ACK from server
|
||||
to ensure stream closure. It should keep reading. */
|
||||
if(!is_http3) {
|
||||
k->keepon &= ~KEEP_RECV; /* we're done reading */
|
||||
}
|
||||
k->download_done = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
max_recv -= blen;
|
||||
|
||||
if(!k->chunk && (blen || k->badheader || is_empty_data)) {
|
||||
|
|
@ -758,22 +697,15 @@ static CURLcode readwrite_data(struct Curl_easy *data,
|
|||
goto out;
|
||||
}
|
||||
|
||||
if(k->download_done && !is_http3) {
|
||||
/* HTTP/3 over QUIC should keep reading until QUIC connection
|
||||
is closed. In contrast to HTTP/2 which can stop reading
|
||||
from TCP connection, HTTP/3 over QUIC needs ACK from server
|
||||
to ensure stream closure. It should keep reading. */
|
||||
k->keepon &= ~KEEP_RECV; /* we're done reading */
|
||||
}
|
||||
} /* if(!header and data to read) */
|
||||
|
||||
if(conn->handler->readwrite && excess_data) {
|
||||
bool readmore = FALSE; /* indicates data is incomplete, need more */
|
||||
|
||||
consumed = 0;
|
||||
result = conn->handler->readwrite(data, conn, excess_data, excess_len,
|
||||
&consumed, &readmore);
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
if(readmore)
|
||||
k->keepon |= KEEP_RECV; /* we're not done reading */
|
||||
break;
|
||||
}
|
||||
|
||||
if(is_empty_data) {
|
||||
/* if we received nothing, the server closed the connection and we
|
||||
are done */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue