mirror of
https://github.com/curl/curl.git
synced 2026-07-31 08:28:03 +03:00
http: expect 100 rework
Move all handling of HTTP's `Expect: 100-continue` feature into a client reader. Add sending flag `KEEP_SEND_TIMED` that triggers transfer sending on general events like a timer. HTTP installs a `CURL_CR_PROTOCOL` reader when announcing `Expect: 100-continue`. That reader works as follows: - on first invocation, records time, starts the `EXPIRE_100_TIMEOUT` timer, disables `KEEP_SEND`, enables `KEEP_SEND_TIMER` and returns 0, eos=FALSE like a paused upload. - on subsequent invocation it checks if the timer has expired. If so, it enables `KEEP_SEND` and switches to passing through reads to the underlying readers. Transfer handling's `readwrite()` will be invoked when a timer expires (like `EXPIRE_100_TIMEOUT`) or when data from the server arrives. Seeing `KEEP_SEND_TIMER`, it will try to upload more data, which triggers reading from the client readers again. Which then may lead to a new pausing or cause the upload to start. Flags and timestamps connected to this have been moved from `SingleRequest` into the reader's context. Closes #13110
This commit is contained in:
parent
3d0fd382a2
commit
80a3b830cc
17 changed files with 301 additions and 189 deletions
|
|
@ -463,7 +463,8 @@ CURLcode Curl_readwrite(struct Curl_easy *data)
|
|||
}
|
||||
|
||||
/* If we still have writing to do, we check if we have a writable socket. */
|
||||
if((k->keepon & KEEP_SEND) && (select_bits & CURL_CSELECT_OUT)) {
|
||||
if(((k->keepon & KEEP_SEND) && (select_bits & CURL_CSELECT_OUT)) ||
|
||||
(k->keepon & KEEP_SEND_TIMED)) {
|
||||
/* write */
|
||||
|
||||
result = readwrite_upload(data, &didwhat);
|
||||
|
|
@ -476,31 +477,6 @@ CURLcode Curl_readwrite(struct Curl_easy *data)
|
|||
|
||||
now = Curl_now();
|
||||
if(!didwhat) {
|
||||
/* no read no write, this is a timeout? */
|
||||
if(k->exp100 == EXP100_AWAITING_CONTINUE) {
|
||||
/* This should allow some time for the header to arrive, but only a
|
||||
very short time as otherwise it'll be too much wasted time too
|
||||
often. */
|
||||
|
||||
/* Quoting RFC2616, section "8.2.3 Use of the 100 (Continue) Status":
|
||||
|
||||
Therefore, when a client sends this header field to an origin server
|
||||
(possibly via a proxy) from which it has never seen a 100 (Continue)
|
||||
status, the client SHOULD NOT wait for an indefinite period before
|
||||
sending the request body.
|
||||
|
||||
*/
|
||||
|
||||
timediff_t ms = Curl_timediff(now, k->start100);
|
||||
if(ms >= data->set.expect_100_timeout) {
|
||||
/* we've waited long enough, continue anyway */
|
||||
k->exp100 = EXP100_SEND_DATA;
|
||||
k->keepon |= KEEP_SEND;
|
||||
Curl_expire_done(data, EXPIRE_100_TIMEOUT);
|
||||
infof(data, "Done waiting for 100-continue");
|
||||
}
|
||||
}
|
||||
|
||||
result = Curl_conn_ev_data_idle(data);
|
||||
if(result)
|
||||
goto out;
|
||||
|
|
@ -1172,36 +1148,8 @@ void Curl_xfer_setup(
|
|||
if(sockindex != -1)
|
||||
k->keepon |= KEEP_RECV;
|
||||
|
||||
if(writesockindex != -1) {
|
||||
/* HTTP 1.1 magic:
|
||||
|
||||
Even if we require a 100-return code before uploading data, we might
|
||||
need to write data before that since the REQUEST may not have been
|
||||
finished sent off just yet.
|
||||
|
||||
Thus, we must check if the request has been sent before we set the
|
||||
state info where we wait for the 100-return code
|
||||
*/
|
||||
if((data->state.expect100header) &&
|
||||
(conn->handler->protocol&PROTO_FAMILY_HTTP)) {
|
||||
/* wait with write until we either got 100-continue or a timeout */
|
||||
k->exp100 = EXP100_AWAITING_CONTINUE;
|
||||
k->start100 = Curl_now();
|
||||
|
||||
/* Set a timeout for the multi interface. Add the inaccuracy margin so
|
||||
that we don't fire slightly too early and get denied to run. */
|
||||
Curl_expire(data, data->set.expect_100_timeout, EXPIRE_100_TIMEOUT);
|
||||
}
|
||||
else {
|
||||
if(data->state.expect100header)
|
||||
/* when we've sent off the rest of the headers, we must await a
|
||||
100-continue but first finish sending the request */
|
||||
k->exp100 = EXP100_SENDING_REQUEST;
|
||||
|
||||
/* enable the write bit when we're not waiting for continue */
|
||||
k->keepon |= KEEP_SEND;
|
||||
}
|
||||
} /* if(writesockindex != -1) */
|
||||
if(writesockindex != -1)
|
||||
k->keepon |= KEEP_SEND;
|
||||
} /* if(k->getheader || !data->req.no_body) */
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue