quiche: return CURLE_HTTP3 on send to invalid stream

Prior to this change if a send failed on a stream in an invalid state
(according to quiche) and not marked as closed (according to libcurl)
then the send function would return CURLE_SEND_ERROR.

We already have similar code for ngtcp2 to return CURLE_HTTP3 in this
case.

Caught by test test_07_upload.py: test_07_22_upload_parallel_fail.

Fixes https://github.com/curl/curl/issues/12590
Closes https://github.com/curl/curl/pull/12597
This commit is contained in:
Jay Satiro 2023-12-26 01:55:54 -05:00
parent 373d34494c
commit b83729a339
2 changed files with 29 additions and 14 deletions

View file

@ -1894,6 +1894,8 @@ static ssize_t cf_ngtcp2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
sent = (ssize_t)len;
goto out;
}
CURL_TRC_CF(data, cf, "[%" PRId64 "] send_body(len=%zu) "
"-> stream closed", stream->id, len);
*err = CURLE_HTTP3;
sent = -1;
goto out;

View file

@ -1078,6 +1078,28 @@ static ssize_t cf_quiche_send(struct Curl_cfilter *cf, struct Curl_easy *data,
goto out;
stream = H3_STREAM_CTX(data);
}
else if(stream->closed) {
if(stream->resp_hds_complete) {
/* sending request body on a stream that has been closed by the
* server. If the server has send us a final response, we should
* silently discard the send data.
* This happens for example on redirects where the server, instead
* of reading the full request body just closed the stream after
* sending the 30x response.
* This is sort of a race: had the transfer loop called recv first,
* it would see the response and stop/discard sending on its own- */
CURL_TRC_CF(data, cf, "[%" PRId64 "] discarding data"
"on closed stream with response", stream->id);
*err = CURLE_OK;
nwritten = (ssize_t)len;
goto out;
}
CURL_TRC_CF(data, cf, "[%" PRId64 "] send_body(len=%zu) "
"-> stream closed", stream->id, len);
*err = CURLE_HTTP3;
nwritten = -1;
goto out;
}
else {
bool eof = (stream->upload_left >= 0 &&
(curl_off_t)len >= stream->upload_left);
@ -1095,20 +1117,11 @@ static ssize_t cf_quiche_send(struct Curl_cfilter *cf, struct Curl_easy *data,
nwritten = -1;
goto out;
}
else if(nwritten == QUICHE_H3_TRANSPORT_ERR_INVALID_STREAM_STATE &&
stream->closed && stream->resp_hds_complete) {
/* sending request body on a stream that has been closed by the
* server. If the server has send us a final response, we should
* silently discard the send data.
* This happens for example on redirects where the server, instead
* of reading the full request body just closed the stream after
* sending the 30x response.
* This is sort of a race: had the transfer loop called recv first,
* it would see the response and stop/discard sending on its own- */
CURL_TRC_CF(data, cf, "[%" PRId64 "] discarding data"
"on closed stream with response", stream->id);
*err = CURLE_OK;
nwritten = (ssize_t)len;
else if(nwritten == QUICHE_H3_TRANSPORT_ERR_INVALID_STREAM_STATE) {
CURL_TRC_CF(data, cf, "[%" PRId64 "] send_body(len=%zu) "
"-> invalid stream state", stream->id, len);
*err = CURLE_HTTP3;
nwritten = -1;
goto out;
}
else if(nwritten == QUICHE_H3_TRANSPORT_ERR_FINAL_SIZE) {