diff options
author | Stefan Eissing <stefan@eissing.org> | 2023-04-13 11:03:50 +0200 |
---|---|---|
committer | Daniel Stenberg <daniel@haxx.se> | 2023-04-13 23:53:36 +0200 |
commit | be800a6cabe5c3e8968549b3481ddc5d73f12721 (patch) | |
tree | 89e6cd750cfec5aaecb9e214bb814796fc4c8287 /lib/vquic/curl_quiche.c | |
parent | 7e68133d041376c1012571e5a2386bb03a620a8e (diff) | |
download | curl-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.c | 58 |
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: |