Skip to content

Commit

Permalink
lib: further send/upload handling polish
Browse files Browse the repository at this point in the history
- Move all the "upload_done" handling to request.c

  - add possibility to abort sending of a request
  - add `Curl_req_done_sending()` for checks
  - transfer.c: readwrite_upload() now clean

- removing data->state.ulbuf and data->req.upload_fromhere

  - as well as data->req.upload_present
  - set data->req.upload_done on having read all from
    the client and completely flushed the send buffer

- tftp, remove setting of data->req.upload_fromhere

  - serves no purpose as `upload_present` is not set
    and the data itself is directly `sendto()` anyway

- smtp, make upload EOB conversion a client reader
- xfer_ulbuf addition

  - add xfer_ulbuf for borrowing, similar to xfer_buf
  - use in file upload
  - use in c-hyper body sending

- h1-proxy, remove init of data->state.uilbuf that is never used
- smb, add own send_buf instead of using data->state.ulbuf

Closes curl#13010
  • Loading branch information
icing authored and bagder committed Mar 4, 2024
1 parent 46aea3d commit e3905de
Show file tree
Hide file tree
Showing 22 changed files with 464 additions and 514 deletions.
54 changes: 30 additions & 24 deletions lib/c-hyper.c
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,7 @@ CURLcode Curl_hyper_stream(struct Curl_easy *data,
infof(data, "Got 417 while waiting for a 100");
data->state.disableexpect = TRUE;
data->req.newurl = strdup(data->state.url);
Curl_done_sending(data, k);
Curl_req_abort_sending(data);
}

result = status_line(data, conn,
Expand Down Expand Up @@ -663,7 +663,10 @@ static int uploadstreamed(void *userdata, hyper_context *ctx,
size_t fillcount;
struct Curl_easy *data = (struct Curl_easy *)userdata;
CURLcode result;
char *xfer_ulbuf;
size_t xfer_ulblen;
bool eos;
int rc = HYPER_POLL_ERROR;
(void)ctx;

if(data->req.exp100 > EXP100_SEND_DATA) {
Expand All @@ -677,39 +680,44 @@ static int uploadstreamed(void *userdata, hyper_context *ctx,
return HYPER_POLL_PENDING;
}

result = Curl_client_read(data, data->state.ulbuf,
data->set.upload_buffer_size,
&fillcount, &eos);
if(result) {
data->state.hresult = result;
return HYPER_POLL_ERROR;
}
result = Curl_multi_xfer_ulbuf_borrow(data, &xfer_ulbuf, &xfer_ulblen);
if(result)
goto out;

result = Curl_client_read(data, xfer_ulbuf, xfer_ulblen, &fillcount, &eos);
if(result)
goto out;

if(fillcount) {
hyper_buf *copy = hyper_buf_copy((uint8_t *)data->state.ulbuf, fillcount);
hyper_buf *copy = hyper_buf_copy((uint8_t *)xfer_ulbuf, fillcount);
if(copy)
*chunk = copy;
else {
data->state.hresult = CURLE_OUT_OF_MEMORY;
return HYPER_POLL_ERROR;
result = CURLE_OUT_OF_MEMORY;
goto out;
}
/* increasing the writebytecount here is a little premature but we
don't know exactly when the body is sent */
data->req.writebytecount += fillcount;
Curl_pgrsSetUploadCounter(data, data->req.writebytecount);
return HYPER_POLL_READY;
rc = HYPER_POLL_READY;
}
else if(eos) {
*chunk = NULL;
return HYPER_POLL_READY;
rc = HYPER_POLL_READY;
}
else {
/* paused, save a waker */
if(data->hyp.send_body_waker)
hyper_waker_free(data->hyp.send_body_waker);
data->hyp.send_body_waker = hyper_context_waker(ctx);
return HYPER_POLL_PENDING;
rc = HYPER_POLL_PENDING;
}

out:
Curl_multi_xfer_ulbuf_release(data, xfer_ulbuf);
data->state.hresult = result;
return rc;
}

/*
Expand All @@ -722,7 +730,6 @@ static CURLcode bodysend(struct Curl_easy *data,
hyper_request *hyperreq,
Curl_HttpReq httpreq)
{
struct HTTP *http = data->req.p.http;
CURLcode result = CURLE_OK;
struct dynbuf req;
if((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD))
Expand All @@ -731,29 +738,28 @@ static CURLcode bodysend(struct Curl_easy *data,
hyper_body *body;
Curl_dyn_init(&req, DYN_HTTP_REQUEST);
result = Curl_http_req_complete(data, &req, httpreq);
if(result)
return result;

if(!result)
/* if the "complete" above did produce more than the closing line,
parse the added headers */
if(Curl_dyn_len(&req) != 2 || strcmp(Curl_dyn_ptr(&req), "\r\n")) {
result = Curl_hyper_header(data, headers, Curl_dyn_ptr(&req));
if(result)
return result;
}

Curl_dyn_free(&req);

body = hyper_body_new();
hyper_body_set_userdata(body, data);
result = Curl_get_upload_buffer(data);
if(result) {
hyper_body_free(body);
return result;
}
/* init the "upload from here" pointer */
data->req.upload_fromhere = data->state.ulbuf;
hyper_body_set_data_func(body, uploadstreamed);

if(HYPERE_OK != hyper_request_set_body(hyperreq, body)) {
/* fail */
result = CURLE_OUT_OF_MEMORY;
}
}
http->sending = HTTPSEND_BODY;
return result;
}

