From: Stefan Eissing Date: Wed, 31 Jan 2024 15:30:54 +0000 (+0100) Subject: HTTP/2: write response directly X-Git-Tag: curl-8_7_0~230 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=0dc036225b3013bf994da81fa44571bcfcecbe92;p=thirdparty%2Fcurl.git HTTP/2: write response directly - use the new `Curl_xfer_write_resp()` to write incoming responses directly to the client - eliminates `stream->recvbuf` - memory consumption on parallel transfers minimized Closes #12828 --- diff --git a/lib/http2.c b/lib/http2.c index c3157d1ef2..cb765b54b5 100644 --- a/lib/http2.c +++ b/lib/http2.c @@ -169,10 +169,9 @@ static CURLcode h2_progress_egress(struct Curl_cfilter *cf, struct Curl_easy *data); /** - * All about the H3 internals of a stream + * All about the H2 internals of a stream */ -struct stream_ctx { - /*********** for HTTP/2 we store stream-local data here *************/ +struct h2_stream_ctx { int32_t id; /* HTTP/2 protocol identifier for stream */ struct bufq recvbuf; /* response buffer */ struct bufq sendbuf; /* request buffer */ @@ -181,6 +180,7 @@ struct stream_ctx { size_t resp_hds_len; /* amount of response header bytes in recvbuf */ size_t upload_blocked_len; curl_off_t upload_left; /* number of request bytes left to upload */ + curl_off_t nrcvd_data; /* number of DATA bytes received */ char **push_headers; /* allocated array */ size_t push_headers_used; /* number of entries filled in */ @@ -198,7 +198,8 @@ struct stream_ctx { buffered data in stream->sendbuf to upload. */ }; -#define H2_STREAM_CTX(d) ((struct stream_ctx *)(((d) && (d)->req.p.http)? \ +#define H2_STREAM_CTX(d) ((struct h2_stream_ctx *)(((d) && \ + (d)->req.p.http)? \ ((struct HTTP *)(d)->req.p.http)->h2_ctx \ : NULL)) #define H2_STREAM_LCTX(d) ((struct HTTP *)(d)->req.p.http)->h2_ctx @@ -210,7 +211,7 @@ struct stream_ctx { */ static void drain_stream(struct Curl_cfilter *cf, struct Curl_easy *data, - struct stream_ctx *stream) + struct h2_stream_ctx *stream) { unsigned char bits; @@ -229,10 +230,10 @@ static void drain_stream(struct Curl_cfilter *cf, static CURLcode http2_data_setup(struct Curl_cfilter *cf, struct Curl_easy *data, - struct stream_ctx **pstream) + struct h2_stream_ctx **pstream) { struct cf_h2_ctx *ctx = cf->ctx; - struct stream_ctx *stream; + struct h2_stream_ctx *stream; (void)cf; DEBUGASSERT(data); @@ -253,8 +254,6 @@ static CURLcode http2_data_setup(struct Curl_cfilter *cf, stream->id = -1; Curl_bufq_initp(&stream->sendbuf, &ctx->stream_bufcp, H2_STREAM_SEND_CHUNKS, BUFQ_OPT_NONE); - Curl_bufq_initp(&stream->recvbuf, &ctx->stream_bufcp, - H2_STREAM_RECV_CHUNKS, BUFQ_OPT_SOFT_LIMIT); Curl_h1_req_parse_init(&stream->h1, H1_PARSE_DEFAULT_MAX_LINE_LEN); Curl_dynhds_init(&stream->resp_trailers, 0, DYN_HTTP_REQUEST); stream->resp_hds_len = 0; @@ -265,6 +264,7 @@ static CURLcode http2_data_setup(struct Curl_cfilter *cf, stream->error = NGHTTP2_NO_ERROR; stream->local_window_size = H2_STREAM_WINDOW_SIZE; stream->upload_left = 0; + stream->nrcvd_data = 0; H2_STREAM_LCTX(data) = stream; *pstream = stream; @@ -275,7 +275,7 @@ static void http2_data_done(struct Curl_cfilter *cf, struct Curl_easy *data, bool premature) { struct cf_h2_ctx *ctx = cf->ctx; - struct stream_ctx *stream = H2_STREAM_CTX(data); + struct h2_stream_ctx *stream = H2_STREAM_CTX(data); DEBUGASSERT(ctx); (void)premature; @@ -298,23 +298,12 @@ static void http2_data_done(struct Curl_cfilter *cf, stream->id, NGHTTP2_STREAM_CLOSED); flush_egress = TRUE; } - if(!Curl_bufq_is_empty(&stream->recvbuf)) { - /* Anything in the recvbuf is still being counted - * in stream and connection window flow control. Need - * to free that space or the connection window might get - * exhausted eventually. */ - nghttp2_session_consume(ctx->h2, stream->id, - Curl_bufq_len(&stream->recvbuf)); - /* give WINDOW_UPATE a chance to be sent, but ignore any error */ - flush_egress = TRUE; - } if(flush_egress) nghttp2_session_send(ctx->h2); } Curl_bufq_free(&stream->sendbuf); - Curl_bufq_free(&stream->recvbuf); Curl_h1_req_parse_free(&stream->h1); Curl_dynhds_free(&stream->resp_trailers); if(stream->push_headers) { @@ -411,7 +400,7 @@ static CURLcode cf_h2_ctx_init(struct Curl_cfilter *cf, bool via_h1_upgrade) { struct cf_h2_ctx *ctx = cf->ctx; - struct stream_ctx *stream; + struct h2_stream_ctx *stream; CURLcode result = CURLE_OUT_OF_MEMORY; int rc; nghttp2_session_callbacks *cbs = NULL; @@ -731,7 +720,7 @@ char *curl_pushheader_bynum(struct curl_pushheaders *h, size_t num) if(!h || !GOOD_EASY_HANDLE(h->data)) return NULL; else { - struct stream_ctx *stream = H2_STREAM_CTX(h->data); + struct h2_stream_ctx *stream = H2_STREAM_CTX(h->data); if(stream && num < stream->push_headers_used) return stream->push_headers[num]; } @@ -743,7 +732,7 @@ char *curl_pushheader_bynum(struct curl_pushheaders *h, size_t num) */ char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header) { - struct stream_ctx *stream; + struct h2_stream_ctx *stream; size_t len; size_t i; /* Verify that we got a good easy handle in the push header struct, @@ -783,7 +772,7 @@ static struct Curl_easy *h2_duphandle(struct Curl_cfilter *cf, (void)Curl_close(&second); } else { - struct stream_ctx *second_stream; + struct h2_stream_ctx *second_stream; second->req.p.http = http; http2_data_setup(cf, second, &second_stream); @@ -867,8 +856,8 @@ static int push_promise(struct Curl_cfilter *cf, CURL_TRC_CF(data, cf, "[%d] PUSH_PROMISE received", frame->promised_stream_id); if(data->multi->push_cb) { - struct stream_ctx *stream; - struct stream_ctx *newstream; + struct h2_stream_ctx *stream; + struct h2_stream_ctx *newstream; struct curl_pushheaders heads; CURLMcode rc; CURLcode result; @@ -967,18 +956,10 @@ static CURLcode recvbuf_write_hds(struct Curl_cfilter *cf, struct Curl_easy *data, const char *buf, size_t blen) { - struct stream_ctx *stream = H2_STREAM_CTX(data); - ssize_t nwritten; - CURLcode result; + bool done; (void)cf; - nwritten = Curl_bufq_write(&stream->recvbuf, - (const unsigned char *)buf, blen, &result); - if(nwritten < 0) - return result; - stream->resp_hds_len += (size_t)nwritten; - DEBUGASSERT((size_t)nwritten == blen); - return CURLE_OK; + return Curl_xfer_write_resp(data, (char *)buf, blen, FALSE, &done); } static CURLcode on_stream_frame(struct Curl_cfilter *cf, @@ -986,10 +967,9 @@ static CURLcode on_stream_frame(struct Curl_cfilter *cf, const nghttp2_frame *frame) { struct cf_h2_ctx *ctx = cf->ctx; - struct stream_ctx *stream = H2_STREAM_CTX(data); + struct h2_stream_ctx *stream = H2_STREAM_CTX(data); int32_t stream_id = frame->hd.stream_id; CURLcode result; - size_t rbuflen; int rv; if(!stream) { @@ -999,9 +979,8 @@ static CURLcode on_stream_frame(struct Curl_cfilter *cf, switch(frame->hd.type) { case NGHTTP2_DATA: - rbuflen = Curl_bufq_len(&stream->recvbuf); - CURL_TRC_CF(data, cf, "[%d] DATA, buffered=%zu, window=%d/%d", - stream_id, rbuflen, + CURL_TRC_CF(data, cf, "[%d] DATA, window=%d/%d", + stream_id, nghttp2_session_get_stream_effective_recv_data_length( ctx->h2, stream->id), nghttp2_session_get_stream_effective_local_window_size( @@ -1018,20 +997,6 @@ static CURLcode on_stream_frame(struct Curl_cfilter *cf, if(frame->hd.flags & NGHTTP2_FLAG_END_STREAM) { drain_stream(cf, data, stream); } - else if(rbuflen > stream->local_window_size) { - int32_t wsize = nghttp2_session_get_stream_local_window_size( - ctx->h2, stream->id); - if(wsize > 0 && (uint32_t)wsize != stream->local_window_size) { - /* H2 flow control is not absolute, as the server might not have the - * same view, yet. When we receive more than we want, we enforce - * the local window size again to make nghttp2 send WINDOW_UPATEs - * accordingly. */ - nghttp2_session_set_local_window_size(ctx->h2, - NGHTTP2_FLAG_NONE, - stream->id, - stream->local_window_size); - } - } break; case NGHTTP2_HEADERS: if(stream->bodystarted) { @@ -1233,7 +1198,7 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame, * servers send an explicit WINDOW_UPDATE, but not all seem to do that. * To be safe, we UNHOLD a stream in order not to stall. */ if(CURL_WANT_SEND(data)) { - struct stream_ctx *stream = H2_STREAM_CTX(data); + struct h2_stream_ctx *stream = H2_STREAM_CTX(data); if(stream) drain_stream(cf, data, stream); } @@ -1270,10 +1235,11 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags, const uint8_t *mem, size_t len, void *userp) { struct Curl_cfilter *cf = userp; - struct stream_ctx *stream; + struct cf_h2_ctx *ctx = cf->ctx; + struct h2_stream_ctx *stream; struct Curl_easy *data_s; - ssize_t nwritten; CURLcode result; + bool done; (void)flags; DEBUGASSERT(stream_id); /* should never be a zero stream ID here */ @@ -1296,18 +1262,15 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags, if(!stream) return NGHTTP2_ERR_CALLBACK_FAILURE; - nwritten = Curl_bufq_write(&stream->recvbuf, mem, len, &result); - if(nwritten < 0) { - if(result != CURLE_AGAIN) - return NGHTTP2_ERR_CALLBACK_FAILURE; + result = Curl_xfer_write_resp(data_s, (char *)mem, len, FALSE, &done); + if(result && result != CURLE_AGAIN) + return NGHTTP2_ERR_CALLBACK_FAILURE; - nwritten = 0; - } + nghttp2_session_consume(ctx->h2, stream_id, len); + stream->nrcvd_data += (curl_off_t)len; /* if we receive data for another handle, wake that up */ drain_stream(cf, data_s, stream); - - DEBUGASSERT((size_t)nwritten == len); return 0; } @@ -1316,7 +1279,7 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id, { struct Curl_cfilter *cf = userp; struct Curl_easy *data_s, *call_data = CF_DATA_CURRENT(cf); - struct stream_ctx *stream; + struct h2_stream_ctx *stream; int rv; (void)session; @@ -1374,7 +1337,7 @@ static int on_begin_headers(nghttp2_session *session, const nghttp2_frame *frame, void *userp) { struct Curl_cfilter *cf = userp; - struct stream_ctx *stream; + struct h2_stream_ctx *stream; struct Curl_easy *data_s = NULL; (void)cf; @@ -1403,7 +1366,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame, void *userp) { struct Curl_cfilter *cf = userp; - struct stream_ctx *stream; + struct h2_stream_ctx *stream; struct Curl_easy *data_s; int32_t stream_id = frame->hd.stream_id; CURLcode result; @@ -1565,7 +1528,7 @@ static ssize_t req_body_read_callback(nghttp2_session *session, { struct Curl_cfilter *cf = userp; struct Curl_easy *data_s; - struct stream_ctx *stream = NULL; + struct h2_stream_ctx *stream = NULL; CURLcode result; ssize_t nread; (void)source; @@ -1667,7 +1630,7 @@ static CURLcode http2_data_done_send(struct Curl_cfilter *cf, { struct cf_h2_ctx *ctx = cf->ctx; CURLcode result = CURLE_OK; - struct stream_ctx *stream = H2_STREAM_CTX(data); + struct h2_stream_ctx *stream = H2_STREAM_CTX(data); if(!ctx || !ctx->h2 || !stream) goto out; @@ -1691,7 +1654,7 @@ out: static ssize_t http2_handle_stream_close(struct Curl_cfilter *cf, struct Curl_easy *data, - struct stream_ctx *stream, + struct h2_stream_ctx *stream, CURLcode *err) { ssize_t rv = 0; @@ -1787,7 +1750,7 @@ static void h2_pri_spec(struct Curl_easy *data, nghttp2_priority_spec *pri_spec) { struct Curl_data_priority *prio = &data->set.priority; - struct stream_ctx *depstream = H2_STREAM_CTX(prio->parent); + struct h2_stream_ctx *depstream = H2_STREAM_CTX(prio->parent); int32_t depstream_id = depstream? depstream->id:0; nghttp2_priority_spec_init(pri_spec, depstream_id, sweight_wanted(data), @@ -1805,7 +1768,7 @@ static CURLcode h2_progress_egress(struct Curl_cfilter *cf, struct Curl_easy *data) { struct cf_h2_ctx *ctx = cf->ctx; - struct stream_ctx *stream = H2_STREAM_CTX(data); + struct h2_stream_ctx *stream = H2_STREAM_CTX(data); int rv = 0; if(stream && stream->id > 0 && @@ -1838,40 +1801,26 @@ out: } static ssize_t stream_recv(struct Curl_cfilter *cf, struct Curl_easy *data, - struct stream_ctx *stream, + struct h2_stream_ctx *stream, char *buf, size_t len, CURLcode *err) { struct cf_h2_ctx *ctx = cf->ctx; ssize_t nread = -1; + (void)buf; *err = CURLE_AGAIN; - if(!Curl_bufq_is_empty(&stream->recvbuf)) { - nread = Curl_bufq_read(&stream->recvbuf, - (unsigned char *)buf, len, err); - if(nread < 0) - goto out; - DEBUGASSERT(nread > 0); - } - - if(nread < 0) { - if(stream->closed) { - CURL_TRC_CF(data, cf, "[%d] returning CLOSE", stream->id); - nread = http2_handle_stream_close(cf, data, stream, err); - } - else if(stream->reset || - (ctx->conn_closed && Curl_bufq_is_empty(&ctx->inbufq)) || - (ctx->goaway && ctx->last_stream_id < stream->id)) { - CURL_TRC_CF(data, cf, "[%d] returning ERR", stream->id); - *err = stream->bodystarted? CURLE_PARTIAL_FILE : CURLE_RECV_ERROR; - nread = -1; - } - } - else if(nread == 0) { - *err = CURLE_AGAIN; + if(stream->closed) { + CURL_TRC_CF(data, cf, "[%d] returning CLOSE", stream->id); + nread = http2_handle_stream_close(cf, data, stream, err); + } + else if(stream->reset || + (ctx->conn_closed && Curl_bufq_is_empty(&ctx->inbufq)) || + (ctx->goaway && ctx->last_stream_id < stream->id)) { + CURL_TRC_CF(data, cf, "[%d] returning ERR", stream->id); + *err = stream->bodystarted? CURLE_PARTIAL_FILE : CURLE_RECV_ERROR; nread = -1; } -out: if(nread < 0 && *err != CURLE_AGAIN) CURL_TRC_CF(data, cf, "[%d] stream_recv(len=%zu) -> %zd, %d", stream->id, len, nread, *err); @@ -1879,10 +1828,11 @@ out: } static CURLcode h2_progress_ingress(struct Curl_cfilter *cf, - struct Curl_easy *data) + struct Curl_easy *data, + size_t data_max_bytes) { struct cf_h2_ctx *ctx = cf->ctx; - struct stream_ctx *stream; + struct h2_stream_ctx *stream; CURLcode result = CURLE_OK; ssize_t nread; @@ -1899,16 +1849,17 @@ static CURLcode h2_progress_ingress(struct Curl_cfilter *cf, * all network input */ while(!ctx->conn_closed && Curl_bufq_is_empty(&ctx->inbufq)) { stream = H2_STREAM_CTX(data); - if(stream && (stream->closed || Curl_bufq_is_full(&stream->recvbuf))) { + if(stream && (stream->closed || !data_max_bytes)) { /* We would like to abort here and stop processing, so that * the transfer loop can handle the data/close here. However, * this may leave data in underlying buffers that will not * be consumed. */ if(!cf->next || !cf->next->cft->has_data_pending(cf->next, data)) - break; + drain_stream(cf, data, stream); + break; } - nread = Curl_bufq_slurp(&ctx->inbufq, nw_in_reader, cf, &result); + nread = Curl_bufq_sipn(&ctx->inbufq, 0, nw_in_reader, cf, &result); if(nread < 0) { if(result != CURLE_AGAIN) { failf(data, "Failed receiving HTTP2 data: %d(%s)", result, @@ -1923,8 +1874,9 @@ static CURLcode h2_progress_ingress(struct Curl_cfilter *cf, break; } else { - CURL_TRC_CF(data, cf, "[0] ingress: read %zd bytes", - nread); + CURL_TRC_CF(data, cf, "[0] ingress: read %zd bytes", nread); + data_max_bytes = (data_max_bytes > (size_t)nread)? + (data_max_bytes - (size_t)nread) : 0; } if(h2_process_pending_input(cf, data, &result)) @@ -1942,7 +1894,7 @@ static ssize_t cf_h2_recv(struct Curl_cfilter *cf, struct Curl_easy *data, char *buf, size_t len, CURLcode *err) { struct cf_h2_ctx *ctx = cf->ctx; - struct stream_ctx *stream = H2_STREAM_CTX(data); + struct h2_stream_ctx *stream = H2_STREAM_CTX(data); ssize_t nread = -1; CURLcode result; struct cf_call_data save; @@ -1966,7 +1918,7 @@ static ssize_t cf_h2_recv(struct Curl_cfilter *cf, struct Curl_easy *data, goto out; if(nread < 0) { - *err = h2_progress_ingress(cf, data); + *err = h2_progress_ingress(cf, data, len); if(*err) goto out; @@ -2011,9 +1963,8 @@ out: nread = -1; } CURL_TRC_CF(data, cf, "[%d] cf_recv(len=%zu) -> %zd %d, " - "buffered=%zu, window=%d/%d, connection %d/%d", + "window=%d/%d, connection %d/%d", stream->id, len, nread, *err, - Curl_bufq_len(&stream->recvbuf), nghttp2_session_get_stream_effective_recv_data_length( ctx->h2, stream->id), nghttp2_session_get_stream_effective_local_window_size( @@ -2025,12 +1976,12 @@ out: return nread; } -static ssize_t h2_submit(struct stream_ctx **pstream, +static ssize_t h2_submit(struct h2_stream_ctx **pstream, struct Curl_cfilter *cf, struct Curl_easy *data, const void *buf, size_t len, CURLcode *err) { struct cf_h2_ctx *ctx = cf->ctx; - struct stream_ctx *stream = NULL; + struct h2_stream_ctx *stream = NULL; struct dynhds h2_headers; nghttp2_nv *nva = NULL; const void *body = NULL; @@ -2169,7 +2120,7 @@ static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data, const void *buf, size_t len, CURLcode *err) { struct cf_h2_ctx *ctx = cf->ctx; - struct stream_ctx *stream = H2_STREAM_CTX(data); + struct h2_stream_ctx *stream = H2_STREAM_CTX(data); struct cf_call_data save; int rv; ssize_t nwritten; @@ -2340,7 +2291,7 @@ static void cf_h2_adjust_pollset(struct Curl_cfilter *cf, sock = Curl_conn_cf_get_socket(cf, data); Curl_pollset_check(data, ps, sock, &want_recv, &want_send); if(want_recv || want_send) { - struct stream_ctx *stream = H2_STREAM_CTX(data); + struct h2_stream_ctx *stream = H2_STREAM_CTX(data); struct cf_call_data save; bool c_exhaust, s_exhaust; @@ -2387,7 +2338,7 @@ static CURLcode cf_h2_connect(struct Curl_cfilter *cf, goto out; } - result = h2_progress_ingress(cf, data); + result = h2_progress_ingress(cf, data, H2_CHUNK_SIZE); if(result) goto out; @@ -2441,7 +2392,7 @@ static CURLcode http2_data_pause(struct Curl_cfilter *cf, { #ifdef NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE struct cf_h2_ctx *ctx = cf->ctx; - struct stream_ctx *stream = H2_STREAM_CTX(data); + struct h2_stream_ctx *stream = H2_STREAM_CTX(data); DEBUGASSERT(data); if(ctx && ctx->h2 && stream) { @@ -2526,11 +2477,10 @@ static bool cf_h2_data_pending(struct Curl_cfilter *cf, const struct Curl_easy *data) { struct cf_h2_ctx *ctx = cf->ctx; - struct stream_ctx *stream = H2_STREAM_CTX(data); + struct h2_stream_ctx *stream = H2_STREAM_CTX(data); if(ctx && (!Curl_bufq_is_empty(&ctx->inbufq) - || (stream && !Curl_bufq_is_empty(&stream->sendbuf)) - || (stream && !Curl_bufq_is_empty(&stream->recvbuf)))) + || (stream && !Curl_bufq_is_empty(&stream->sendbuf)))) return TRUE; return cf->next? cf->next->cft->has_data_pending(cf->next, data) : FALSE; } @@ -2615,7 +2565,8 @@ struct Curl_cftype Curl_cft_nghttp2 = { static CURLcode http2_cfilter_add(struct Curl_cfilter **pcf, struct Curl_easy *data, struct connectdata *conn, - int sockindex) + int sockindex, + bool via_h1_upgrade) { struct Curl_cfilter *cf = NULL; struct cf_h2_ctx *ctx; @@ -2630,8 +2581,9 @@ static CURLcode http2_cfilter_add(struct Curl_cfilter **pcf, if(result) goto out; + ctx = NULL; Curl_conn_cf_add(data, conn, sockindex, cf); - result = CURLE_OK; + result = cf_h2_ctx_init(cf, data, via_h1_upgrade); out: if(result) @@ -2641,7 +2593,8 @@ out: } static CURLcode http2_cfilter_insert_after(struct Curl_cfilter *cf, - struct Curl_easy *data) + struct Curl_easy *data, + bool via_h1_upgrade) { struct Curl_cfilter *cf_h2 = NULL; struct cf_h2_ctx *ctx; @@ -2656,8 +2609,9 @@ static CURLcode http2_cfilter_insert_after(struct Curl_cfilter *cf, if(result) goto out; + ctx = NULL; Curl_conn_cf_insert_after(cf, cf_h2); - result = CURLE_OK; + result = cf_h2_ctx_init(cf_h2, data, via_h1_upgrade); out: if(result) @@ -2714,11 +2668,7 @@ CURLcode Curl_http2_switch(struct Curl_easy *data, DEBUGASSERT(!Curl_conn_is_http2(data, conn, sockindex)); DEBUGF(infof(data, "switching to HTTP/2")); - result = http2_cfilter_add(&cf, data, conn, sockindex); - if(result) - return result; - - result = cf_h2_ctx_init(cf, data, FALSE); + result = http2_cfilter_add(&cf, data, conn, sockindex, FALSE); if(result) return result; @@ -2741,15 +2691,11 @@ CURLcode Curl_http2_switch_at(struct Curl_cfilter *cf, struct Curl_easy *data) DEBUGASSERT(!Curl_cf_is_http2(cf, data)); - result = http2_cfilter_insert_after(cf, data); + result = http2_cfilter_insert_after(cf, data, FALSE); if(result) return result; cf_h2 = cf->next; - result = cf_h2_ctx_init(cf_h2, data, FALSE); - if(result) - return result; - cf->conn->httpversion = 20; /* we know we're on HTTP/2 now */ cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */ cf->conn->bundle->multiuse = BUNDLE_MULTIPLEX; @@ -2774,17 +2720,13 @@ CURLcode Curl_http2_upgrade(struct Curl_easy *data, DEBUGF(infof(data, "upgrading to HTTP/2")); DEBUGASSERT(data->req.upgr101 == UPGR101_RECEIVED); - result = http2_cfilter_add(&cf, data, conn, sockindex); + result = http2_cfilter_add(&cf, data, conn, sockindex, TRUE); if(result) return result; DEBUGASSERT(cf->cft == &Curl_cft_nghttp2); ctx = cf->ctx; - result = cf_h2_ctx_init(cf, data, TRUE); - if(result) - return result; - if(nread > 0) { /* Remaining data from the protocol switch reply is already using * the switched protocol, ie. HTTP/2. We add that to the network @@ -2823,7 +2765,7 @@ CURLcode Curl_http2_upgrade(struct Curl_easy *data, CURLE_HTTP2_STREAM error! */ bool Curl_h2_http_1_1_error(struct Curl_easy *data) { - struct stream_ctx *stream = H2_STREAM_CTX(data); + struct h2_stream_ctx *stream = H2_STREAM_CTX(data); return (stream && stream->error == NGHTTP2_HTTP_1_1_REQUIRED); }