CURLcode result = CURLE_OK;
if(0 == k->bodywrites) {
- bool done = FALSE;
#if defined(USE_NTLM)
struct connectdata *conn = data->conn;
if(conn->bits.close &&
}
if(data->state.hconnect && (data->req.httpcode/100 != 2) &&
data->state.authproxy.done) {
- done = TRUE;
+ data->req.done = TRUE;
result = CURLE_OK;
}
else
- result = Curl_http_firstwrite(data, data->conn, &done);
- if(result || done) {
+ result = Curl_http_firstwrite(data);
+ if(result || data->req.done) {
infof(data, "Return early from hyper_body_chunk");
data->state.hresult = result;
return HYPER_ITER_BREAK;
CURLcode Curl_hyper_stream(struct Curl_easy *data,
struct connectdata *conn,
int *didwhat,
- bool *done,
int select_res)
{
hyper_response *resp = NULL;
h->write_waker = NULL;
}
- *done = FALSE;
do {
hyper_task_return_type t;
task = hyper_executor_poll(h->exec);
break;
}
}
- *done = TRUE;
+ data->req.done = TRUE;
hyper_error_free(hypererr);
break;
}
hyper_task_free(task);
if((userdata_t)userdata == USERDATA_RESP_BODY) {
/* end of transfer */
- *done = TRUE;
+ data->req.done = TRUE;
infof(data, "hyperstream is done");
if(!k->bodywrites) {
/* hyper doesn't always call the body write callback */
- bool stilldone;
- result = Curl_http_firstwrite(data, data->conn, &stilldone);
+ result = Curl_http_firstwrite(data);
}
break;
}
CURLcode Curl_hyper_stream(struct Curl_easy *data,
struct connectdata *conn,
int *didwhat,
- bool *done,
int select_res);
CURLcode Curl_hyper_header(struct Curl_easy *data, hyper_headers *headers,
int didwhat;
(void)ts;
- *done = FALSE;
- result = Curl_hyper_stream(data, cf->conn, &didwhat, done,
+ result = Curl_hyper_stream(data, cf->conn, &didwhat,
CURL_CSELECT_IN | CURL_CSELECT_OUT);
+ *done = data->req.done;
if(result || !*done)
return result;
if(h->exec) {
* If the other side indicated a connection close, or if someone
* else told us to close this connection, do so now.
*/
+ Curl_req_soft_reset(&data->req, data);
if(ts->close_connection || conn->bits.close) {
/* Close this filter and the sub-chain, re-connect the
* sub-chain and continue. Closing this filter will
*done = (result == CURLE_OK) && tunnel_is_established(cf->ctx);
if(*done) {
cf->connected = TRUE;
- /* Restore `data->req` fields that may habe been touched */
- data->req.header = TRUE; /* assume header */
- data->req.bytecount = 0;
- data->req.ignorebody = FALSE;
+ /* The real request will follow the CONNECT, reset request partially */
+ Curl_req_soft_reset(&data->req, data);
Curl_client_reset(data);
Curl_pgrsSetUploadCounter(data, 0);
Curl_pgrsSetDownloadCounter(data, 0);
*/
void curl_easy_reset(struct Curl_easy *data)
{
- Curl_req_reset(&data->req, data);
+ Curl_req_hard_reset(&data->req, data);
/* zero out UserDefined data: */
Curl_freeset(data);
return CURLE_OK;
}
-CURLcode Curl_http_firstwrite(struct Curl_easy *data,
- struct connectdata *conn,
- bool *done)
+CURLcode Curl_http_firstwrite(struct Curl_easy *data)
{
+ struct connectdata *conn = data->conn;
struct SingleRequest *k = &data->req;
- *done = FALSE;
if(data->req.newurl) {
if(conn->bits.close) {
/* Abort after the headers if "follow Location" is set
and we're set to close anyway. */
k->keepon &= ~KEEP_RECV;
- *done = TRUE;
+ k->done = TRUE;
return CURLE_OK;
}
/* We have a new url to load, but since we want to be able to reuse this
streamclose(conn, "already downloaded");
/* Abort download */
k->keepon &= ~KEEP_RECV;
- *done = TRUE;
+ k->done = TRUE;
return CURLE_OK;
}
action for an HTTP/1.1 client */
if(!Curl_meets_timecondition(data, k->timeofdoc)) {
- *done = TRUE;
+ k->done = TRUE;
/* We're simulating an HTTP 304 from server so we return
what should have been returned from the server */
data->info.httpcode = 304;
*/
CURLcode Curl_http_write_resp_hds(struct Curl_easy *data,
const char *buf, size_t blen,
- size_t *pconsumed,
- bool *done)
+ size_t *pconsumed)
{
- *done = FALSE;
if(!data->req.header) {
*pconsumed = 0;
return CURLE_OK;
result = http_rw_headers(data, buf, blen, pconsumed);
if(!result && !data->req.header) {
/* we have successfully finished parsing the HEADERs */
- result = Curl_http_firstwrite(data, data->conn, done);
+ result = Curl_http_firstwrite(data);
if(!data->req.no_body && Curl_dyn_len(&data->state.headerb)) {
/* leftover from parsing something that turned out not
CURLcode Curl_http_write_resp(struct Curl_easy *data,
const char *buf, size_t blen,
- bool is_eos,
- bool *done)
+ bool is_eos)
{
CURLcode result;
size_t consumed;
int flags;
- *done = FALSE;
- result = Curl_http_write_resp_hds(data, buf, blen, &consumed, done);
- if(result || *done)
+ result = Curl_http_write_resp_hds(data, buf, blen, &consumed);
+ if(result || data->req.done)
goto out;
DEBUGASSERT(consumed <= blen);
#endif
CURLcode Curl_http_range(struct Curl_easy *data,
Curl_HttpReq httpreq);
-CURLcode Curl_http_firstwrite(struct Curl_easy *data,
- struct connectdata *conn,
- bool *done);
+CURLcode Curl_http_firstwrite(struct Curl_easy *data);
/* protocol-specific functions set up to be called by the main engine */
CURLcode Curl_http_setup_conn(struct Curl_easy *data,
curl_socket_t *socks);
CURLcode Curl_http_write_resp(struct Curl_easy *data,
const char *buf, size_t blen,
- bool is_eos,
- bool *done);
+ bool is_eos);
/* These functions are in http.c */
CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
CURLcode Curl_http_write_resp_hds(struct Curl_easy *data,
const char *buf, size_t blen,
- size_t *pconsumed,
- bool *done);
+ size_t *pconsumed);
/**
* Curl_http_output_auth() setups the authentication headers for the
struct Curl_easy *data,
const char *buf, size_t blen)
{
- bool done;
-
(void)cf;
- return Curl_xfer_write_resp(data, (char *)buf, blen, FALSE, &done);
+ return Curl_xfer_write_resp(data, (char *)buf, blen, FALSE);
}
static CURLcode on_stream_frame(struct Curl_cfilter *cf,
struct h2_stream_ctx *stream;
struct Curl_easy *data_s;
CURLcode result;
- bool done;
(void)flags;
DEBUGASSERT(stream_id); /* should never be a zero stream ID here */
if(!stream)
return NGHTTP2_ERR_CALLBACK_FAILURE;
- result = Curl_xfer_write_resp(data_s, (char *)mem, len, FALSE, &done);
+ result = Curl_xfer_write_resp(data_s, (char *)mem, len, FALSE);
if(result && result != CURLE_AGAIN)
return NGHTTP2_ERR_CALLBACK_FAILURE;
bool async;
bool protocol_connected = FALSE;
bool dophase_done = FALSE;
- bool done = FALSE;
CURLMcode rc;
CURLcode result = CURLE_OK;
timediff_t recv_timeout_ms;
}
/* read/write data if it is ready to do so */
- result = Curl_readwrite(data, &done);
+ result = Curl_readwrite(data);
- if(done || (result == CURLE_RECV_ERROR)) {
+ if(data->req.done || (result == CURLE_RECV_ERROR)) {
/* If CURLE_RECV_ERROR happens early enough, we assume it was a race
* condition and the server closed the reused connection exactly when
* we wanted to use it, so figure out if that is indeed the case.
/* if we are to retry, set the result to OK and consider the
request as done */
result = CURLE_OK;
- done = TRUE;
+ data->req.done = TRUE;
}
}
else if((CURLE_HTTP2_STREAM == result) &&
as done */
retry = TRUE;
result = CURLE_OK;
- done = TRUE;
+ data->req.done = TRUE;
}
else
result = ret;
Curl_posttransfer(data);
multi_done(data, result, TRUE);
}
- else if(done) {
+ else if(data->req.done) {
/* call this even if the readwrite function returned error */
Curl_posttransfer(data);
return CURLE_OK;
}
-CURLcode Curl_req_start(struct SingleRequest *req,
- struct Curl_easy *data)
+CURLcode Curl_req_soft_reset(struct SingleRequest *req,
+ struct Curl_easy *data)
{
CURLcode result;
- req->start = Curl_now();
+ req->done = FALSE;
+ req->upload_done = FALSE;
+ req->download_done = FALSE;
+ req->ignorebody = FALSE;
+ req->bytecount = 0;
+ req->writebytecount = 0;
+ req->header = TRUE; /* assume header */
+ req->headerline = 0;
+ req->headerbytecount = 0;
+ req->allheadercount = 0;
+ req->deductheadercount = 0;
+
result = Curl_client_start(data);
if(result)
return result;
return CURLE_OK;
}
+CURLcode Curl_req_start(struct SingleRequest *req,
+ struct Curl_easy *data)
+{
+ req->start = Curl_now();
+ return Curl_req_soft_reset(req, data);
+}
+
static CURLcode req_flush(struct Curl_easy *data);
CURLcode Curl_req_done(struct SingleRequest *req,
return CURLE_OK;
}
-void Curl_req_reset(struct SingleRequest *req, struct Curl_easy *data)
+void Curl_req_hard_reset(struct SingleRequest *req, struct Curl_easy *data)
{
struct curltime t0 = {0, 0};
unsigned char setcookies;
#endif
BIT(header); /* incoming data has HTTP header */
+ BIT(done); /* request is done, e.g. no more send/recv should
+ * happen. This can be TRUE before `upload_done` or
+ * `download_done` is TRUE. */
BIT(content_range); /* set TRUE if Content-Range: was found */
BIT(download_done); /* set to TRUE when download is complete */
BIT(eos_written); /* iff EOS has been written to client */
CURLcode Curl_req_init(struct SingleRequest *req);
/**
- * The request is about to start.
+ * The request is about to start. Record time and do a soft reset.
*/
CURLcode Curl_req_start(struct SingleRequest *req,
struct Curl_easy *data);
+/**
+ * The request may continue with a follow up. Reset
+ * members, but keep start time for overall duration calc.
+ */
+CURLcode Curl_req_soft_reset(struct SingleRequest *req,
+ struct Curl_easy *data);
+
/**
* The request is done. If not aborted, make sure that buffers are
* flushed to the client.
void Curl_req_free(struct SingleRequest *req, struct Curl_easy *data);
/**
- * Reset the state of the request for new use, given the
- * settings.
+ * Hard reset the state of the request to virgin state base on
+ * transfer settings.
*/
-void Curl_req_reset(struct SingleRequest *req, struct Curl_easy *data);
+void Curl_req_hard_reset(struct SingleRequest *req, struct Curl_easy *data);
#ifndef USE_HYPER
/**
static CURLcode rtsp_rtp_write_resp(struct Curl_easy *data,
const char *buf,
size_t blen,
- bool is_eos,
- bool *done);
+ bool is_eos);
static CURLcode rtsp_setup_connection(struct Curl_easy *data,
struct connectdata *conn);
static CURLcode rtsp_rtp_write_resp(struct Curl_easy *data,
const char *buf,
size_t blen,
- bool is_eos,
- bool *done)
+ bool is_eos)
{
struct rtsp_conn *rtspc = &(data->conn->proto.rtspc);
CURLcode result = CURLE_OK;
if(!data->req.header)
rtspc->in_header = FALSE;
- *done = FALSE;
if(!blen) {
goto out;
}
/* we want to parse headers, do so */
if(data->req.header && blen) {
rtspc->in_header = TRUE;
- result = Curl_http_write_resp_hds(data, buf, blen, &consumed, done);
+ result = Curl_http_write_resp_hds(data, buf, blen, &consumed);
if(result)
goto out;
}
if(rtspc->state != RTP_PARSE_SKIP)
- *done = FALSE;
+ data->req.done = FALSE;
/* we SHOULD have consumed all bytes, unless the response is borked.
* In which case we write out the left over bytes, letting the client
* writer deal with it (it will report EXCESS and fail the transfer). */
DEBUGF(infof(data, "rtsp_rtp_write_resp(len=%zu, in_header=%d, done=%d "
" rtspc->state=%d, req.size=%" CURL_FORMAT_CURL_OFF_T ")",
- blen, rtspc->in_header, *done, rtspc->state, data->req.size));
+ blen, rtspc->in_header, data->req.done, rtspc->state,
+ data->req.size));
if(!result && (is_eos || blen)) {
result = Curl_client_write(data, CLIENTWRITE_BODY|
(is_eos? CLIENTWRITE_EOS:0),
*/
static CURLcode readwrite_data(struct Curl_easy *data,
struct SingleRequest *k,
- int *didwhat, bool *done)
+ int *didwhat)
{
struct connectdata *conn = data->conn;
CURLcode result = CURLE_OK;
curl_off_t total_received = 0;
bool is_multiplex = FALSE;
- *done = FALSE;
-
result = Curl_multi_xfer_buf_borrow(data, &xfer_buf, &xfer_blen);
if(result)
goto out;
}
total_received += blen;
- result = Curl_xfer_write_resp(data, buf, blen, is_eos, done);
- if(result || *done)
+ result = Curl_xfer_write_resp(data, buf, blen, is_eos);
+ if(result || data->req.done)
goto out;
/* if we are done, we stop receiving. On multiplexed connections,
* Curl_readwrite() is the low-level function to be called when data is to
* be read and written to/from the connection.
*/
-CURLcode Curl_readwrite(struct Curl_easy *data,
- bool *done)
+CURLcode Curl_readwrite(struct Curl_easy *data)
{
struct connectdata *conn = data->conn;
struct SingleRequest *k = &data->req;
#ifdef USE_HYPER
if(conn->datastream) {
- result = conn->datastream(data, conn, &didwhat, done, select_bits);
- if(result || *done)
+ result = conn->datastream(data, conn, &didwhat, select_bits);
+ if(result || data->req.done)
goto out;
}
else {
the stream was rewound (in which case we have data in a
buffer) */
if((k->keepon & KEEP_RECV) && (select_bits & CURL_CSELECT_IN)) {
- result = readwrite_data(data, k, &didwhat, done);
- if(result || *done)
+ result = readwrite_data(data, k, &didwhat);
+ if(result || data->req.done)
goto out;
}
}
}
- /* Now update the "done" boolean we return */
- *done = (0 == (k->keepon&(KEEP_RECVBITS|KEEP_SENDBITS))) ? TRUE : FALSE;
+ /* If there is nothing more to send/recv, the request is done */
+ if(0 == (k->keepon&(KEEP_RECVBITS|KEEP_SENDBITS)))
+ data->req.done = TRUE;
+
out:
if(result)
DEBUGF(infof(data, "Curl_readwrite() -> %d", result));
data->state.url = newurl;
data->state.url_alloc = TRUE;
-
+ Curl_req_soft_reset(&data->req, data);
infof(data, "Issue another request to this URL: '%s'", data->state.url);
/*
CURLcode Curl_xfer_write_resp(struct Curl_easy *data,
char *buf, size_t blen,
- bool is_eos, bool *done)
+ bool is_eos)
{
CURLcode result = CURLE_OK;
if(data->conn->handler->write_resp) {
/* protocol handlers offering this function take full responsibility
* for writing all received download data to the client. */
- result = data->conn->handler->write_resp(data, buf, blen, is_eos, done);
+ result = data->conn->handler->write_resp(data, buf, blen, is_eos);
}
else {
/* No special handling by protocol handler, write all received data
CURLcode Curl_follow(struct Curl_easy *data, char *newurl,
followtype type);
-CURLcode Curl_readwrite(struct Curl_easy *data, bool *done);
+CURLcode Curl_readwrite(struct Curl_easy *data);
int Curl_single_getsock(struct Curl_easy *data,
struct connectdata *conn, curl_socket_t *socks);
CURLcode Curl_retry_request(struct Curl_easy *data, char **url);
*/
CURLcode Curl_xfer_write_resp(struct Curl_easy *data,
char *buf, size_t blen,
- bool is_eos, bool *done);
+ bool is_eos);
/* This sets up a forthcoming transfer */
void Curl_xfer_setup(struct Curl_easy *data,
*asyncp = FALSE; /* assume synchronous resolves by default */
- /* init the single-transfer specific data */
- Curl_req_reset(&data->req, data);
+ /* Set the request to virgin state based on transfer settings */
+ Curl_req_hard_reset(&data->req, data);
/* call the stuff that needs to be called */
result = create_conn(data, &conn, asyncp);
CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn)
{
- struct SingleRequest *k = &data->req;
-
/* if this is a pushed stream, we need this: */
CURLcode result = Curl_preconnect(data);
if(result)
if(result)
return result;
- k->header = TRUE; /* assume header */
- k->bytecount = 0;
- k->ignorebody = FALSE;
-
Curl_speedinit(data);
Curl_pgrsSetUploadCounter(data, 0);
Curl_pgrsSetDownloadCounter(data, 0);
typedef CURLcode (*Curl_datastream)(struct Curl_easy *data,
struct connectdata *conn,
int *didwhat,
- bool *done,
int select_res);
#endif
allow the protocol to do extra handling in writing response to
the client. */
CURLcode (*write_resp)(struct Curl_easy *data, const char *buf, size_t blen,
- bool is_eos, bool *done);
+ bool is_eos);
/* This function can perform various checks on the connection. See
CONNCHECK_* for more information about the checks that can be performed,
static CURLcode write_resp_hds(struct Curl_easy *data,
const char *buf, size_t blen)
{
- bool done;
- return Curl_xfer_write_resp(data, (char *)buf, blen, FALSE, &done);
+ return Curl_xfer_write_resp(data, (char *)buf, blen, FALSE);
}
static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream3_id,
struct Curl_easy *data = stream_user_data;
struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
CURLcode result;
- bool done;
(void)conn;
(void)stream3_id;
if(!stream)
return NGHTTP3_ERR_CALLBACK_FAILURE;
- result = Curl_xfer_write_resp(data, (char *)buf, blen, FALSE, &done);
+ result = Curl_xfer_write_resp(data, (char *)buf, blen, FALSE);
if(result) {
CURL_TRC_CF(data, cf, "[%" PRId64 "] DATA len=%zu, ERROR receiving %d",
stream->id, blen, result);