summaryrefslogtreecommitdiff
path: root/lib/vquic/curl_quiche.c
diff options
context:
space:
mode:
authorStefan Eissing <stefan@eissing.org>2023-04-13 11:03:50 +0200
committerDaniel Stenberg <daniel@haxx.se>2023-04-13 23:53:36 +0200
commitbe800a6cabe5c3e8968549b3481ddc5d73f12721 (patch)
tree89e6cd750cfec5aaecb9e214bb814796fc4c8287 /lib/vquic/curl_quiche.c
parent7e68133d041376c1012571e5a2386bb03a620a8e (diff)
downloadcurl-be800a6cabe5c3e8968549b3481ddc5d73f12721.tar.gz
http3: check stream_ctx more thoroughly in all backends
- callbacks and filter methods might be invoked at unexpected times, e.g. when the transfer's stream_ctx has not been initialized yet or, more likely, has already been taken down. - check for existance of stream_ctx in such places and return an error or silently succeed the call. Closes #10951
Diffstat (limited to 'lib/vquic/curl_quiche.c')
-rw-r--r--lib/vquic/curl_quiche.c58
1 files changed, 45 insertions, 13 deletions
diff --git a/lib/vquic/curl_quiche.c b/lib/vquic/curl_quiche.c
index 69a65f01b..31a7174bf 100644
--- a/lib/vquic/curl_quiche.c
+++ b/lib/vquic/curl_quiche.c
@@ -344,6 +344,8 @@ static CURLcode write_resp_raw(struct Curl_cfilter *cf,
ssize_t nwritten;
(void)cf;
+ if(!stream)
+ return CURLE_RECV_ERROR;
nwritten = Curl_bufq_write(&stream->recvbuf, mem, memlen, &result);
if(nwritten < 0)
return result;
@@ -390,7 +392,7 @@ static int cb_each_header(uint8_t *name, size_t name_len,
if(result) {
DEBUGF(LOG_CF(x->data, x->cf,
"[h3sid=%"PRId64"][HEADERS][%.*s: %.*s] error %d",
- stream->id, (int)name_len, name,
+ stream? stream->id : -1, (int)name_len, name,
(int)value_len, value, result));
}
return result;
@@ -405,6 +407,11 @@ static ssize_t stream_resp_read(void *reader_ctx,
struct stream_ctx *stream = H3_STREAM_CTX(x->data);
ssize_t nread;
+ if(!stream) {
+ *err = CURLE_RECV_ERROR;
+ return -1;
+ }
+
nread = quiche_h3_recv_body(ctx->h3c, ctx->qconn, stream->id,
buf, len);
if(nread >= 0) {
@@ -429,6 +436,9 @@ static CURLcode cf_recv_body(struct Curl_cfilter *cf,
struct cb_ctx cb_ctx;
CURLcode result = CURLE_OK;
+ if(!stream)
+ return CURLE_RECV_ERROR;
+
if(!stream->resp_hds_complete) {
result = write_resp_raw(cf, data, "\r\n", 2);
if(result)
@@ -486,6 +496,8 @@ static CURLcode h3_process_event(struct Curl_cfilter *cf,
CURLcode result = CURLE_OK;
int rc;
+ if(!stream)
+ return CURLE_OK;
DEBUGASSERT(stream3_id == stream->id);
switch(quiche_h3_event_type(ev)) {
case QUICHE_H3_EVENT_HEADERS:
@@ -764,6 +776,7 @@ static ssize_t recv_closed_stream(struct Curl_cfilter *cf,
struct stream_ctx *stream = H3_STREAM_CTX(data);
ssize_t nread = -1;
+ DEBUGASSERT(stream);
if(stream->reset) {
failf(data,
"HTTP/3 stream %" PRId64 " reset by server", stream->id);
@@ -798,6 +811,11 @@ static ssize_t cf_quiche_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
ssize_t nread = -1;
CURLcode result;
+ if(!stream) {
+ *err = CURLE_RECV_ERROR;
+ goto out;
+ }
+
if(!Curl_bufq_is_empty(&stream->recvbuf)) {
nread = Curl_bufq_read(&stream->recvbuf,
(unsigned char *)buf, len, err);
@@ -868,6 +886,14 @@ static ssize_t h3_open_stream(struct Curl_cfilter *cf,
quiche_h3_header *nva = NULL;
struct h2h3req *hreq = NULL;
+ if(!stream) {
+ *err = h3_data_setup(cf, data);
+ if(*err)
+ goto fail;
+ stream = H3_STREAM_CTX(data);
+ DEBUGASSERT(stream);
+ }
+
if(!stream->req_hds_len) {
stream->req_hds_len = len; /* fist call */
}
@@ -969,10 +995,11 @@ static ssize_t cf_quiche_send(struct Curl_cfilter *cf, struct Curl_easy *data,
goto out;
}
- if(stream->id < 0) {
+ if(!stream || stream->id < 0) {
nwritten = h3_open_stream(cf, data, buf, len, err);
if(nwritten < 0)
goto out;
+ stream = H3_STREAM_CTX(data);
}
else {
nwritten = quiche_h3_send_body(ctx->h3c, ctx->qconn, stream->id,
@@ -1019,7 +1046,7 @@ out:
nwritten = -1;
}
DEBUGF(LOG_CF(data, cf, "[h3sid=%" PRId64 "] cf_send(len=%zu) -> %zd, %d",
- stream->id, len, nwritten, *err));
+ stream? stream->id : -1, len, nwritten, *err));
return nwritten;
}
@@ -1028,10 +1055,13 @@ static bool stream_is_writeable(struct Curl_cfilter *cf,
{
struct cf_quiche_ctx *ctx = cf->ctx;
struct stream_ctx *stream = H3_STREAM_CTX(data);
+ quiche_stream_iter *qiter;
bool is_writable = FALSE;
+ if(!stream)
+ return FALSE;
/* surely, there must be a better way */
- quiche_stream_iter *qiter = quiche_conn_writable(ctx->qconn);
+ qiter = quiche_conn_writable(ctx->qconn);
if(qiter) {
uint64_t stream_id;
while(quiche_stream_iter_next(qiter, &stream_id)) {
@@ -1076,7 +1106,7 @@ static bool cf_quiche_data_pending(struct Curl_cfilter *cf,
{
const struct stream_ctx *stream = H3_STREAM_CTX(data);
(void)cf;
- return !Curl_bufq_is_empty(&stream->recvbuf);
+ return stream && !Curl_bufq_is_empty(&stream->recvbuf);
}
static CURLcode cf_quiche_data_event(struct Curl_cfilter *cf,
@@ -1098,14 +1128,16 @@ static CURLcode cf_quiche_data_event(struct Curl_cfilter *cf,
}
case CF_CTRL_DATA_DONE_SEND: {
struct stream_ctx *stream = H3_STREAM_CTX(data);
- unsigned char body[1];
- ssize_t sent;
- stream->upload_done = TRUE;
-
- body[0] = 'X';
- sent = cf_quiche_send(cf, data, body, 0, &result);
- DEBUGF(LOG_CF(data, cf, "[h3sid=%"PRId64"] DONE_SEND -> %zd, %d",
- stream->id, sent, result));
+ if(stream) {
+ unsigned char body[1];
+ ssize_t sent;
+ stream->upload_done = TRUE;
+
+ body[0] = 'X';
+ sent = cf_quiche_send(cf, data, body, 0, &result);
+ DEBUGF(LOG_CF(data, cf, "[h3sid=%"PRId64"] DONE_SEND -> %zd, %d",
+ stream->id, sent, result));
+ }
break;
}
case CF_CTRL_DATA_IDLE: