lib: further send/upload handling polish

- 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 #13010
This commit is contained in:
Stefan Eissing 2024-02-28 14:51:53 +01:00 committed by Daniel Stenberg
parent 46aea3d990
commit e3905de819
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
22 changed files with 485 additions and 535 deletions

View file

@ -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);
@ -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! */
@ -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:
@ -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:
@ -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;
@ -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;
@ -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 */
@ -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
@ -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 */
@ -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");
@ -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;
}
@ -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;