Expand Down
6 changes: 0 additions & 6 deletions lib/cf-h1-proxy.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,18 +114,12 @@ static CURLcode tunnel_init(struct Curl_cfilter *cf,
struct h1_tunnel_state **pts)
{
struct h1_tunnel_state *ts;
CURLcode result;

if(cf->conn->handler->flags & PROTOPT_NOTCPPROXY) {
failf(data, "%s cannot be done over CONNECT", cf->conn->handler->scheme);
return CURLE_UNSUPPORTED_PROTOCOL;
}

/* we might need the upload buffer for streaming a partial request */
result = Curl_get_upload_buffer(data);
if(result)
return result;

ts = calloc(1, sizeof(*ts));
if(!ts)
return CURLE_OUT_OF_MEMORY;
Expand Down
16 changes: 8 additions & 8 deletions lib/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -291,8 +291,8 @@ static CURLcode file_upload(struct Curl_easy *data)
int fd;
int mode;
CURLcode result = CURLE_OK;
char *xfer_buf;
size_t xfer_blen;
char *xfer_ulbuf;
size_t xfer_ulblen;
curl_off_t bytecount = 0;
struct_stat file_stat;
const char *sendbuf;
Expand Down Expand Up @@ -340,7 +340,7 @@ static CURLcode file_upload(struct Curl_easy *data)
data->state.resume_from = (curl_off_t)file_stat.st_size;
}

result = Curl_multi_xfer_buf_borrow(data, &xfer_buf, &xfer_blen);
result = Curl_multi_xfer_ulbuf_borrow(data, &xfer_ulbuf, &xfer_ulblen);
if(result)
goto out;

Expand All @@ -349,7 +349,7 @@ static CURLcode file_upload(struct Curl_easy *data)
ssize_t nwrite;
size_t readcount;

result = Curl_client_read(data, xfer_buf, xfer_blen, &readcount, &eos);
result = Curl_client_read(data, xfer_ulbuf, xfer_ulblen, &readcount, &eos);
if(result)
break;

Expand All @@ -363,16 +363,16 @@ static CURLcode file_upload(struct Curl_easy *data)
if((curl_off_t)nread <= data->state.resume_from) {
data->state.resume_from -= nread;
nread = 0;
sendbuf = xfer_buf;
sendbuf = xfer_ulbuf;
}
else {
sendbuf = xfer_buf + data->state.resume_from;
sendbuf = xfer_ulbuf + data->state.resume_from;
nread -= (size_t)data->state.resume_from;
data->state.resume_from = 0;
}
}
else
sendbuf = xfer_buf;
sendbuf = xfer_ulbuf;

