transfer: readwrite improvements

- changed header/chunk/handler->readwrite prototypes to accept `buf`,
  `blen` and a `pconsumed` pointer. They now get the buffer to work on
  and report back how many bytes they consumed
- eliminated `k->str` in SingleRequest
- improved excess data handling to properly calculate with any body data
  left in the headerb buffer
- eliminated `k->badheader` enum to only be a bool

Closes #12283
This commit is contained in:
Stefan Eissing 2023-11-06 17:06:06 +01:00 committed by Daniel Stenberg
parent d9e7643ced
commit 1cd2f0072f
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
8 changed files with 269 additions and 246 deletions

View file

@ -3995,36 +3995,32 @@ CURLcode Curl_bump_headersize(struct Curl_easy *data,
*/
CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
struct connectdata *conn,
ssize_t *nread,
const char *buf, size_t blen,
size_t *pconsumed,
bool *stop_reading)
{
CURLcode result;
struct SingleRequest *k = &data->req;
ssize_t onread = *nread;
char *ostr = k->str;
char *headp;
char *str_start;
char *end_ptr;
/* header line within buffer loop */
*stop_reading = FALSE;
*pconsumed = 0;
do {
size_t rest_length;
size_t full_length;
size_t line_length;
int writetype;
/* str_start is start of line within buf */
str_start = k->str;
/* data is in network encoding so use 0x0a instead of '\n' */
end_ptr = memchr(str_start, 0x0a, *nread);
end_ptr = memchr(buf, 0x0a, blen);
if(!end_ptr) {
/* Not a complete header line within buffer, append the data to
the end of the headerbuff. */
result = Curl_dyn_addn(&data->state.headerb, str_start, *nread);
result = Curl_dyn_addn(&data->state.headerb, buf, blen);
if(result)
return result;
*pconsumed += blen;
if(!k->headerline) {
/* check if this looks like a protocol header */
@ -4036,31 +4032,28 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
if(st == STATUS_BAD) {
/* this is not the beginning of a protocol first header line */
k->header = FALSE;
k->badheader = HEADER_ALLBAD;
k->badheader = TRUE;
streamclose(conn, "bad HTTP: No end-of-message indicator");
if(!data->set.http09_allowed) {
failf(data, "Received HTTP/0.9 when not allowed");
return CURLE_UNSUPPORTED_PROTOCOL;
}
break;
goto out;
}
}
*nread = 0;
break; /* read more and try again */
goto out; /* read more and try again */
}
/* decrease the size of the remaining (supposed) header line */
rest_length = (end_ptr - k->str) + 1;
*nread -= (ssize_t)rest_length;
k->str = end_ptr + 1; /* move past new line */
full_length = k->str - str_start;
result = Curl_dyn_addn(&data->state.headerb, str_start, full_length);
line_length = (end_ptr - buf) + 1;
result = Curl_dyn_addn(&data->state.headerb, buf, line_length);
if(result)
return result;
blen -= line_length;
buf += line_length;
*pconsumed += line_length;
/****
* We now have a FULL header line in 'headerb'.
*****/
@ -4078,14 +4071,12 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
return CURLE_UNSUPPORTED_PROTOCOL;
}
k->header = FALSE;
if(*nread)
if(blen)
/* since there's more, this is a partial bad header */
k->badheader = HEADER_PARTHEADER;
k->badheader = TRUE;
else {
/* this was all we read so it's all a bad header */
k->badheader = HEADER_ALLBAD;
*nread = onread;
k->str = ostr;
k->badheader = TRUE;
return CURLE_OK;
}
break;
@ -4139,22 +4130,23 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
/* switch to http2 now. The bytes after response headers
are also processed here, otherwise they are lost. */
result = Curl_http2_upgrade(data, conn, FIRSTSOCKET,
k->str, *nread);
result = Curl_http2_upgrade(data, conn, FIRSTSOCKET, buf, blen);
if(result)
return result;
*nread = 0;
*pconsumed += blen;
blen = 0;
}
#ifdef USE_WEBSOCKETS
else if(k->upgr101 == UPGR101_WS) {
/* verify the response */
result = Curl_ws_accept(data, k->str, *nread);
result = Curl_ws_accept(data, buf, blen);
if(result)
return result;
k->header = FALSE; /* no more header to parse! */
if(data->set.connect_only) {
k->keepon &= ~KEEP_RECV; /* read no more content */
*nread = 0;
*pconsumed += blen;
blen = 0;
}
}
#endif
@ -4393,8 +4385,10 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
k->keepon &= ~KEEP_RECV;
}
Curl_debug(data, CURLINFO_HEADER_IN, str_start, headerlen);
break; /* exit header line loop */
Curl_debug(data, CURLINFO_HEADER_IN,
Curl_dyn_ptr(&data->state.headerb),
Curl_dyn_len(&data->state.headerb));
goto out; /* exit header line loop */
}
/* We continue reading headers, reset the line-based header */
@ -4583,12 +4577,12 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
Curl_dyn_reset(&data->state.headerb);
}
while(*k->str); /* header line within buffer */
while(blen);
/* We might have reached the end of the header part here, but
there might be a non-header part left in the end of the read
buffer. */
out:
return CURLE_OK;
}