lib: Curl_read/Curl_write clarifications

- replace `Curl_read()`, `Curl_write()` and `Curl_nwrite()` to
  clarify when and at what level they operate
- send/recv of transfer related data is now done via
  `Curl_xfer_send()/Curl_xfer_recv()` which no longer has
  socket/socketindex as parameter. It decides on the transfer
  setup of `conn->sockfd` and `conn->writesockfd` on which
  connection filter chain to operate.
- send/recv on a specific connection filter chain is done via
  `Curl_conn_send()/Curl_conn_recv()` which get the socket index
  as parameter.
- rename `Curl_setup_transfer()` to `Curl_xfer_setup()` for
  naming consistency
- clarify that the special CURLE_AGAIN hangling to return
  `CURLE_OK` with length 0 only applies to `Curl_xfer_send()`
  and CURLE_AGAIN is returned by all other send() variants.
- fix a bug in websocket `curl_ws_recv()` that mixed up data
  when it arrived in more than a single chunk (to be made
  into a sperate PR, also)

Added as documented [in
CLIENT-READER.md](5b1f31dfba/docs/CLIENT-READERS.md).

- old `Curl_buffer_send()` completely replaced by new `Curl_req_send()`
- old `Curl_fillreadbuffer()` replaced with `Curl_client_read()`
- HTTP chunked uploads are now formatted in a client reader added when
  needed.
- FTP line-end conversions are done in a client reader added when
  needed.
- when sending requests headers, remaining buffer space is filled with
  body data for sending in "one go". This is independent of the request
  body size. Resolves #12938 as now small and large requests have the
  same code path.

Changes done to test cases:

- test513: now fails before sending request headers as this initial
  "client read" triggers the setup fault. Behaves now the same as in
  hyper build
- test547, test555, test1620: fix the length check in the lib code to
  only fail for reads *smaller* than expected. This was a bug in the
  test code that never triggered in the old implementation.

Closes #12969
This commit is contained in:
Stefan Eissing 2024-02-15 16:22:53 +01:00 committed by Daniel Stenberg
parent 8d67c61c47
commit 9369c30cd8
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
26 changed files with 1191 additions and 1021 deletions

View file

