Lines Matching +full:- +full:- +full:with +full:- +full:nghttp2
21 * SPDX-License-Identifier: curl
29 #include <nghttp2/nghttp2.h>
42 #include "urlapi-int.h"
57 #error too old nghttp2 version, upgrade!
81 * nghttp2 allows us to tweak the local window size. */
93 /* We need to accommodate the max number of streams with their window sizes on
96 * is blocked from sending us any data. See #10988 for an issue with this. */
106 iv[0].value = Curl_multi_max_concurrent_streams(data->multi); in populate_settings()
112 iv[2].value = data->multi->push_cb != NULL; in populate_settings()
139 struct Curl_hash streams; /* hash of `data->mid` to `h2_stream_ctx` */
157 ((struct cf_h2_ctx *)(cf)->ctx)->call_data
163 Curl_bufcp_init(&ctx->stream_bufcp, H2_CHUNK_SIZE, H2_STREAM_POOL_SPARES); in cf_h2_ctx_init()
164 Curl_bufq_initp(&ctx->inbufq, &ctx->stream_bufcp, H2_NW_RECV_CHUNKS, 0); in cf_h2_ctx_init()
165 Curl_bufq_initp(&ctx->outbufq, &ctx->stream_bufcp, H2_NW_SEND_CHUNKS, 0); in cf_h2_ctx_init()
166 Curl_dyn_init(&ctx->scratch, CURL_MAX_HTTP_HEADER); in cf_h2_ctx_init()
167 Curl_hash_offt_init(&ctx->streams, 63, h2_stream_hash_free); in cf_h2_ctx_init()
168 ctx->remote_max_sid = 2147483647; in cf_h2_ctx_init()
169 ctx->via_h1_upgrade = via_h1_upgrade; in cf_h2_ctx_init()
170 ctx->initialized = TRUE; in cf_h2_ctx_init()
175 if(ctx && ctx->initialized) { in cf_h2_ctx_free()
176 Curl_bufq_free(&ctx->inbufq); in cf_h2_ctx_free()
177 Curl_bufq_free(&ctx->outbufq); in cf_h2_ctx_free()
178 Curl_bufcp_free(&ctx->stream_bufcp); in cf_h2_ctx_free()
179 Curl_dyn_free(&ctx->scratch); in cf_h2_ctx_free()
180 Curl_hash_clean(&ctx->streams); in cf_h2_ctx_free()
181 Curl_hash_destroy(&ctx->streams); in cf_h2_ctx_free()
189 if(ctx->h2) { in cf_h2_ctx_close()
190 nghttp2_session_del(ctx->h2); in cf_h2_ctx_close()
226 data? Curl_hash_offt_get(&(ctx)->streams, (data)->mid) : NULL))
237 stream->id = -1; in h2_stream_ctx_create()
238 Curl_bufq_initp(&stream->sendbuf, &ctx->stream_bufcp, in h2_stream_ctx_create()
240 Curl_h1_req_parse_init(&stream->h1, H1_PARSE_DEFAULT_MAX_LINE_LEN); in h2_stream_ctx_create()
241 Curl_dynhds_init(&stream->resp_trailers, 0, DYN_HTTP_REQUEST); in h2_stream_ctx_create()
242 stream->bodystarted = FALSE; in h2_stream_ctx_create()
243 stream->status_code = -1; in h2_stream_ctx_create()
244 stream->closed = FALSE; in h2_stream_ctx_create()
245 stream->close_handled = FALSE; in h2_stream_ctx_create()
246 stream->error = NGHTTP2_NO_ERROR; in h2_stream_ctx_create()
247 stream->local_window_size = H2_STREAM_WINDOW_SIZE_INITIAL; in h2_stream_ctx_create()
248 stream->nrcvd_data = 0; in h2_stream_ctx_create()
255 for(i = 0; i < stream->push_headers_used; i++) in free_push_headers()
256 free(stream->push_headers[i]); in free_push_headers()
257 Curl_safefree(stream->push_headers); in free_push_headers()
258 stream->push_headers_used = 0; in free_push_headers()
263 Curl_bufq_free(&stream->sendbuf); in h2_stream_ctx_free()
264 Curl_h1_req_parse_free(&stream->h1); in h2_stream_ctx_free()
265 Curl_dynhds_free(&stream->resp_trailers); in h2_stream_ctx_free()
281 if(data->set.max_recv_speed && data->set.max_recv_speed < INT32_MAX) { in cf_h2_get_desired_local_win()
286 return (int32_t)data->set.max_recv_speed; in cf_h2_get_desired_local_win()
296 struct cf_h2_ctx *ctx = cf->ctx; in cf_h2_update_local_win()
301 if(dwsize != stream->local_window_size) { in cf_h2_update_local_win()
303 ctx->h2, stream->id); in cf_h2_update_local_win()
305 rv = nghttp2_submit_window_update(ctx->h2, NGHTTP2_FLAG_NONE, in cf_h2_update_local_win()
306 stream->id, dwsize - wsize); in cf_h2_update_local_win()
309 "%s(%d)", stream->id, nghttp2_strerror(rv), rv); in cf_h2_update_local_win()
312 stream->local_window_size = dwsize; in cf_h2_update_local_win()
314 stream->id, dwsize - wsize); in cf_h2_update_local_win()
317 rv = nghttp2_session_set_local_window_size(ctx->h2, NGHTTP2_FLAG_NONE, in cf_h2_update_local_win()
318 stream->id, dwsize); in cf_h2_update_local_win()
321 "%s(%d)", stream->id, nghttp2_strerror(rv), rv); in cf_h2_update_local_win()
324 stream->local_window_size = dwsize; in cf_h2_update_local_win()
326 stream->id, dwsize); in cf_h2_update_local_win()
358 if(!stream->closed && in drain_stream()
359 (!stream->body_eos || !Curl_bufq_is_empty(&stream->sendbuf))) in drain_stream()
361 if(stream->closed || (data->state.select_bits != bits)) { in drain_stream()
363 stream->id, bits); in drain_stream()
364 data->state.select_bits = bits; in drain_stream()
373 struct cf_h2_ctx *ctx = cf->ctx; in http2_data_setup()
388 if(!Curl_hash_offt_set(&ctx->streams, data->mid, stream)) { in http2_data_setup()
399 struct cf_h2_ctx *ctx = cf->ctx; in http2_data_done()
403 if(!stream || !ctx->initialized) in http2_data_done()
406 if(ctx->h2) { in http2_data_done()
409 (void)nghttp2_session_set_stream_user_data(ctx->h2, stream->id, NULL); in http2_data_done()
411 if(!stream->closed && stream->id > 0) { in http2_data_done()
414 stream->id); in http2_data_done()
415 stream->closed = TRUE; in http2_data_done()
416 stream->reset = TRUE; in http2_data_done()
417 nghttp2_submit_rst_stream(ctx->h2, NGHTTP2_FLAG_NONE, in http2_data_done()
418 stream->id, NGHTTP2_STREAM_CLOSED); in http2_data_done()
423 nghttp2_session_send(ctx->h2); in http2_data_done()
426 Curl_hash_offt_remove(&ctx->streams, data->mid); in http2_data_done()
432 struct cf_h2_ctx *ctx = cf->ctx; in h2_client_new()
443 /* with 1.50.0 */ in h2_client_new()
448 rc = nghttp2_session_client_new3(&ctx->h2, cbs, cf, o, &mem); in h2_client_new()
460 return Curl_conn_cf_recv(cf->next, data, (char *)buf, buflen, err); in nw_in_reader()
471 ssize_t nwritten = Curl_conn_cf_send(cf->next, data, (const char *)buf, in nw_out_writer()
508 struct cf_h2_ctx *ctx = cf->ctx; in cf_h2_ctx_open()
514 DEBUGASSERT(!ctx->h2); in cf_h2_ctx_open()
515 DEBUGASSERT(ctx->initialized); in cf_h2_ctx_open()
519 failf(data, "Couldn't initialize nghttp2 callbacks"); in cf_h2_ctx_open()
538 /* The nghttp2 session is not yet setup, do it */ in cf_h2_ctx_open()
541 failf(data, "Couldn't initialize nghttp2"); in cf_h2_ctx_open()
544 ctx->max_concurrent_streams = DEFAULT_MAX_CONCURRENT_STREAMS; in cf_h2_ctx_open()
546 if(ctx->via_h1_upgrade) { in cf_h2_ctx_open()
555 failf(data, "nghttp2 unexpectedly failed on pack_settings_payload"); in cf_h2_ctx_open()
564 stream->id = 1; in cf_h2_ctx_open()
566 rc = nghttp2_session_upgrade2(ctx->h2, binsettings, (size_t)binlen, in cf_h2_ctx_open()
567 data->state.httpreq == HTTPREQ_HEAD, in cf_h2_ctx_open()
576 rc = nghttp2_session_set_stream_user_data(ctx->h2, stream->id, in cf_h2_ctx_open()
580 stream->id); in cf_h2_ctx_open()
590 rc = nghttp2_submit_settings(ctx->h2, NGHTTP2_FLAG_NONE, in cf_h2_ctx_open()
600 rc = nghttp2_session_set_local_window_size(ctx->h2, NGHTTP2_FLAG_NONE, 0, in cf_h2_ctx_open()
612 ctx->via_h1_upgrade ? " (via h1 upgrade)" : ""); in cf_h2_ctx_open()
625 return ctx->drain_total == 0 && !nghttp2_session_want_read(ctx->h2) && in should_close_session()
626 !nghttp2_session_want_write(ctx->h2); in should_close_session()
631 * This function returns 0 if it succeeds, or -1 and error code will
638 struct cf_h2_ctx *ctx = cf->ctx; in h2_process_pending_input()
643 while(Curl_bufq_peek(&ctx->inbufq, &buf, &blen)) { in h2_process_pending_input()
645 rv = nghttp2_session_mem_recv(ctx->h2, (const uint8_t *)buf, blen); in h2_process_pending_input()
651 return -1; in h2_process_pending_input()
653 Curl_bufq_skip(&ctx->inbufq, (size_t)rv); in h2_process_pending_input()
654 if(Curl_bufq_is_empty(&ctx->inbufq)) { in h2_process_pending_input()
659 "in connection buffer", Curl_bufq_len(&ctx->inbufq)); in h2_process_pending_input()
663 if(nghttp2_session_check_request_allowed(ctx->h2) == 0) { in h2_process_pending_input()
668 connclose(cf->conn, "http/2: No new requests allowed"); in h2_process_pending_input()
684 struct cf_h2_ctx *ctx = cf->ctx; in http2_connisalive()
688 if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending)) in http2_connisalive()
696 ssize_t nread = -1; in http2_connisalive()
699 nread = Curl_bufq_slurp(&ctx->inbufq, nw_in_reader, cf, &result); in http2_connisalive()
700 if(nread != -1) { in http2_connisalive()
722 struct cf_h2_ctx *ctx = cf->ctx; in http2_send_ping()
725 rc = nghttp2_submit_ping(ctx->h2, 0, ZERO_NULL); in http2_send_ping()
732 rc = nghttp2_session_send(ctx->h2); in http2_send_ping()
742 * Store nghttp2 version info in this buffer.
747 (void)msnprintf(p, len, "nghttp2/%s", h2->version_str); in Curl_http2_ver()
753 struct cf_h2_ctx *ctx = cf->ctx; in nw_out_flush()
758 if(Curl_bufq_is_empty(&ctx->outbufq)) in nw_out_flush()
761 nwritten = Curl_bufq_pass(&ctx->outbufq, nw_out_writer, cf, &result); in nw_out_flush()
764 CURL_TRC_CF(data, cf, "flush nw send buffer(%zu) -> EAGAIN", in nw_out_flush()
765 Curl_bufq_len(&ctx->outbufq)); in nw_out_flush()
766 ctx->nw_out_blocked = 1; in nw_out_flush()
770 return Curl_bufq_is_empty(&ctx->outbufq) ? CURLE_OK : CURLE_AGAIN; in nw_out_flush()
774 * The implementation of nghttp2_send_callback type. Here we write |data| with
783 struct cf_h2_ctx *ctx = cf->ctx; in send_callback()
792 if(!cf->connected) in send_callback()
793 nwritten = Curl_bufq_write(&ctx->outbufq, buf, blen, &result); in send_callback()
795 nwritten = Curl_bufq_write_pass(&ctx->outbufq, buf, blen, in send_callback()
799 ctx->nw_out_blocked = 1; in send_callback()
807 ctx->nw_out_blocked = 1; in send_callback()
829 if(!h || !GOOD_EASY_HANDLE(h->data)) in curl_pushheader_bynum()
832 if(h->stream && num < h->stream->push_headers_used) in curl_pushheader_bynum()
833 return h->stream->push_headers[num]; in curl_pushheader_bynum()
852 if(!h || !GOOD_EASY_HANDLE(h->data) || !header || !header[0] || in curl_pushheader_byname()
856 stream = h->stream; in curl_pushheader_byname()
861 for(i = 0; i < stream->push_headers_used; i++) { in curl_pushheader_byname()
862 if(!strncmp(header, stream->push_headers[i], len)) { in curl_pushheader_byname()
863 /* sub-match, make sure that it is followed by a colon */ in curl_pushheader_byname()
864 if(stream->push_headers[i][len] != ':') in curl_pushheader_byname()
866 return &stream->push_headers[i][len + 1]; in curl_pushheader_byname()
879 second->state.priority.weight = data->state.priority.weight; in h2_duphandle()
931 if(data->state.url_alloc) in set_transfer_url()
932 free(data->state.url); in set_transfer_url()
933 data->state.url_alloc = TRUE; in set_transfer_url()
934 data->state.url = url; in set_transfer_url()
949 struct cf_h2_ctx *ctx = cf->ctx; in push_promise()
953 frame->promised_stream_id); in push_promise()
954 if(data->multi->push_cb) { in push_promise()
1000 rv = data->multi->push_cb(data, newhandle, in push_promise()
1001 stream->push_headers_used, &heads, in push_promise()
1002 data->multi->push_userp); in push_promise()
1015 newstream->id = frame->promised_stream_id; in push_promise()
1016 newhandle->req.maxdownload = -1; in push_promise()
1017 newhandle->req.size = -1; in push_promise()
1020 state with the given connection !*/ in push_promise()
1021 rc = Curl_multi_add_perform(data->multi, newhandle, cf->conn); in push_promise()
1029 rv = nghttp2_session_set_stream_user_data(ctx->h2, in push_promise()
1030 newstream->id, in push_promise()
1034 newstream->id); in push_promise()
1041 if(newstream->id > ctx->local_max_sid) in push_promise()
1042 ctx->local_max_sid = newstream->id; in push_promise()
1059 if(!stream->xfer_result) { in h2_xfer_write_resp_hd()
1060 stream->xfer_result = Curl_xfer_write_resp_hd(data, buf, blen, eos); in h2_xfer_write_resp_hd()
1061 if(!stream->xfer_result && !eos) in h2_xfer_write_resp_hd()
1062 stream->xfer_result = cf_h2_update_local_win(cf, data, stream, FALSE); in h2_xfer_write_resp_hd()
1063 if(stream->xfer_result) in h2_xfer_write_resp_hd()
1065 stream->id, stream->xfer_result, blen); in h2_xfer_write_resp_hd()
1076 if(!stream->xfer_result) in h2_xfer_write_resp()
1077 stream->xfer_result = Curl_xfer_write_resp(data, buf, blen, eos); in h2_xfer_write_resp()
1078 if(!stream->xfer_result && !eos) in h2_xfer_write_resp()
1079 stream->xfer_result = cf_h2_update_local_win(cf, data, stream, FALSE); in h2_xfer_write_resp()
1081 if(stream->xfer_result) { in h2_xfer_write_resp()
1082 struct cf_h2_ctx *ctx = cf->ctx; in h2_xfer_write_resp()
1084 "RST-ing stream", in h2_xfer_write_resp()
1085 stream->id, stream->xfer_result, blen); in h2_xfer_write_resp()
1086 nghttp2_submit_rst_stream(ctx->h2, 0, stream->id, in h2_xfer_write_resp()
1095 struct cf_h2_ctx *ctx = cf->ctx; in on_stream_frame()
1097 int32_t stream_id = frame->hd.stream_id; in on_stream_frame()
1105 switch(frame->hd.type) { in on_stream_frame()
1110 ctx->h2, stream->id), in on_stream_frame()
1112 ctx->h2, stream->id)); in on_stream_frame()
1114 if(!stream->bodystarted) { in on_stream_frame()
1115 rv = nghttp2_submit_rst_stream(ctx->h2, NGHTTP2_FLAG_NONE, in on_stream_frame()
1124 if(stream->bodystarted) { in on_stream_frame()
1130 /* nghttp2 guarantees that :status is received, and we store it to in on_stream_frame()
1131 stream->status_code. Fuzzing has proven this can still be reached in on_stream_frame()
1133 if(stream->status_code == -1) in on_stream_frame()
1137 if(stream->status_code / 100 != 1) in on_stream_frame()
1138 stream->bodystarted = TRUE; in on_stream_frame()
1140 stream->status_code = -1; in on_stream_frame()
1142 h2_xfer_write_resp_hd(cf, data, stream, STRCONST("\r\n"), stream->closed); in on_stream_frame()
1144 if(stream->status_code / 100 != 1) { in on_stream_frame()
1145 stream->resp_hds_complete = TRUE; in on_stream_frame()
1150 rv = push_promise(cf, data, &frame->push_promise); in on_stream_frame()
1153 rv = nghttp2_submit_rst_stream(ctx->h2, NGHTTP2_FLAG_NONE, in on_stream_frame()
1154 frame->push_promise.promised_stream_id, in on_stream_frame()
1166 stream->closed = TRUE; in on_stream_frame()
1167 if(frame->rst_stream.error_code) { in on_stream_frame()
1168 stream->reset = TRUE; in on_stream_frame()
1173 if(CURL_WANT_SEND(data) && Curl_bufq_is_empty(&stream->sendbuf)) { in on_stream_frame()
1177 else if(!Curl_bufq_is_empty(&stream->sendbuf)) { in on_stream_frame()
1179 rv = nghttp2_session_resume_data(ctx->h2, stream->id); in on_stream_frame()
1188 if(frame->hd.flags & NGHTTP2_FLAG_END_STREAM) { in on_stream_frame()
1189 if(!stream->closed && !stream->body_eos && in on_stream_frame()
1190 ((stream->status_code >= 400) || (stream->status_code < 200))) { in on_stream_frame()
1194 CURL_TRC_CF(data, cf, "[%d] EOS frame with unfinished upload and " in on_stream_frame()
1196 stream_id, stream->status_code); in on_stream_frame()
1197 nghttp2_submit_rst_stream(ctx->h2, NGHTTP2_FLAG_NONE, in on_stream_frame()
1198 stream->id, NGHTTP2_STREAM_CLOSED); in on_stream_frame()
1199 stream->closed = TRUE; in on_stream_frame()
1209 switch(frame->hd.type) { in fr_print()
1213 (int)frame->hd.length, in fr_print()
1214 !!(frame->hd.flags & NGHTTP2_FLAG_END_STREAM), in fr_print()
1215 (int)frame->data.padlen); in fr_print()
1220 (int)frame->hd.length, in fr_print()
1221 !!(frame->hd.flags & NGHTTP2_FLAG_END_HEADERS), in fr_print()
1222 !!(frame->hd.flags & NGHTTP2_FLAG_END_STREAM)); in fr_print()
1227 (int)frame->hd.length, frame->hd.flags); in fr_print()
1232 (int)frame->hd.length, frame->hd.flags, in fr_print()
1233 frame->rst_stream.error_code); in fr_print()
1236 if(frame->hd.flags & NGHTTP2_FLAG_ACK) { in fr_print()
1240 "FRAME[SETTINGS, len=%d]", (int)frame->hd.length); in fr_print()
1245 (int)frame->hd.length, in fr_print()
1246 !!(frame->hd.flags & NGHTTP2_FLAG_END_HEADERS)); in fr_print()
1251 (int)frame->hd.length, in fr_print()
1252 frame->hd.flags&NGHTTP2_FLAG_ACK); in fr_print()
1257 size_t len = (frame->goaway.opaque_data_len < s_len) ? in fr_print()
1258 frame->goaway.opaque_data_len : s_len-1; in fr_print()
1260 memcpy(scratch, frame->goaway.opaque_data, len); in fr_print()
1263 "last_stream=%d]", frame->goaway.error_code, in fr_print()
1264 scratch, frame->goaway.last_stream_id); in fr_print()
1269 frame->window_update.window_size_increment); in fr_print()
1273 frame->hd.type, (int)frame->hd.length, in fr_print()
1274 frame->hd.flags); in fr_print()
1289 len = fr_print(frame, buffer, sizeof(buffer)-1); in on_frame_send()
1291 CURL_TRC_CF(data, cf, "[%d] -> %s", frame->hd.stream_id, buffer); in on_frame_send()
1301 struct cf_h2_ctx *ctx = cf->ctx; in on_frame_recv()
1303 int32_t stream_id = frame->hd.stream_id; in on_frame_recv()
1310 len = fr_print(frame, buffer, sizeof(buffer)-1); in on_frame_recv()
1312 CURL_TRC_CF(data, cf, "[%d] <- %s",frame->hd.stream_id, buffer); in on_frame_recv()
1317 /* stream ID zero is for connection-oriented stuff */ in on_frame_recv()
1319 switch(frame->hd.type) { in on_frame_recv()
1321 if(!(frame->hd.flags & NGHTTP2_FLAG_ACK)) { in on_frame_recv()
1322 uint32_t max_conn = ctx->max_concurrent_streams; in on_frame_recv()
1323 ctx->max_concurrent_streams = nghttp2_session_get_remote_settings( in on_frame_recv()
1325 ctx->enable_push = nghttp2_session_get_remote_settings( in on_frame_recv()
1328 ctx->max_concurrent_streams); in on_frame_recv()
1330 ctx->enable_push ? "TRUE" : "false"); in on_frame_recv()
1331 if(data && max_conn != ctx->max_concurrent_streams) { in on_frame_recv()
1334 ctx->max_concurrent_streams); in on_frame_recv()
1335 Curl_multi_connchanged(data->multi); in on_frame_recv()
1351 ctx->rcvd_goaway = TRUE; in on_frame_recv()
1352 ctx->goaway_error = frame->goaway.error_code; in on_frame_recv()
1353 ctx->remote_max_sid = frame->goaway.last_stream_id; in on_frame_recv()
1356 ctx->goaway_error, ctx->remote_max_sid); in on_frame_recv()
1357 Curl_multi_connchanged(data->multi); in on_frame_recv()
1380 struct cf_h2_ctx *ctx = cf->ctx; in on_data_chunk_recv()
1391 /* Receiving a Stream ID not in the hash should not happen - unless in on_data_chunk_recv()
1407 nghttp2_session_consume(ctx->h2, stream_id, len); in on_data_chunk_recv()
1408 stream->nrcvd_data += (curl_off_t)len; in on_data_chunk_recv()
1416 struct cf_h2_ctx *ctx = cf->ctx; in on_stream_close()
1432 /* nghttp2 still has an easy registered for the stream which has in on_stream_close()
1447 stream->closed = TRUE; in on_stream_close()
1448 stream->error = error_code; in on_stream_close()
1449 if(stream->error) { in on_stream_close()
1450 stream->reset = TRUE; in on_stream_close()
1453 if(stream->error) in on_stream_close()
1460 /* remove `data_s` from the nghttp2 stream */ in on_stream_close()
1474 struct cf_h2_ctx *ctx = cf->ctx; in on_begin_headers()
1479 data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id); in on_begin_headers()
1484 if(frame->hd.type != NGHTTP2_HEADERS) { in on_begin_headers()
1489 if(!stream || !stream->bodystarted) { in on_begin_headers()
1496 /* frame->hd.type is either NGHTTP2_HEADERS or NGHTTP2_PUSH_PROMISE */
1504 struct cf_h2_ctx *ctx = cf->ctx; in on_header()
1507 int32_t stream_id = frame->hd.stream_id; in on_header()
1528 if(frame->hd.type == NGHTTP2_PUSH_PROMISE) { in on_header()
1534 char *check = aprintf("%s:%d", cf->conn->host.name, in on_header()
1535 cf->conn->remote_port); in on_header()
1540 ((cf->conn->remote_port != cf->conn->given->defport) || in on_header()
1541 !strcasecompare(cf->conn->host.name, (const char *)value))) { in on_header()
1556 if(!stream->push_headers) { in on_header()
1557 stream->push_headers_alloc = 10; in on_header()
1558 stream->push_headers = malloc(stream->push_headers_alloc * in on_header()
1560 if(!stream->push_headers) in on_header()
1562 stream->push_headers_used = 0; in on_header()
1564 else if(stream->push_headers_used == in on_header()
1565 stream->push_headers_alloc) { in on_header()
1567 if(stream->push_headers_alloc > 1000) { in on_header()
1573 stream->push_headers_alloc *= 2; in on_header()
1574 headp = realloc(stream->push_headers, in on_header()
1575 stream->push_headers_alloc * sizeof(char *)); in on_header()
1580 stream->push_headers = headp; in on_header()
1584 stream->push_headers[stream->push_headers_used++] = h; in on_header()
1588 if(stream->bodystarted) { in on_header()
1591 stream->id, (int)namelen, name, (int)valuelen, value); in on_header()
1592 result = Curl_dynhds_add(&stream->resp_trailers, in on_header()
1601 if(namelen == sizeof(HTTP_PSEUDO_STATUS) - 1 && in on_header()
1603 /* nghttp2 guarantees :status is received first and only once. */ in on_header()
1605 result = Curl_http_decode_status(&stream->status_code, in on_header()
1610 stream->status_code); in on_header()
1614 Curl_dyn_reset(&ctx->scratch); in on_header()
1615 result = Curl_dyn_addn(&ctx->scratch, STRCONST("HTTP/2 ")); in on_header()
1617 result = Curl_dyn_addn(&ctx->scratch, value, valuelen); in on_header()
1619 result = Curl_dyn_addn(&ctx->scratch, STRCONST(" \r\n")); in on_header()
1621 h2_xfer_write_resp_hd(cf, data_s, stream, Curl_dyn_ptr(&ctx->scratch), in on_header()
1622 Curl_dyn_len(&ctx->scratch), FALSE); in on_header()
1630 stream->id, stream->status_code); in on_header()
1634 /* nghttp2 guarantees that namelen > 0, and :status was already in on_header()
1635 received, and this is not pseudo-header field . */ in on_header()
1636 /* convert to an HTTP1-style header */ in on_header()
1637 Curl_dyn_reset(&ctx->scratch); in on_header()
1638 result = Curl_dyn_addn(&ctx->scratch, (const char *)name, namelen); in on_header()
1640 result = Curl_dyn_addn(&ctx->scratch, STRCONST(": ")); in on_header()
1642 result = Curl_dyn_addn(&ctx->scratch, (const char *)value, valuelen); in on_header()
1644 result = Curl_dyn_addn(&ctx->scratch, STRCONST("\r\n")); in on_header()
1646 h2_xfer_write_resp_hd(cf, data_s, stream, Curl_dyn_ptr(&ctx->scratch), in on_header()
1647 Curl_dyn_len(&ctx->scratch), FALSE); in on_header()
1655 stream->id, (int)namelen, name, (int)valuelen, value); in on_header()
1668 struct cf_h2_ctx *ctx = cf->ctx; in req_body_read_callback()
1680 connection-oriented stuff */ in req_body_read_callback()
1691 nread = Curl_bufq_read(&stream->sendbuf, buf, length, &result); in req_body_read_callback()
1698 CURL_TRC_CF(data_s, cf, "[%d] req_body_read(len=%zu) eos=%d -> %zd, %d", in req_body_read_callback()
1699 stream_id, length, stream->body_eos, nread, result); in req_body_read_callback()
1701 if(stream->body_eos && Curl_bufq_is_empty(&stream->sendbuf)) { in req_body_read_callback()
1731 struct SingleRequest *k = &data->req; in Curl_http2_request_upgrade()
1737 failf(data, "nghttp2 unexpectedly failed on pack_settings_payload"); in Curl_http2_request_upgrade()
1750 "Connection: Upgrade, HTTP2-Settings\r\n" in Curl_http2_request_upgrade()
1752 "HTTP2-Settings: %s\r\n", in Curl_http2_request_upgrade()
1756 k->upgr101 = UPGR101_H2; in Curl_http2_request_upgrade()
1757 data->conn->bits.asks_multiplex = TRUE; in Curl_http2_request_upgrade()
1769 if(stream->error == NGHTTP2_REFUSED_STREAM) { in http2_handle_stream_close()
1771 "connection", stream->id); in http2_handle_stream_close()
1772 connclose(cf->conn, "REFUSED_STREAM"); /* do not use this anymore */ in http2_handle_stream_close()
1773 data->state.refused_stream = TRUE; in http2_handle_stream_close()
1775 return -1; in http2_handle_stream_close()
1777 else if(stream->error != NGHTTP2_NO_ERROR) { in http2_handle_stream_close()
1778 if(stream->resp_hds_complete && data->req.no_body) { in http2_handle_stream_close()
1781 stream->id, nghttp2_http2_strerror(stream->error), in http2_handle_stream_close()
1782 stream->error); in http2_handle_stream_close()
1783 stream->close_handled = TRUE; in http2_handle_stream_close()
1788 stream->id, nghttp2_http2_strerror(stream->error), in http2_handle_stream_close()
1789 stream->error); in http2_handle_stream_close()
1791 return -1; in http2_handle_stream_close()
1793 else if(stream->reset) { in http2_handle_stream_close()
1794 failf(data, "HTTP/2 stream %u was reset", stream->id); in http2_handle_stream_close()
1795 *err = data->req.bytecount ? CURLE_PARTIAL_FILE : CURLE_HTTP2; in http2_handle_stream_close()
1796 return -1; in http2_handle_stream_close()
1799 if(!stream->bodystarted) { in http2_handle_stream_close()
1802 stream->id); in http2_handle_stream_close()
1804 return -1; in http2_handle_stream_close()
1807 if(Curl_dynhds_count(&stream->resp_trailers)) { in http2_handle_stream_close()
1814 for(i = 0; i < Curl_dynhds_count(&stream->resp_trailers); ++i) { in http2_handle_stream_close()
1815 e = Curl_dynhds_getn(&stream->resp_trailers, i); in http2_handle_stream_close()
1820 (int)e->namelen, e->name, in http2_handle_stream_close()
1821 (int)e->valuelen, e->value); in http2_handle_stream_close()
1836 stream->close_handled = TRUE; in http2_handle_stream_close()
1841 CURL_TRC_CF(data, cf, "handle_stream_close -> %zd, %d", rv, *err); in http2_handle_stream_close()
1847 /* 0 weight is not set by user and we take the nghttp2 default one */ in sweight_wanted()
1848 return data->set.priority.weight ? in sweight_wanted()
1849 data->set.priority.weight : NGHTTP2_DEFAULT_WEIGHT; in sweight_wanted()
1854 /* 0 weight is not set by user and we take the nghttp2 default one */ in sweight_in_effect()
1855 return data->state.priority.weight ? in sweight_in_effect()
1856 data->state.priority.weight : NGHTTP2_DEFAULT_WEIGHT; in sweight_in_effect()
1860 * h2_pri_spec() fills in the pri_spec struct, used by nghttp2 to send weight
1869 struct Curl_data_priority *prio = &data->set.priority; in h2_pri_spec()
1870 struct h2_stream_ctx *depstream = H2_STREAM_CTX(ctx, prio->parent); in h2_pri_spec()
1871 int32_t depstream_id = depstream ? depstream->id : 0; in h2_pri_spec()
1874 data->set.priority.exclusive); in h2_pri_spec()
1875 data->state.priority = *prio; in h2_pri_spec()
1880 * dependency settings and if so it submits a PRIORITY frame with the updated
1887 struct cf_h2_ctx *ctx = cf->ctx; in h2_progress_egress()
1891 if(stream && stream->id > 0 && in h2_progress_egress()
1893 (data->set.priority.exclusive != data->state.priority.exclusive) || in h2_progress_egress()
1894 (data->set.priority.parent != data->state.priority.parent)) ) { in h2_progress_egress()
1899 CURL_TRC_CF(data, cf, "[%d] Queuing PRIORITY", stream->id); in h2_progress_egress()
1900 DEBUGASSERT(stream->id != -1); in h2_progress_egress()
1901 rv = nghttp2_submit_priority(ctx->h2, NGHTTP2_FLAG_NONE, in h2_progress_egress()
1902 stream->id, &pri_spec); in h2_progress_egress()
1907 ctx->nw_out_blocked = 0; in h2_progress_egress()
1908 while(!rv && !ctx->nw_out_blocked && nghttp2_session_want_write(ctx->h2)) in h2_progress_egress()
1909 rv = nghttp2_session_send(ctx->h2); in h2_progress_egress()
1918 * other initial frames are sent together with the first request. in h2_progress_egress()
1920 if(!cf->connected && !cf->conn->connect_only) in h2_progress_egress()
1929 struct cf_h2_ctx *ctx = cf->ctx; in stream_recv()
1930 ssize_t nread = -1; in stream_recv()
1934 if(stream->xfer_result) { in stream_recv()
1935 CURL_TRC_CF(data, cf, "[%d] xfer write failed", stream->id); in stream_recv()
1936 *err = stream->xfer_result; in stream_recv()
1937 nread = -1; in stream_recv()
1939 else if(stream->closed) { in stream_recv()
1940 CURL_TRC_CF(data, cf, "[%d] returning CLOSE", stream->id); in stream_recv()
1943 else if(stream->reset || in stream_recv()
1944 (ctx->conn_closed && Curl_bufq_is_empty(&ctx->inbufq)) || in stream_recv()
1945 (ctx->rcvd_goaway && ctx->remote_max_sid < stream->id)) { in stream_recv()
1946 CURL_TRC_CF(data, cf, "[%d] returning ERR", stream->id); in stream_recv()
1947 *err = data->req.bytecount ? CURLE_PARTIAL_FILE : CURLE_HTTP2; in stream_recv()
1948 nread = -1; in stream_recv()
1952 CURL_TRC_CF(data, cf, "[%d] stream_recv(len=%zu) -> %zd, %d", in stream_recv()
1953 stream->id, len, nread, *err); in stream_recv()
1961 struct cf_h2_ctx *ctx = cf->ctx; in h2_progress_ingress()
1967 if(!Curl_bufq_is_empty(&ctx->inbufq)) { in h2_progress_ingress()
1969 Curl_bufq_len(&ctx->inbufq)); in h2_progress_ingress()
1977 while(!ctx->conn_closed && Curl_bufq_is_empty(&ctx->inbufq)) { in h2_progress_ingress()
1979 if(stream && (stream->closed || !data_max_bytes)) { in h2_progress_ingress()
1984 if(!cf->next || !cf->next->cft->has_data_pending(cf->next, data)) in h2_progress_ingress()
1989 nread = Curl_bufq_sipn(&ctx->inbufq, 0, nw_in_reader, cf, &result); in h2_progress_ingress()
2000 ctx->conn_closed = TRUE; in h2_progress_ingress()
2006 (data_max_bytes - (size_t)nread) : 0; in h2_progress_ingress()
2012 Curl_bufq_len(&ctx->inbufq)); in h2_progress_ingress()
2015 if(ctx->conn_closed && Curl_bufq_is_empty(&ctx->inbufq)) { in h2_progress_ingress()
2016 connclose(cf->conn, "GOAWAY received"); in h2_progress_ingress()
2026 struct cf_h2_ctx *ctx = cf->ctx; in cf_h2_recv()
2028 ssize_t nread = -1; in cf_h2_recv()
2038 "or already cleared, mid=%" FMT_OFF_T, data->mid); in cf_h2_recv()
2040 return -1; in cf_h2_recv()
2061 nghttp2_session_consume(ctx->h2, stream->id, (size_t)nread); in cf_h2_recv()
2062 if(stream->closed) { in cf_h2_recv()
2063 CURL_TRC_CF(data, cf, "[%d] DRAIN closed stream", stream->id); in cf_h2_recv()
2079 nread = -1; in cf_h2_recv()
2081 CURL_TRC_CF(data, cf, "[%d] cf_recv(len=%zu) -> %zd %d, " in cf_h2_recv()
2083 stream->id, len, nread, *err, in cf_h2_recv()
2085 ctx->h2, stream->id), in cf_h2_recv()
2087 ctx->h2, stream->id), in cf_h2_recv()
2088 nghttp2_session_get_local_window_size(ctx->h2), in cf_h2_recv()
2101 struct cf_h2_ctx *ctx = cf->ctx; in cf_h2_body_send()
2104 if(stream->closed) { in cf_h2_body_send()
2105 if(stream->resp_hds_complete) { in cf_h2_body_send()
2112 "on closed stream with response", stream->id); in cf_h2_body_send()
2114 stream->body_eos = TRUE; in cf_h2_body_send()
2119 infof(data, "stream %u closed", stream->id); in cf_h2_body_send()
2121 return -1; in cf_h2_body_send()
2124 nwritten = Curl_bufq_write(&stream->sendbuf, buf, blen, err); in cf_h2_body_send()
2126 return -1; in cf_h2_body_send()
2129 stream->body_eos = TRUE; in cf_h2_body_send()
2131 if(eos || !Curl_bufq_is_empty(&stream->sendbuf)) { in cf_h2_body_send()
2133 int rv = nghttp2_session_resume_data(ctx->h2, stream->id); in cf_h2_body_send()
2136 return -1; in cf_h2_body_send()
2147 struct cf_h2_ctx *ctx = cf->ctx; in h2_submit()
2162 nwritten = -1; in h2_submit()
2166 nwritten = Curl_h1_req_parse_read(&stream->h1, buf, len, NULL, 0, err); in h2_submit()
2169 if(!stream->h1.done) { in h2_submit()
2173 DEBUGASSERT(stream->h1.req); in h2_submit()
2175 *err = Curl_http_req_to_h2(&h2_headers, stream->h1.req, data); in h2_submit()
2177 nwritten = -1; in h2_submit()
2181 Curl_h1_req_parse_free(&stream->h1); in h2_submit()
2186 nwritten = -1; in h2_submit()
2191 if(!nghttp2_session_check_request_allowed(ctx->h2)) in h2_submit()
2192 CURL_TRC_CF(data, cf, "send request NOT allowed (via nghttp2)"); in h2_submit()
2194 switch(data->state.httpreq) { in h2_submit()
2201 stream_id = nghttp2_submit_request(ctx->h2, &pri_spec, nva, nheader, in h2_submit()
2205 stream_id = nghttp2_submit_request(ctx->h2, &pri_spec, nva, nheader, in h2_submit()
2213 nwritten = -1; in h2_submit()
2222 stream_id, data->state.url); in h2_submit()
2238 stream->id = stream_id; in h2_submit()
2241 bodylen = len - nwritten; in h2_submit()
2251 nwritten = -1; in h2_submit()
2257 CURL_TRC_CF(data, cf, "[%d] submit -> %zd, %d", in h2_submit()
2258 stream ? stream->id : -1, nwritten, *err); in h2_submit()
2269 struct cf_h2_ctx *ctx = cf->ctx; in cf_h2_send()
2277 if(!stream || stream->id == -1) { in cf_h2_send()
2284 else if(stream->body_eos) { in cf_h2_send()
2286 * being able to flush stream->sendbuf. Make a 0-length write in cf_h2_send()
2291 CURL_TRC_CF(data, cf, "[%d] cf_body_send last CHUNK -> %zd, %d, eos=%d", in cf_h2_send()
2292 stream->id, nwritten, *err, eos); in cf_h2_send()
2300 CURL_TRC_CF(data, cf, "[%d] cf_body_send(len=%zu) -> %zd, %d, eos=%d", in cf_h2_send()
2301 stream->id, len, nwritten, *err, eos); in cf_h2_send()
2304 /* Call the nghttp2 send loop and flush to write ALL buffered data, in cf_h2_send()
2308 /* if the stream has been closed in egress handling (nghttp2 does that in cf_h2_send()
2310 if(stream && stream->closed) { in cf_h2_send()
2311 infof(data, "stream %u closed", stream->id); in cf_h2_send()
2313 nwritten = -1; in cf_h2_send()
2318 nwritten = -1; in cf_h2_send()
2323 /* nghttp2 thinks this session is done. If the stream has not been in cf_h2_send()
2325 if(stream && stream->closed) { in cf_h2_send()
2331 nwritten = -1; in cf_h2_send()
2337 CURL_TRC_CF(data, cf, "[%d] cf_send(len=%zu) -> %zd, %d, " in cf_h2_send()
2338 "eos=%d, h2 windows %d-%d (stream-conn), " in cf_h2_send()
2339 "buffers %zu-%zu (stream-conn)", in cf_h2_send()
2340 stream->id, len, nwritten, *err, in cf_h2_send()
2341 stream->body_eos, in cf_h2_send()
2343 ctx->h2, stream->id), in cf_h2_send()
2344 nghttp2_session_get_remote_window_size(ctx->h2), in cf_h2_send()
2345 Curl_bufq_len(&stream->sendbuf), in cf_h2_send()
2346 Curl_bufq_len(&ctx->outbufq)); in cf_h2_send()
2349 CURL_TRC_CF(data, cf, "cf_send(len=%zu) -> %zd, %d, " in cf_h2_send()
2350 "connection-window=%d, nw_send_buffer(%zu)", in cf_h2_send()
2352 nghttp2_session_get_remote_window_size(ctx->h2), in cf_h2_send()
2353 Curl_bufq_len(&ctx->outbufq)); in cf_h2_send()
2362 struct cf_h2_ctx *ctx = cf->ctx; in cf_h2_flush()
2368 if(stream && !Curl_bufq_is_empty(&stream->sendbuf)) { in cf_h2_flush()
2370 int rv = nghttp2_session_resume_data(ctx->h2, stream->id); in cf_h2_flush()
2381 CURL_TRC_CF(data, cf, "[%d] flush -> %d, " in cf_h2_flush()
2382 "h2 windows %d-%d (stream-conn), " in cf_h2_flush()
2383 "buffers %zu-%zu (stream-conn)", in cf_h2_flush()
2384 stream->id, result, in cf_h2_flush()
2386 ctx->h2, stream->id), in cf_h2_flush()
2387 nghttp2_session_get_remote_window_size(ctx->h2), in cf_h2_flush()
2388 Curl_bufq_len(&stream->sendbuf), in cf_h2_flush()
2389 Curl_bufq_len(&ctx->outbufq)); in cf_h2_flush()
2392 CURL_TRC_CF(data, cf, "flush -> %d, " in cf_h2_flush()
2393 "connection-window=%d, nw_send_buffer(%zu)", in cf_h2_flush()
2394 result, nghttp2_session_get_remote_window_size(ctx->h2), in cf_h2_flush()
2395 Curl_bufq_len(&ctx->outbufq)); in cf_h2_flush()
2405 struct cf_h2_ctx *ctx = cf->ctx; in cf_h2_adjust_pollset()
2410 if(!ctx->h2) in cf_h2_adjust_pollset()
2420 c_exhaust = want_send && !nghttp2_session_get_remote_window_size(ctx->h2); in cf_h2_adjust_pollset()
2421 s_exhaust = want_send && stream && stream->id >= 0 && in cf_h2_adjust_pollset()
2422 !nghttp2_session_get_stream_remote_window_size(ctx->h2, in cf_h2_adjust_pollset()
2423 stream->id); in cf_h2_adjust_pollset()
2426 (!c_exhaust && nghttp2_session_want_write(ctx->h2)) || in cf_h2_adjust_pollset()
2427 !Curl_bufq_is_empty(&ctx->outbufq); in cf_h2_adjust_pollset()
2432 else if(ctx->sent_goaway && !cf->shutdown) { in cf_h2_adjust_pollset()
2435 want_send = nghttp2_session_want_write(ctx->h2) || in cf_h2_adjust_pollset()
2436 !Curl_bufq_is_empty(&ctx->outbufq); in cf_h2_adjust_pollset()
2437 want_recv = nghttp2_session_want_read(ctx->h2); in cf_h2_adjust_pollset()
2447 struct cf_h2_ctx *ctx = cf->ctx; in cf_h2_connect()
2452 if(cf->connected) { in cf_h2_connect()
2458 if(!cf->next->connected) { in cf_h2_connect()
2459 result = Curl_conn_cf_connect(cf->next, data, blocking, done); in cf_h2_connect()
2467 DEBUGASSERT(ctx->initialized); in cf_h2_connect()
2468 if(!ctx->h2) { in cf_h2_connect()
2488 cf->connected = TRUE; in cf_h2_connect()
2492 CURL_TRC_CF(data, cf, "cf_connect() -> %d, %d, ", result, *done); in cf_h2_connect()
2499 struct cf_h2_ctx *ctx = cf->ctx; in cf_h2_close()
2507 cf->connected = FALSE; in cf_h2_close()
2509 if(cf->next) in cf_h2_close()
2510 cf->next->cft->do_close(cf->next, data); in cf_h2_close()
2515 struct cf_h2_ctx *ctx = cf->ctx; in cf_h2_destroy()
2520 cf->ctx = NULL; in cf_h2_destroy()
2527 struct cf_h2_ctx *ctx = cf->ctx; in cf_h2_shutdown()
2532 if(!cf->connected || !ctx->h2 || cf->shutdown || ctx->conn_closed) { in cf_h2_shutdown()
2539 if(!ctx->sent_goaway) { in cf_h2_shutdown()
2540 rv = nghttp2_submit_goaway(ctx->h2, NGHTTP2_FLAG_NONE, in cf_h2_shutdown()
2541 ctx->local_max_sid, 0, in cf_h2_shutdown()
2550 ctx->sent_goaway = TRUE; in cf_h2_shutdown()
2552 /* GOAWAY submitted, process egress and ingress until nghttp2 is done. */ in cf_h2_shutdown()
2554 if(nghttp2_session_want_write(ctx->h2) || in cf_h2_shutdown()
2555 !Curl_bufq_is_empty(&ctx->outbufq)) in cf_h2_shutdown()
2557 if(!result && nghttp2_session_want_read(ctx->h2)) in cf_h2_shutdown()
2563 *done = (ctx->conn_closed || in cf_h2_shutdown()
2564 (!result && !nghttp2_session_want_write(ctx->h2) && in cf_h2_shutdown()
2565 !nghttp2_session_want_read(ctx->h2) && in cf_h2_shutdown()
2566 Curl_bufq_is_empty(&ctx->outbufq))); in cf_h2_shutdown()
2570 cf->shutdown = (result || *done); in cf_h2_shutdown()
2578 struct cf_h2_ctx *ctx = cf->ctx; in http2_data_pause()
2582 if(ctx && ctx->h2 && stream) { in http2_data_pause()
2599 CURL_TRC_CF(data, cf, "[%d] stream now %spaused", stream->id, in http2_data_pause()
2637 struct cf_h2_ctx *ctx = cf->ctx; in cf_h2_data_pending()
2639 if(ctx && !Curl_bufq_is_empty(&ctx->inbufq)) in cf_h2_data_pending()
2641 return cf->next ? cf->next->cft->has_data_pending(cf->next, data) : FALSE; in cf_h2_data_pending()
2648 struct cf_h2_ctx *ctx = cf->ctx; in cf_h2_is_alive()
2653 result = (ctx && ctx->h2 && http2_connisalive(cf, data, input_pending)); in cf_h2_is_alive()
2654 CURL_TRC_CF(data, cf, "conn alive -> %d, input_pending=%d", in cf_h2_is_alive()
2676 struct cf_h2_ctx *ctx = cf->ctx; in cf_h2_query()
2685 if(nghttp2_session_check_request_allowed(ctx->h2) == 0) { in cf_h2_query()
2687 effective_max = CONN_INUSE(cf->conn); in cf_h2_query()
2690 effective_max = ctx->max_concurrent_streams; in cf_h2_query()
2697 *pres1 = stream ? (int)stream->error : 0; in cf_h2_query()
2702 if(!Curl_bufq_is_empty(&ctx->outbufq) || in cf_h2_query()
2703 (stream && !Curl_bufq_is_empty(&stream->sendbuf))) { in cf_h2_query()
2715 return cf->next ? in cf_h2_query()
2716 cf->next->cft->query(cf->next, data, query, pres1, pres2) : in cf_h2_query()
2749 DEBUGASSERT(data->conn); in http2_cfilter_add()
2799 data->state.httpwant == CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE) { in Curl_http2_may_switch()
2801 if(data->conn->bits.httpproxy && !data->conn->bits.tunnel_proxy) { in Curl_http2_may_switch()
2820 result = http2_cfilter_add(&cf, data, data->conn, FIRSTSOCKET, FALSE); in Curl_http2_switch()
2825 data->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */ in Curl_http2_switch()
2826 Curl_multi_connchanged(data->multi); in Curl_http2_switch()
2828 if(cf->next) { in Curl_http2_switch()
2846 cf_h2 = cf->next; in Curl_http2_switch_at()
2847 cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */ in Curl_http2_switch_at()
2848 Curl_multi_connchanged(data->multi); in Curl_http2_switch_at()
2850 if(cf_h2->next) { in Curl_http2_switch_at()
2866 DEBUGASSERT(data->req.upgr101 == UPGR101_RECEIVED); in Curl_http2_upgrade()
2873 DEBUGASSERT(cf->cft == &Curl_cft_nghttp2); in Curl_http2_upgrade()
2874 ctx = cf->ctx; in Curl_http2_upgrade()
2882 copied = Curl_bufq_write(&ctx->inbufq, in Curl_http2_upgrade()
2898 conn->bits.multiplex = TRUE; /* at least potentially multiplexed */ in Curl_http2_upgrade()
2899 Curl_multi_connchanged(data->multi); in Curl_http2_upgrade()
2901 if(cf->next) { in Curl_http2_upgrade()
2913 int err = Curl_conn_get_stream_error(data, data->conn, FIRSTSOCKET); in Curl_h2_http_1_1_error()