/* write the data to the target */
nwrite = write(fd, sendbuf, nread);
Expand All @@ -395,7 +395,7 @@ static CURLcode file_upload(struct Curl_easy *data)

out:
close(fd);
Curl_multi_xfer_buf_release(data, xfer_buf);
Curl_multi_xfer_ulbuf_release(data, xfer_ulbuf);

return result;
}
Expand Down
58 changes: 17 additions & 41 deletions lib/http.c
Original file line number Diff line number Diff line change
Expand Up @@ -1283,7 +1283,6 @@ CURLcode Curl_http_done(struct Curl_easy *data,
if(!http)
return CURLE_OK;

Curl_dyn_free(&http->send_buffer);
Curl_dyn_reset(&data->state.headerb);
Curl_hyper_done(data);
Curl_ws_done(data);
Expand Down Expand Up @@ -2151,6 +2150,12 @@ CURLcode Curl_http_req_complete(struct Curl_easy *data,
CURLcode result = CURLE_OK;
struct HTTP *http = data->req.p.http;

if(data->req.upload_chunky) {
result = Curl_httpchunk_add_reader(data);
if(result)
return result;
}

DEBUGASSERT(data->conn);
switch(httpreq) {
case HTTPREQ_PUT: /* Let's PUT the data to the server! */
Expand Down Expand Up @@ -2252,7 +2257,6 @@ CURLcode Curl_http_req_complete(struct Curl_easy *data,
data->state.in = (void *) data->state.mimepost;
result = Client_reader_set_fread(data, data->state.infilesize);
}
http->sending = HTTPSEND_BODY;
break;
#endif
case HTTPREQ_POST:
Expand Down Expand Up @@ -2294,19 +2298,21 @@ CURLcode Curl_http_req_complete(struct Curl_easy *data,
goto out;

if(!http->postsize) {
Curl_pgrsSetUploadSize(data, -1);
Curl_pgrsSetUploadSize(data, 0);
result = Client_reader_set_null(data);
}
else if(data->set.postfields) { /* we have the bytes */
else if(data->set.postfields) {
Curl_pgrsSetUploadSize(data, http->postsize);
result = Client_reader_set_buf(data, data->set.postfields,
(size_t)http->postsize);
if(http->postsize > 0)
result = Client_reader_set_buf(data, data->set.postfields,
(size_t)http->postsize);
else
result = Client_reader_set_null(data);
}
else { /* we read the bytes from the callback */
Curl_pgrsSetUploadSize(data, http->postsize);
result = Client_reader_set_fread(data, http->postsize);
}
http->sending = HTTPSEND_BODY;
break;

default:
Expand Down Expand Up @@ -2647,7 +2653,6 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
{
struct connectdata *conn = data->conn;
CURLcode result = CURLE_OK;
struct HTTP *http;
Curl_HttpReq httpreq;
const char *te = ""; /* transfer-encoding */
const char *request;
Expand Down Expand Up @@ -2699,9 +2704,6 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
if(result)
goto fail;

http = data->req.p.http;
DEBUGASSERT(http);

result = Curl_http_host(data, conn);
if(result)
goto fail;
Expand Down Expand Up @@ -2880,7 +2882,6 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
result = Curl_add_custom_headers(data, FALSE, &req);

if(!result) {
http->postdata = NULL; /* nothing to post at this point */
if((httpreq == HTTPREQ_GET) ||
(httpreq == HTTPREQ_HEAD))
Curl_pgrsSetUploadSize(data, 0); /* nothing */
Expand All @@ -2896,29 +2897,6 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
if(result)
goto fail;

if(data->req.writebytecount) {
/* if a request-body has been sent off, we make sure this progress is noted
properly */
Curl_pgrsSetUploadCounter(data, data->req.writebytecount);
if(Curl_pgrsUpdate(data))
result = CURLE_ABORTED_BY_CALLBACK;

if(!http->postsize) {
/* already sent the entire request body, mark the "upload" as
complete */
infof(data, "upload completely sent off: %" CURL_FORMAT_CURL_OFF_T
" out of %" CURL_FORMAT_CURL_OFF_T " bytes",
data->req.writebytecount, http->postsize);
data->req.upload_done = TRUE;
data->req.keepon &= ~KEEP_SEND; /* we're done writing */
data->req.exp100 = EXP100_SEND_DATA; /* already sent */
Curl_expire_done(data, EXPIRE_100_TIMEOUT);
}
}

if(data->req.upload_done)
Curl_conn_ev_data_done_send(data);

if((conn->httpversion >= 20) && data->req.upload_chunky)
/* upload_chunky was set above to set up the request in a chunky fashion,
but is disabled here again to avoid that the chunked encoded version is
Expand Down Expand Up @@ -3782,7 +3760,7 @@ static CURLcode http_rw_headers(struct Curl_easy *data,
* connection for closure after we've read the entire response.
*/
Curl_expire_done(data, EXPIRE_100_TIMEOUT);
if(!k->upload_done) {
if(!Curl_req_done_sending(data)) {
if((k->httpcode == 417) && data->state.expect100header) {
/* 417 Expectation Failed - try again without the Expect
header */
Expand All @@ -3801,7 +3779,7 @@ static CURLcode http_rw_headers(struct Curl_easy *data,
data->state.disableexpect = TRUE;
DEBUGASSERT(!data->req.newurl);
data->req.newurl = strdup(data->state.url);
Curl_done_sending(data, k);
Curl_req_abort_sending(data);
}
else if(data->set.http_keep_sending_on_error) {
infof(data, "HTTP error before end of send, keep sending");
Expand All @@ -3813,10 +3791,9 @@ static CURLcode http_rw_headers(struct Curl_easy *data,
else {
infof(data, "HTTP error before end of send, stop sending");
streamclose(conn, "Stop sending data before everything sent");
result = Curl_done_sending(data, k);
result = Curl_req_abort_sending(data);
if(result)
return result;
k->upload_done = TRUE;
if(data->state.expect100header)
k->exp100 = EXP100_FAILED;
}
Expand All @@ -3828,8 +3805,7 @@ static CURLcode http_rw_headers(struct Curl_easy *data,
}
}

if(data->state.rewindbeforesend &&
(conn->writesockfd != CURL_SOCKET_BAD)) {
if(data->state.rewindbeforesend && !Curl_req_done_sending(data)) {
/* We rewind before next send, continue sending now */
infof(data, "Keep sending data to get tossed away");
k->keepon |= KEEP_SEND;
Expand Down
17 changes: 0 additions & 17 deletions lib/http.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,27 +189,10 @@ CURLcode Curl_http_auth_act(struct Curl_easy *data);
***************************************************************************/
struct HTTP {
curl_off_t postsize; /* off_t to handle large file sizes */
const char *postdata;
struct back {
curl_read_callback fread_func; /* backup storage for fread pointer */
void *fread_in; /* backup storage for fread_in pointer */
const char *postdata;
curl_off_t postsize;
struct Curl_easy *data;
} backup;

enum {
HTTPSEND_NADA, /* init */
HTTPSEND_REQUEST, /* sending a request */
HTTPSEND_BODY /* sending body */
} sending;

#ifndef CURL_DISABLE_HTTP
void *h2_ctx; /* HTTP/2 implementation context */
void *h3_ctx; /* HTTP/3 implementation context */
struct dynbuf send_buffer; /* used if the request couldn't be sent in one
chunk, points to an allocated send_buffer
struct */
#endif
};

Expand Down
Loading

0 comments on commit e3905de

Please sign in to comment.