@ -241,6 +241,8 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
const char *p_userpwd = NULL;
*done = TRUE;
/* Initialize a dynamic send buffer */
Curl_dyn_init(&req_buffer, DYN_RTSP_REQ_HEADER);
rtsp->CSeq_sent = data->state.rtsp_next_client_CSeq;
rtsp->CSeq_recv = 0;
@ -311,8 +313,7 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
if(rtspreq == RTSPREQ_RECEIVE) {
Curl_xfer_setup(data, FIRSTSOCKET, -1, TRUE, -1);
return result;
goto out;
}
p_session_id = data->set.str[STRING_RTSP_SESSION_ID];
@ -320,7 +321,8 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
(rtspreq & ~(RTSPREQ_OPTIONS | RTSPREQ_DESCRIBE | RTSPREQ_SETUP))) {
failf(data, "Refusing to issue an RTSP request [%s] without a session ID.",
p_request);
return CURLE_BAD_FUNCTION_ARGUMENT;
result = CURLE_BAD_FUNCTION_ARGUMENT;
goto out;
}
/* Stream URI. Default to server '*' if not specified */
@ -347,7 +349,8 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
else {
failf(data,
"Refusing to issue an RTSP SETUP without a Transport: header.");
return CURLE_BAD_FUNCTION_ARGUMENT;
result = CURLE_BAD_FUNCTION_ARGUMENT;
goto out;
}
p_transport = data->state.aptr.rtsp_transport;
@ -366,9 +369,10 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
data->state.aptr.accept_encoding =
aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]);
if(!data->state.aptr.accept_encoding)
return CURLE_OUT_OF_MEMORY;
if(!data->state.aptr.accept_encoding) {
result = CURLE_OUT_OF_MEMORY;
goto out;
}
p_accept_encoding = data->state.aptr.accept_encoding;
}
}
@ -390,7 +394,7 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
result = Curl_http_output_auth(data, conn, p_request, HTTPREQ_GET,
p_stream_uri, FALSE);
if(result)
return result;
goto out;
p_proxyuserpwd = data->state.aptr.proxyuserpwd;
p_userpwd = data->state.aptr.userpwd;
@ -424,23 +428,22 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
*/
if(Curl_checkheaders(data, STRCONST("CSeq"))) {
failf(data, "CSeq cannot be set as a custom header.");
return CURLE_RTSP_CSEQ_ERROR;
result = CURLE_RTSP_CSEQ_ERROR;
goto out;
}
if(Curl_checkheaders(data, STRCONST("Session"))) {
failf(data, "Session ID cannot be set as a custom header.");
return CURLE_BAD_FUNCTION_ARGUMENT;
result = CURLE_BAD_FUNCTION_ARGUMENT;
goto out;
}
/* Initialize a dynamic send buffer */
Curl_dyn_init(&req_buffer, DYN_RTSP_REQ_HEADER);
result =
Curl_dyn_addf(&req_buffer,
"%s %s RTSP/1.0\r\n" /* Request Stream-URI RTSP/1.0 */
"CSeq: %ld\r\n", /* CSeq */
p_request, p_stream_uri, rtsp->CSeq_sent);
if(result)
return result;
goto out;
/*
* Rather than do a normal alloc line, keep the session_id unformatted
@ -449,7 +452,7 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
if(p_session_id) {
result = Curl_dyn_addf(&req_buffer, "Session: %s\r\n", p_session_id);
if(result)
return result;
goto out;
}
/*
@ -481,17 +484,17 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
Curl_safefree(data->state.aptr.userpwd);
if(result)
return result;
goto out;
if((rtspreq == RTSPREQ_SETUP) || (rtspreq == RTSPREQ_DESCRIBE)) {
result = Curl_add_timecondition(data, &req_buffer);
if(result)
return result;
goto out;
}
result = Curl_add_custom_headers(data, FALSE, &req_buffer);
if(result)
return result;
goto out;
if(rtspreq == RTSPREQ_ANNOUNCE ||
rtspreq == RTSPREQ_SET_PARAMETER ||
@ -500,13 +503,24 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
if(data->state.upload) {
putsize = data->state.infilesize;
data->state.httpreq = HTTPREQ_PUT;
result = Client_reader_set_fread(data, putsize);
if(result)
goto out;
}
else {
postsize = (data->state.infilesize != -1)?
data->state.infilesize:
(data->set.postfields? (curl_off_t)strlen(data->set.postfields):0);
data->state.httpreq = HTTPREQ_POST;
if(postsize > 0 && data->set.postfields)
result = Client_reader_set_buf(data, data->set.postfields,
(size_t)postsize);
else if(!postsize)
result = Client_reader_set_null(data);
else
result = Client_reader_set_fread(data, postsize);
if(result)
goto out;
}
if(putsize > 0 || postsize > 0) {
@ -518,7 +532,7 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
"Content-Length: %" CURL_FORMAT_CURL_OFF_T"\r\n",
(data->state.upload ? putsize : postsize));
if(result)
return result;
goto out;
}
if(rtspreq == RTSPREQ_SET_PARAMETER ||
@ -528,7 +542,7 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
STRCONST("Content-Type: "
"text/parameters\r\n"));
if(result)
return result;
goto out;
}
}
@ -538,7 +552,7 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
STRCONST("Content-Type: "
"application/sdp\r\n"));
if(result)
return result;
goto out;
}
}
@ -550,31 +564,27 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
data->req.no_body = TRUE;
}
}
else {
result = Client_reader_set_null(data);
if(result)
goto out;
}
/* RTSP never allows chunked transfer */
data->req.forbidchunk = TRUE;
/* Finish the request buffer */
result = Curl_dyn_addn(&req_buffer, STRCONST("\r\n"));
if(result)
return result;
if(postsize > 0) {
result = Curl_dyn_addn(&req_buffer, data->set.postfields,
(size_t)postsize);
if(result)
return result;
}
goto out;
/* issue the request */
result = Curl_req_send_hds(data, Curl_dyn_ptr(&req_buffer),
Curl_dyn_len(&req_buffer));
Curl_dyn_free(&req_buffer);
result = Curl_req_send(data, &req_buffer);
if(result) {
failf(data, "Failed sending RTSP request");
return result;
goto out;
}
Curl_xfer_setup(data, FIRSTSOCKET, -1, TRUE, putsize?FIRSTSOCKET:-1);
Curl_xfer_setup(data, FIRSTSOCKET, -1, TRUE, FIRSTSOCKET);
/* Increment the CSeq on success */
data->state.rtsp_next_client_CSeq++;
@ -586,7 +596,8 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
if(Curl_pgrsUpdate(data))
result = CURLE_ABORTED_BY_CALLBACK;
}
out:
Curl_dyn_free(&req_buffer);
return result;
}