• Home
  • Raw
  • Download

Lines Matching +full:- +full:- +full:without +full:- +full:nghttp2

18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * SPDX-License-Identifier: curl
29 #include <nghttp2/nghttp2.h>
42 #include "urlapi-int.h"
57 #error too old nghttp2 version, upgrade!
100 iv[0].value = Curl_multi_max_concurrent_streams(data->multi); in populate_settings()
106 iv[2].value = data->multi->push_cb != NULL; in populate_settings()
133 struct Curl_hash streams; /* hash of `data->id` to `h2_stream_ctx` */
147 ((struct cf_h2_ctx *)(cf)->ctx)->call_data
151 struct cf_call_data save = ctx->call_data; in cf_h2_ctx_clear()
153 if(ctx->h2) { in cf_h2_ctx_clear()
154 nghttp2_session_del(ctx->h2); in cf_h2_ctx_clear()
156 Curl_bufq_free(&ctx->inbufq); in cf_h2_ctx_clear()
157 Curl_bufq_free(&ctx->outbufq); in cf_h2_ctx_clear()
158 Curl_bufcp_free(&ctx->stream_bufcp); in cf_h2_ctx_clear()
159 Curl_dyn_free(&ctx->scratch); in cf_h2_ctx_clear()
160 Curl_hash_clean(&ctx->streams); in cf_h2_ctx_clear()
161 Curl_hash_destroy(&ctx->streams); in cf_h2_ctx_clear()
163 ctx->call_data = save; in cf_h2_ctx_clear()
205 buffered data in stream->sendbuf to upload. */
209 data? Curl_hash_offt_get(&(ctx)->streams, (data)->id) : NULL))
220 stream->id = -1; in h2_stream_ctx_create()
221 Curl_bufq_initp(&stream->sendbuf, &ctx->stream_bufcp, in h2_stream_ctx_create()
223 Curl_h1_req_parse_init(&stream->h1, H1_PARSE_DEFAULT_MAX_LINE_LEN); in h2_stream_ctx_create()
224 Curl_dynhds_init(&stream->resp_trailers, 0, DYN_HTTP_REQUEST); in h2_stream_ctx_create()
225 stream->resp_hds_len = 0; in h2_stream_ctx_create()
226 stream->bodystarted = FALSE; in h2_stream_ctx_create()
227 stream->status_code = -1; in h2_stream_ctx_create()
228 stream->closed = FALSE; in h2_stream_ctx_create()
229 stream->close_handled = FALSE; in h2_stream_ctx_create()
230 stream->error = NGHTTP2_NO_ERROR; in h2_stream_ctx_create()
231 stream->local_window_size = H2_STREAM_WINDOW_SIZE; in h2_stream_ctx_create()
232 stream->upload_left = 0; in h2_stream_ctx_create()
233 stream->nrcvd_data = 0; in h2_stream_ctx_create()
240 for(i = 0; i<stream->push_headers_used; i++) in free_push_headers()
241 free(stream->push_headers[i]); in free_push_headers()
242 Curl_safefree(stream->push_headers); in free_push_headers()
243 stream->push_headers_used = 0; in free_push_headers()
248 Curl_bufq_free(&stream->sendbuf); in h2_stream_ctx_free()
249 Curl_h1_req_parse_free(&stream->h1); in h2_stream_ctx_free()
250 Curl_dynhds_free(&stream->resp_trailers); in h2_stream_ctx_free()
272 if(!stream->send_closed && in drain_stream()
273 (stream->upload_left || stream->upload_blocked_len)) in drain_stream()
275 if(data->state.select_bits != bits) { in drain_stream()
277 stream->id, bits); in drain_stream()
278 data->state.select_bits = bits; in drain_stream()
287 struct cf_h2_ctx *ctx = cf->ctx; in http2_data_setup()
292 if(!data->req.p.http) { in http2_data_setup()
306 if(!Curl_hash_offt_set(&ctx->streams, data->id, stream)) { in http2_data_setup()
317 struct cf_h2_ctx *ctx = cf->ctx; in http2_data_done()
324 if(ctx->h2) { in http2_data_done()
327 (void)nghttp2_session_set_stream_user_data(ctx->h2, stream->id, NULL); in http2_data_done()
329 if(!stream->closed && stream->id > 0) { in http2_data_done()
332 stream->id); in http2_data_done()
333 stream->closed = TRUE; in http2_data_done()
334 stream->reset = TRUE; in http2_data_done()
335 stream->send_closed = TRUE; in http2_data_done()
336 nghttp2_submit_rst_stream(ctx->h2, NGHTTP2_FLAG_NONE, in http2_data_done()
337 stream->id, NGHTTP2_STREAM_CLOSED); in http2_data_done()
342 nghttp2_session_send(ctx->h2); in http2_data_done()
345 Curl_hash_offt_remove(&ctx->streams, data->id); in http2_data_done()
351 struct cf_h2_ctx *ctx = cf->ctx; in h2_client_new()
365 rc = nghttp2_session_client_new2(&ctx->h2, cbs, cf, o); in h2_client_new()
377 return Curl_conn_cf_recv(cf->next, data, (char *)buf, buflen, err); in nw_in_reader()
388 ssize_t nwritten = Curl_conn_cf_send(cf->next, data, in nw_out_writer()
428 struct cf_h2_ctx *ctx = cf->ctx; in cf_h2_ctx_init()
434 DEBUGASSERT(!ctx->h2); in cf_h2_ctx_init()
435 Curl_bufcp_init(&ctx->stream_bufcp, H2_CHUNK_SIZE, H2_STREAM_POOL_SPARES); in cf_h2_ctx_init()
436 Curl_bufq_initp(&ctx->inbufq, &ctx->stream_bufcp, H2_NW_RECV_CHUNKS, 0); in cf_h2_ctx_init()
437 Curl_bufq_initp(&ctx->outbufq, &ctx->stream_bufcp, H2_NW_SEND_CHUNKS, 0); in cf_h2_ctx_init()
438 Curl_dyn_init(&ctx->scratch, CURL_MAX_HTTP_HEADER); in cf_h2_ctx_init()
439 Curl_hash_offt_init(&ctx->streams, 63, h2_stream_hash_free); in cf_h2_ctx_init()
440 ctx->last_stream_id = 2147483647; in cf_h2_ctx_init()
444 failf(data, "Couldn't initialize nghttp2 callbacks"); in cf_h2_ctx_init()
461 /* The nghttp2 session is not yet setup, do it */ in cf_h2_ctx_init()
464 failf(data, "Couldn't initialize nghttp2"); in cf_h2_ctx_init()
467 ctx->max_concurrent_streams = DEFAULT_MAX_CONCURRENT_STREAMS; in cf_h2_ctx_init()
478 failf(data, "nghttp2 unexpectedly failed on pack_settings_payload"); in cf_h2_ctx_init()
487 stream->id = 1; in cf_h2_ctx_init()
489 rc = nghttp2_session_upgrade2(ctx->h2, binsettings, binlen, in cf_h2_ctx_init()
490 data->state.httpreq == HTTPREQ_HEAD, in cf_h2_ctx_init()
499 rc = nghttp2_session_set_stream_user_data(ctx->h2, stream->id, in cf_h2_ctx_init()
503 stream->id); in cf_h2_ctx_init()
513 rc = nghttp2_submit_settings(ctx->h2, NGHTTP2_FLAG_NONE, in cf_h2_ctx_init()
523 rc = nghttp2_session_set_local_window_size(ctx->h2, NGHTTP2_FLAG_NONE, 0, in cf_h2_ctx_init()
548 return ctx->drain_total == 0 && !nghttp2_session_want_read(ctx->h2) && in should_close_session()
549 !nghttp2_session_want_write(ctx->h2); in should_close_session()
554 * This function returns 0 if it succeeds, or -1 and error code will
561 struct cf_h2_ctx *ctx = cf->ctx; in h2_process_pending_input()
566 while(Curl_bufq_peek(&ctx->inbufq, &buf, &blen)) { in h2_process_pending_input()
568 rv = nghttp2_session_mem_recv(ctx->h2, (const uint8_t *)buf, blen); in h2_process_pending_input()
574 return -1; in h2_process_pending_input()
576 Curl_bufq_skip(&ctx->inbufq, (size_t)rv); in h2_process_pending_input()
577 if(Curl_bufq_is_empty(&ctx->inbufq)) { in h2_process_pending_input()
582 "in connection buffer", Curl_bufq_len(&ctx->inbufq)); in h2_process_pending_input()
586 if(nghttp2_session_check_request_allowed(ctx->h2) == 0) { in h2_process_pending_input()
591 connclose(cf->conn, "http/2: No new requests allowed"); in h2_process_pending_input()
607 struct cf_h2_ctx *ctx = cf->ctx; in http2_connisalive()
611 if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending)) in http2_connisalive()
619 ssize_t nread = -1; in http2_connisalive()
622 nread = Curl_bufq_slurp(&ctx->inbufq, nw_in_reader, cf, &result); in http2_connisalive()
623 if(nread != -1) { in http2_connisalive()
645 struct cf_h2_ctx *ctx = cf->ctx; in http2_send_ping()
648 rc = nghttp2_submit_ping(ctx->h2, 0, ZERO_NULL); in http2_send_ping()
655 rc = nghttp2_session_send(ctx->h2); in http2_send_ping()
665 * Store nghttp2 version info in this buffer.
670 (void)msnprintf(p, len, "nghttp2/%s", h2->version_str); in Curl_http2_ver()
676 struct cf_h2_ctx *ctx = cf->ctx; in nw_out_flush()
681 if(Curl_bufq_is_empty(&ctx->outbufq)) in nw_out_flush()
684 nwritten = Curl_bufq_pass(&ctx->outbufq, nw_out_writer, cf, &result); in nw_out_flush()
687 CURL_TRC_CF(data, cf, "flush nw send buffer(%zu) -> EAGAIN", in nw_out_flush()
688 Curl_bufq_len(&ctx->outbufq)); in nw_out_flush()
689 ctx->nw_out_blocked = 1; in nw_out_flush()
693 return Curl_bufq_is_empty(&ctx->outbufq)? CURLE_OK: CURLE_AGAIN; in nw_out_flush()
706 struct cf_h2_ctx *ctx = cf->ctx; in send_callback()
715 nwritten = Curl_bufq_write_pass(&ctx->outbufq, buf, blen, in send_callback()
719 ctx->nw_out_blocked = 1; in send_callback()
727 ctx->nw_out_blocked = 1; in send_callback()
749 if(!h || !GOOD_EASY_HANDLE(h->data)) in curl_pushheader_bynum()
752 if(h->stream && num < h->stream->push_headers_used) in curl_pushheader_bynum()
753 return h->stream->push_headers[num]; in curl_pushheader_bynum()
772 if(!h || !GOOD_EASY_HANDLE(h->data) || !header || !header[0] || in curl_pushheader_byname()
776 stream = h->stream; in curl_pushheader_byname()
781 for(i = 0; i<stream->push_headers_used; i++) { in curl_pushheader_byname()
782 if(!strncmp(header, stream->push_headers[i], len)) { in curl_pushheader_byname()
783 /* sub-match, make sure that it is followed by a colon */ in curl_pushheader_byname()
784 if(stream->push_headers[i][len] != ':') in curl_pushheader_byname()
786 return &stream->push_headers[i][len + 1]; in curl_pushheader_byname()
805 second->req.p.http = http; in h2_duphandle()
807 second->state.priority.weight = data->state.priority.weight; in h2_duphandle()
860 if(data->state.url_alloc) in set_transfer_url()
861 free(data->state.url); in set_transfer_url()
862 data->state.url_alloc = TRUE; in set_transfer_url()
863 data->state.url = url; in set_transfer_url()
870 if(newhandle->req.p.http) { in discard_newhandle()
880 struct cf_h2_ctx *ctx = cf->ctx; in push_promise()
884 frame->promised_stream_id); in push_promise()
885 if(data->multi->push_cb) { in push_promise()
931 rv = data->multi->push_cb(data, newhandle, in push_promise()
932 stream->push_headers_used, &heads, in push_promise()
933 data->multi->push_userp); in push_promise()
946 newstream->id = frame->promised_stream_id; in push_promise()
947 newhandle->req.maxdownload = -1; in push_promise()
948 newhandle->req.size = -1; in push_promise()
952 rc = Curl_multi_add_perform(data->multi, newhandle, cf->conn); in push_promise()
960 rv = nghttp2_session_set_stream_user_data(ctx->h2, in push_promise()
961 newstream->id, in push_promise()
965 newstream->id); in push_promise()
986 if(!stream->xfer_result) { in h2_xfer_write_resp_hd()
987 stream->xfer_result = Curl_xfer_write_resp_hd(data, buf, blen, eos); in h2_xfer_write_resp_hd()
988 if(stream->xfer_result) in h2_xfer_write_resp_hd()
990 stream->id, stream->xfer_result, blen); in h2_xfer_write_resp_hd()
1001 if(!stream->xfer_result) in h2_xfer_write_resp()
1002 stream->xfer_result = Curl_xfer_write_resp(data, buf, blen, eos); in h2_xfer_write_resp()
1004 if(stream->xfer_result) { in h2_xfer_write_resp()
1005 struct cf_h2_ctx *ctx = cf->ctx; in h2_xfer_write_resp()
1007 "RST-ing stream", in h2_xfer_write_resp()
1008 stream->id, stream->xfer_result, blen); in h2_xfer_write_resp()
1009 nghttp2_submit_rst_stream(ctx->h2, 0, stream->id, in h2_xfer_write_resp()
1018 struct cf_h2_ctx *ctx = cf->ctx; in on_stream_frame()
1020 int32_t stream_id = frame->hd.stream_id; in on_stream_frame()
1028 switch(frame->hd.type) { in on_stream_frame()
1033 ctx->h2, stream->id), in on_stream_frame()
1035 ctx->h2, stream->id)); in on_stream_frame()
1037 if(!stream->bodystarted) { in on_stream_frame()
1038 rv = nghttp2_submit_rst_stream(ctx->h2, NGHTTP2_FLAG_NONE, in on_stream_frame()
1045 if(frame->hd.flags & NGHTTP2_FLAG_END_STREAM) { in on_stream_frame()
1050 if(stream->bodystarted) { in on_stream_frame()
1056 /* nghttp2 guarantees that :status is received, and we store it to in on_stream_frame()
1057 stream->status_code. Fuzzing has proven this can still be reached in on_stream_frame()
1058 without status code having been set. */ in on_stream_frame()
1059 if(stream->status_code == -1) in on_stream_frame()
1063 if(stream->status_code / 100 != 1) { in on_stream_frame()
1064 stream->bodystarted = TRUE; in on_stream_frame()
1065 stream->status_code = -1; in on_stream_frame()
1068 h2_xfer_write_resp_hd(cf, data, stream, STRCONST("\r\n"), stream->closed); in on_stream_frame()
1070 if(stream->status_code / 100 != 1) { in on_stream_frame()
1071 stream->resp_hds_complete = TRUE; in on_stream_frame()
1076 rv = push_promise(cf, data, &frame->push_promise); in on_stream_frame()
1079 rv = nghttp2_submit_rst_stream(ctx->h2, NGHTTP2_FLAG_NONE, in on_stream_frame()
1080 frame->push_promise.promised_stream_id, in on_stream_frame()
1092 stream->closed = TRUE; in on_stream_frame()
1093 if(frame->rst_stream.error_code) { in on_stream_frame()
1094 stream->reset = TRUE; in on_stream_frame()
1096 stream->send_closed = TRUE; in on_stream_frame()
1113 switch(frame->hd.type) { in fr_print()
1117 (int)frame->hd.length, in fr_print()
1118 !!(frame->hd.flags & NGHTTP2_FLAG_END_STREAM), in fr_print()
1119 (int)frame->data.padlen); in fr_print()
1124 (int)frame->hd.length, in fr_print()
1125 !!(frame->hd.flags & NGHTTP2_FLAG_END_HEADERS), in fr_print()
1126 !!(frame->hd.flags & NGHTTP2_FLAG_END_STREAM)); in fr_print()
1131 (int)frame->hd.length, frame->hd.flags); in fr_print()
1136 (int)frame->hd.length, frame->hd.flags, in fr_print()
1137 frame->rst_stream.error_code); in fr_print()
1140 if(frame->hd.flags & NGHTTP2_FLAG_ACK) { in fr_print()
1144 "FRAME[SETTINGS, len=%d]", (int)frame->hd.length); in fr_print()
1149 (int)frame->hd.length, in fr_print()
1150 !!(frame->hd.flags & NGHTTP2_FLAG_END_HEADERS)); in fr_print()
1155 (int)frame->hd.length, in fr_print()
1156 frame->hd.flags&NGHTTP2_FLAG_ACK); in fr_print()
1161 size_t len = (frame->goaway.opaque_data_len < s_len)? in fr_print()
1162 frame->goaway.opaque_data_len : s_len-1; in fr_print()
1164 memcpy(scratch, frame->goaway.opaque_data, len); in fr_print()
1167 "last_stream=%d]", frame->goaway.error_code, in fr_print()
1168 scratch, frame->goaway.last_stream_id); in fr_print()
1173 frame->window_update.window_size_increment); in fr_print()
1177 frame->hd.type, (int)frame->hd.length, in fr_print()
1178 frame->hd.flags); in fr_print()
1193 len = fr_print(frame, buffer, sizeof(buffer)-1); in on_frame_send()
1195 CURL_TRC_CF(data, cf, "[%d] -> %s", frame->hd.stream_id, buffer); in on_frame_send()
1205 struct cf_h2_ctx *ctx = cf->ctx; in on_frame_recv()
1207 int32_t stream_id = frame->hd.stream_id; in on_frame_recv()
1214 len = fr_print(frame, buffer, sizeof(buffer)-1); in on_frame_recv()
1216 CURL_TRC_CF(data, cf, "[%d] <- %s",frame->hd.stream_id, buffer); in on_frame_recv()
1221 /* stream ID zero is for connection-oriented stuff */ in on_frame_recv()
1223 switch(frame->hd.type) { in on_frame_recv()
1225 if(!(frame->hd.flags & NGHTTP2_FLAG_ACK)) { in on_frame_recv()
1226 uint32_t max_conn = ctx->max_concurrent_streams; in on_frame_recv()
1227 ctx->max_concurrent_streams = nghttp2_session_get_remote_settings( in on_frame_recv()
1229 ctx->enable_push = nghttp2_session_get_remote_settings( in on_frame_recv()
1232 ctx->max_concurrent_streams); in on_frame_recv()
1234 ctx->enable_push ? "TRUE" : "false"); in on_frame_recv()
1235 if(data && max_conn != ctx->max_concurrent_streams) { in on_frame_recv()
1238 ctx->max_concurrent_streams); in on_frame_recv()
1239 Curl_multi_connchanged(data->multi); in on_frame_recv()
1255 ctx->goaway = TRUE; in on_frame_recv()
1256 ctx->goaway_error = frame->goaway.error_code; in on_frame_recv()
1257 ctx->last_stream_id = frame->goaway.last_stream_id; in on_frame_recv()
1260 ctx->goaway_error, ctx->last_stream_id); in on_frame_recv()
1261 Curl_multi_connchanged(data->multi); in on_frame_recv()
1284 struct cf_h2_ctx *ctx = cf->ctx; in on_data_chunk_recv()
1295 /* Receiving a Stream ID not in the hash should not happen - unless in on_data_chunk_recv()
1311 nghttp2_session_consume(ctx->h2, stream_id, len); in on_data_chunk_recv()
1312 stream->nrcvd_data += (curl_off_t)len; in on_data_chunk_recv()
1323 struct cf_h2_ctx *ctx = cf->ctx; in on_stream_close()
1331 connection-oriented stuff */ in on_stream_close()
1340 /* nghttp2 still has an easy registered for the stream which has in on_stream_close()
1355 stream->closed = TRUE; in on_stream_close()
1356 stream->error = error_code; in on_stream_close()
1357 if(stream->error) { in on_stream_close()
1358 stream->reset = TRUE; in on_stream_close()
1359 stream->send_closed = TRUE; in on_stream_close()
1362 if(stream->error) in on_stream_close()
1369 /* remove `data_s` from the nghttp2 stream */ in on_stream_close()
1383 struct cf_h2_ctx *ctx = cf->ctx; in on_begin_headers()
1388 data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id); in on_begin_headers()
1393 if(frame->hd.type != NGHTTP2_HEADERS) { in on_begin_headers()
1398 if(!stream || !stream->bodystarted) { in on_begin_headers()
1405 /* frame->hd.type is either NGHTTP2_HEADERS or NGHTTP2_PUSH_PROMISE */
1413 struct cf_h2_ctx *ctx = cf->ctx; in on_header()
1416 int32_t stream_id = frame->hd.stream_id; in on_header()
1437 if(frame->hd.type == NGHTTP2_PUSH_PROMISE) { in on_header()
1443 char *check = aprintf("%s:%d", cf->conn->host.name, in on_header()
1444 cf->conn->remote_port); in on_header()
1449 ((cf->conn->remote_port != cf->conn->given->defport) || in on_header()
1450 !strcasecompare(cf->conn->host.name, (const char *)value))) { in on_header()
1465 if(!stream->push_headers) { in on_header()
1466 stream->push_headers_alloc = 10; in on_header()
1467 stream->push_headers = malloc(stream->push_headers_alloc * in on_header()
1469 if(!stream->push_headers) in on_header()
1471 stream->push_headers_used = 0; in on_header()
1473 else if(stream->push_headers_used == in on_header()
1474 stream->push_headers_alloc) { in on_header()
1476 if(stream->push_headers_alloc > 1000) { in on_header()
1482 stream->push_headers_alloc *= 2; in on_header()
1483 headp = realloc(stream->push_headers, in on_header()
1484 stream->push_headers_alloc * sizeof(char *)); in on_header()
1489 stream->push_headers = headp; in on_header()
1493 stream->push_headers[stream->push_headers_used++] = h; in on_header()
1497 if(stream->bodystarted) { in on_header()
1500 stream->id, (int)namelen, name, (int)valuelen, value); in on_header()
1501 result = Curl_dynhds_add(&stream->resp_trailers, in on_header()
1510 if(namelen == sizeof(HTTP_PSEUDO_STATUS) - 1 && in on_header()
1512 /* nghttp2 guarantees :status is received first and only once. */ in on_header()
1514 result = Curl_http_decode_status(&stream->status_code, in on_header()
1519 stream->status_code); in on_header()
1523 Curl_dyn_reset(&ctx->scratch); in on_header()
1524 result = Curl_dyn_addn(&ctx->scratch, STRCONST("HTTP/2 ")); in on_header()
1526 result = Curl_dyn_addn(&ctx->scratch, value, valuelen); in on_header()
1528 result = Curl_dyn_addn(&ctx->scratch, STRCONST(" \r\n")); in on_header()
1530 h2_xfer_write_resp_hd(cf, data_s, stream, Curl_dyn_ptr(&ctx->scratch), in on_header()
1531 Curl_dyn_len(&ctx->scratch), FALSE); in on_header()
1539 stream->id, stream->status_code); in on_header()
1543 /* nghttp2 guarantees that namelen > 0, and :status was already in on_header()
1544 received, and this is not pseudo-header field . */ in on_header()
1545 /* convert to an HTTP1-style header */ in on_header()
1546 Curl_dyn_reset(&ctx->scratch); in on_header()
1547 result = Curl_dyn_addn(&ctx->scratch, (const char *)name, namelen); in on_header()
1549 result = Curl_dyn_addn(&ctx->scratch, STRCONST(": ")); in on_header()
1551 result = Curl_dyn_addn(&ctx->scratch, (const char *)value, valuelen); in on_header()
1553 result = Curl_dyn_addn(&ctx->scratch, STRCONST("\r\n")); in on_header()
1555 h2_xfer_write_resp_hd(cf, data_s, stream, Curl_dyn_ptr(&ctx->scratch), in on_header()
1556 Curl_dyn_len(&ctx->scratch), FALSE); in on_header()
1564 stream->id, (int)namelen, name, (int)valuelen, value); in on_header()
1577 struct cf_h2_ctx *ctx = cf->ctx; in req_body_read_callback()
1587 connection-oriented stuff */ in req_body_read_callback()
1601 nread = Curl_bufq_read(&stream->sendbuf, buf, length, &result); in req_body_read_callback()
1608 if(nread > 0 && stream->upload_left != -1) in req_body_read_callback()
1609 stream->upload_left -= nread; in req_body_read_callback()
1612 CURL_FORMAT_CURL_OFF_T " -> %zd, %d", in req_body_read_callback()
1613 stream_id, length, stream->upload_left, nread, result); in req_body_read_callback()
1615 if(stream->upload_left == 0) in req_body_read_callback()
1646 struct SingleRequest *k = &data->req; in Curl_http2_request_upgrade()
1652 failf(data, "nghttp2 unexpectedly failed on pack_settings_payload"); in Curl_http2_request_upgrade()
1665 "Connection: Upgrade, HTTP2-Settings\r\n" in Curl_http2_request_upgrade()
1667 "HTTP2-Settings: %s\r\n", in Curl_http2_request_upgrade()
1671 k->upgr101 = UPGR101_H2; in Curl_http2_request_upgrade()
1679 struct cf_h2_ctx *ctx = cf->ctx; in http2_data_done_send()
1683 if(!ctx || !ctx->h2 || !stream) in http2_data_done_send()
1686 CURL_TRC_CF(data, cf, "[%d] data done send", stream->id); in http2_data_done_send()
1687 if(!stream->send_closed) { in http2_data_done_send()
1688 stream->send_closed = TRUE; in http2_data_done_send()
1689 if(stream->upload_left) { in http2_data_done_send()
1691 stream->upload_left = Curl_bufq_len(&stream->sendbuf); in http2_data_done_send()
1693 that it can signal EOF to nghttp2 */ in http2_data_done_send()
1694 (void)nghttp2_session_resume_data(ctx->h2, stream->id); in http2_data_done_send()
1710 if(stream->error == NGHTTP2_REFUSED_STREAM) { in http2_handle_stream_close()
1712 "connection", stream->id); in http2_handle_stream_close()
1713 connclose(cf->conn, "REFUSED_STREAM"); /* don't use this anymore */ in http2_handle_stream_close()
1714 data->state.refused_stream = TRUE; in http2_handle_stream_close()
1716 return -1; in http2_handle_stream_close()
1718 else if(stream->error != NGHTTP2_NO_ERROR) { in http2_handle_stream_close()
1719 if(stream->resp_hds_complete && data->req.no_body) { in http2_handle_stream_close()
1722 stream->id, nghttp2_http2_strerror(stream->error), in http2_handle_stream_close()
1723 stream->error); in http2_handle_stream_close()
1724 stream->close_handled = TRUE; in http2_handle_stream_close()
1729 stream->id, nghttp2_http2_strerror(stream->error), in http2_handle_stream_close()
1730 stream->error); in http2_handle_stream_close()
1732 return -1; in http2_handle_stream_close()
1734 else if(stream->reset) { in http2_handle_stream_close()
1735 failf(data, "HTTP/2 stream %u was reset", stream->id); in http2_handle_stream_close()
1736 *err = data->req.bytecount? CURLE_PARTIAL_FILE : CURLE_HTTP2; in http2_handle_stream_close()
1737 return -1; in http2_handle_stream_close()
1740 if(!stream->bodystarted) { in http2_handle_stream_close()
1743 stream->id); in http2_handle_stream_close()
1745 return -1; in http2_handle_stream_close()
1748 if(Curl_dynhds_count(&stream->resp_trailers)) { in http2_handle_stream_close()
1755 for(i = 0; i < Curl_dynhds_count(&stream->resp_trailers); ++i) { in http2_handle_stream_close()
1756 e = Curl_dynhds_getn(&stream->resp_trailers, i); in http2_handle_stream_close()
1761 (int)e->namelen, e->name, in http2_handle_stream_close()
1762 (int)e->valuelen, e->value); in http2_handle_stream_close()
1777 stream->close_handled = TRUE; in http2_handle_stream_close()
1782 CURL_TRC_CF(data, cf, "handle_stream_close -> %zd, %d", rv, *err); in http2_handle_stream_close()
1788 /* 0 weight is not set by user and we take the nghttp2 default one */ in sweight_wanted()
1789 return data->set.priority.weight? in sweight_wanted()
1790 data->set.priority.weight : NGHTTP2_DEFAULT_WEIGHT; in sweight_wanted()
1795 /* 0 weight is not set by user and we take the nghttp2 default one */ in sweight_in_effect()
1796 return data->state.priority.weight? in sweight_in_effect()
1797 data->state.priority.weight : NGHTTP2_DEFAULT_WEIGHT; in sweight_in_effect()
1801 * h2_pri_spec() fills in the pri_spec struct, used by nghttp2 to send weight
1810 struct Curl_data_priority *prio = &data->set.priority; in h2_pri_spec()
1811 struct h2_stream_ctx *depstream = H2_STREAM_CTX(ctx, prio->parent); in h2_pri_spec()
1812 int32_t depstream_id = depstream? depstream->id:0; in h2_pri_spec()
1815 data->set.priority.exclusive); in h2_pri_spec()
1816 data->state.priority = *prio; in h2_pri_spec()
1828 struct cf_h2_ctx *ctx = cf->ctx; in h2_progress_egress()
1832 if(stream && stream->id > 0 && in h2_progress_egress()
1834 (data->set.priority.exclusive != data->state.priority.exclusive) || in h2_progress_egress()
1835 (data->set.priority.parent != data->state.priority.parent)) ) { in h2_progress_egress()
1840 CURL_TRC_CF(data, cf, "[%d] Queuing PRIORITY", stream->id); in h2_progress_egress()
1841 DEBUGASSERT(stream->id != -1); in h2_progress_egress()
1842 rv = nghttp2_submit_priority(ctx->h2, NGHTTP2_FLAG_NONE, in h2_progress_egress()
1843 stream->id, &pri_spec); in h2_progress_egress()
1848 ctx->nw_out_blocked = 0; in h2_progress_egress()
1849 while(!rv && !ctx->nw_out_blocked && nghttp2_session_want_write(ctx->h2)) in h2_progress_egress()
1850 rv = nghttp2_session_send(ctx->h2); in h2_progress_egress()
1865 struct cf_h2_ctx *ctx = cf->ctx; in stream_recv()
1866 ssize_t nread = -1; in stream_recv()
1870 if(stream->xfer_result) { in stream_recv()
1871 CURL_TRC_CF(data, cf, "[%d] xfer write failed", stream->id); in stream_recv()
1872 *err = stream->xfer_result; in stream_recv()
1873 nread = -1; in stream_recv()
1875 else if(stream->closed) { in stream_recv()
1876 CURL_TRC_CF(data, cf, "[%d] returning CLOSE", stream->id); in stream_recv()
1879 else if(stream->reset || in stream_recv()
1880 (ctx->conn_closed && Curl_bufq_is_empty(&ctx->inbufq)) || in stream_recv()
1881 (ctx->goaway && ctx->last_stream_id < stream->id)) { in stream_recv()
1882 CURL_TRC_CF(data, cf, "[%d] returning ERR", stream->id); in stream_recv()
1883 *err = data->req.bytecount? CURLE_PARTIAL_FILE : CURLE_HTTP2; in stream_recv()
1884 nread = -1; in stream_recv()
1888 CURL_TRC_CF(data, cf, "[%d] stream_recv(len=%zu) -> %zd, %d", in stream_recv()
1889 stream->id, len, nread, *err); in stream_recv()
1897 struct cf_h2_ctx *ctx = cf->ctx; in h2_progress_ingress()
1903 if(!Curl_bufq_is_empty(&ctx->inbufq)) { in h2_progress_ingress()
1905 Curl_bufq_len(&ctx->inbufq)); in h2_progress_ingress()
1913 while(!ctx->conn_closed && Curl_bufq_is_empty(&ctx->inbufq)) { in h2_progress_ingress()
1915 if(stream && (stream->closed || !data_max_bytes)) { in h2_progress_ingress()
1920 if(!cf->next || !cf->next->cft->has_data_pending(cf->next, data)) in h2_progress_ingress()
1925 nread = Curl_bufq_sipn(&ctx->inbufq, 0, nw_in_reader, cf, &result); in h2_progress_ingress()
1936 ctx->conn_closed = TRUE; in h2_progress_ingress()
1942 (data_max_bytes - (size_t)nread) : 0; in h2_progress_ingress()
1949 if(ctx->conn_closed && Curl_bufq_is_empty(&ctx->inbufq)) { in h2_progress_ingress()
1950 connclose(cf->conn, "GOAWAY received"); in h2_progress_ingress()
1959 struct cf_h2_ctx *ctx = cf->ctx; in cf_h2_recv()
1961 ssize_t nread = -1; in cf_h2_recv()
1970 failf(data, "[%zd-%zd], http/2 recv on a transfer never opened " in cf_h2_recv()
1971 "or already cleared", (ssize_t)data->id, in cf_h2_recv()
1972 (ssize_t)cf->conn->connection_id); in cf_h2_recv()
1974 return -1; in cf_h2_recv()
1996 if(stream->resp_hds_len >= data_consumed) { in cf_h2_recv()
1997 stream->resp_hds_len -= data_consumed; /* no DATA */ in cf_h2_recv()
2000 if(stream->resp_hds_len) { in cf_h2_recv()
2001 data_consumed -= stream->resp_hds_len; in cf_h2_recv()
2002 stream->resp_hds_len = 0; in cf_h2_recv()
2005 nghttp2_session_consume(ctx->h2, stream->id, data_consumed); in cf_h2_recv()
2009 if(stream->closed) { in cf_h2_recv()
2010 CURL_TRC_CF(data, cf, "[%d] DRAIN closed stream", stream->id); in cf_h2_recv()
2026 nread = -1; in cf_h2_recv()
2028 CURL_TRC_CF(data, cf, "[%d] cf_recv(len=%zu) -> %zd %d, " in cf_h2_recv()
2030 stream->id, len, nread, *err, in cf_h2_recv()
2032 ctx->h2, stream->id), in cf_h2_recv()
2034 ctx->h2, stream->id), in cf_h2_recv()
2035 nghttp2_session_get_local_window_size(ctx->h2), in cf_h2_recv()
2047 struct cf_h2_ctx *ctx = cf->ctx; in h2_submit()
2063 nwritten = -1; in h2_submit()
2067 nwritten = Curl_h1_req_parse_read(&stream->h1, buf, len, NULL, 0, err); in h2_submit()
2071 if(!stream->h1.done) { in h2_submit()
2075 DEBUGASSERT(stream->h1.req); in h2_submit()
2077 *err = Curl_http_req_to_h2(&h2_headers, stream->h1.req, data); in h2_submit()
2079 nwritten = -1; in h2_submit()
2083 Curl_h1_req_parse_free(&stream->h1); in h2_submit()
2088 nwritten = -1; in h2_submit()
2093 if(!nghttp2_session_check_request_allowed(ctx->h2)) in h2_submit()
2094 CURL_TRC_CF(data, cf, "send request NOT allowed (via nghttp2)"); in h2_submit()
2096 switch(data->state.httpreq) { in h2_submit()
2101 if(data->state.infilesize != -1) in h2_submit()
2102 stream->upload_left = data->state.infilesize; in h2_submit()
2104 /* data sending without specifying the data amount up front */ in h2_submit()
2105 stream->upload_left = -1; /* unknown */ in h2_submit()
2109 stream_id = nghttp2_submit_request(ctx->h2, &pri_spec, nva, nheader, in h2_submit()
2113 stream->upload_left = 0; /* no request body */ in h2_submit()
2114 stream_id = nghttp2_submit_request(ctx->h2, &pri_spec, nva, nheader, in h2_submit()
2122 nwritten = -1; in h2_submit()
2131 stream_id, data->state.url); in h2_submit()
2147 stream->id = stream_id; in h2_submit()
2148 stream->local_window_size = H2_STREAM_WINDOW_SIZE; in h2_submit()
2149 if(data->set.max_recv_speed) { in h2_submit()
2154 curl_off_t n = (((data->set.max_recv_speed - 1) / H2_CHUNK_SIZE) + 1); in h2_submit()
2158 stream->local_window_size = (uint32_t)n * H2_CHUNK_SIZE; in h2_submit()
2163 bodylen = len - nwritten; in h2_submit()
2167 ssize_t n = Curl_bufq_write(&stream->sendbuf, body, bodylen, err); in h2_submit()
2170 nwritten = -1; in h2_submit()
2177 CURL_TRC_CF(data, cf, "[%d] submit -> %zd, %d", in h2_submit()
2178 stream? stream->id : -1, nwritten, *err); in h2_submit()
2188 struct cf_h2_ctx *ctx = cf->ctx; in cf_h2_send()
2199 if(stream && stream->id != -1) { in cf_h2_send()
2200 if(stream->upload_blocked_len) { in cf_h2_send()
2205 DEBUGASSERT(len >= stream->upload_blocked_len); in cf_h2_send()
2206 if(len < stream->upload_blocked_len) { in cf_h2_send()
2210 len, stream->upload_blocked_len); in cf_h2_send()
2212 nwritten = -1; in cf_h2_send()
2215 nwritten = (ssize_t)stream->upload_blocked_len; in cf_h2_send()
2216 stream->upload_blocked_len = 0; in cf_h2_send()
2219 else if(stream->closed) { in cf_h2_send()
2220 if(stream->resp_hds_complete) { in cf_h2_send()
2227 "on closed stream with response", stream->id); in cf_h2_send()
2232 infof(data, "stream %u closed", stream->id); in cf_h2_send()
2234 nwritten = -1; in cf_h2_send()
2238 /* If stream_id != -1, we have dispatched request HEADERS and in cf_h2_send()
2241 nwritten = Curl_bufq_write(&stream->sendbuf, buf, len, err); in cf_h2_send()
2246 if(!Curl_bufq_is_empty(&stream->sendbuf)) { in cf_h2_send()
2248 rv = nghttp2_session_resume_data(ctx->h2, stream->id); in cf_h2_send()
2251 nwritten = -1; in cf_h2_send()
2265 /* Call the nghttp2 send loop and flush to write ALL buffered data, in cf_h2_send()
2268 /* if the stream has been closed in egress handling (nghttp2 does that in cf_h2_send()
2270 if(stream && stream->closed && !was_blocked) { in cf_h2_send()
2271 infof(data, "stream %u closed", stream->id); in cf_h2_send()
2273 nwritten = -1; in cf_h2_send()
2281 nwritten = -1; in cf_h2_send()
2284 else if(stream && !Curl_bufq_is_empty(&stream->sendbuf)) { in cf_h2_send()
2285 /* although we wrote everything that nghttp2 wants to send now, in cf_h2_send()
2293 * exhaustion. Data is left in our stream buffer, or nghttp2's internal in cf_h2_send()
2295 size_t rwin = nghttp2_session_get_stream_remote_window_size(ctx->h2, in cf_h2_send()
2296 stream->id); in cf_h2_send()
2302 stream->upload_blocked_len = ((size_t)nwritten) - hdslen; in cf_h2_send()
2305 stream->id, len, in cf_h2_send()
2306 nghttp2_session_get_remote_window_size(ctx->h2), rwin, in cf_h2_send()
2307 hdslen, stream->upload_blocked_len); in cf_h2_send()
2314 nwritten = -1; in cf_h2_send()
2319 /* nghttp2 thinks this session is done. If the stream has not been in cf_h2_send()
2321 if(stream->closed) { in cf_h2_send()
2327 nwritten = -1; in cf_h2_send()
2333 CURL_TRC_CF(data, cf, "[%d] cf_send(len=%zu) -> %zd, %d, " in cf_h2_send()
2335 "h2 windows %d-%d (stream-conn), " in cf_h2_send()
2336 "buffers %zu-%zu (stream-conn)", in cf_h2_send()
2337 stream->id, len, nwritten, *err, in cf_h2_send()
2338 stream->upload_left, in cf_h2_send()
2340 ctx->h2, stream->id), in cf_h2_send()
2341 nghttp2_session_get_remote_window_size(ctx->h2), in cf_h2_send()
2342 Curl_bufq_len(&stream->sendbuf), in cf_h2_send()
2343 Curl_bufq_len(&ctx->outbufq)); in cf_h2_send()
2346 CURL_TRC_CF(data, cf, "cf_send(len=%zu) -> %zd, %d, " in cf_h2_send()
2347 "connection-window=%d, nw_send_buffer(%zu)", in cf_h2_send()
2349 nghttp2_session_get_remote_window_size(ctx->h2), in cf_h2_send()
2350 Curl_bufq_len(&ctx->outbufq)); in cf_h2_send()
2360 struct cf_h2_ctx *ctx = cf->ctx; in cf_h2_adjust_pollset()
2364 if(!ctx->h2) in cf_h2_adjust_pollset()
2375 c_exhaust = want_send && !nghttp2_session_get_remote_window_size(ctx->h2); in cf_h2_adjust_pollset()
2376 s_exhaust = want_send && stream && stream->id >= 0 && in cf_h2_adjust_pollset()
2377 !nghttp2_session_get_stream_remote_window_size(ctx->h2, in cf_h2_adjust_pollset()
2378 stream->id); in cf_h2_adjust_pollset()
2381 (!c_exhaust && nghttp2_session_want_write(ctx->h2)); in cf_h2_adjust_pollset()
2392 struct cf_h2_ctx *ctx = cf->ctx; in cf_h2_connect()
2396 if(cf->connected) { in cf_h2_connect()
2402 if(!cf->next->connected) { in cf_h2_connect()
2403 result = Curl_conn_cf_connect(cf->next, data, blocking, done); in cf_h2_connect()
2411 if(!ctx->h2) { in cf_h2_connect()
2430 cf->connected = TRUE; in cf_h2_connect()
2434 CURL_TRC_CF(data, cf, "cf_connect() -> %d, %d, ", result, *done); in cf_h2_connect()
2441 struct cf_h2_ctx *ctx = cf->ctx; in cf_h2_close()
2450 if(cf->next) in cf_h2_close()
2451 cf->next->cft->do_close(cf->next, data); in cf_h2_close()
2456 struct cf_h2_ctx *ctx = cf->ctx; in cf_h2_destroy()
2461 cf->ctx = NULL; in cf_h2_destroy()
2470 struct cf_h2_ctx *ctx = cf->ctx; in http2_data_pause()
2474 if(ctx && ctx->h2 && stream) { in http2_data_pause()
2475 uint32_t window = pause? 0 : stream->local_window_size; in http2_data_pause()
2477 int rv = nghttp2_session_set_local_window_size(ctx->h2, in http2_data_pause()
2479 stream->id, in http2_data_pause()
2503 window, stream->id)); in http2_data_pause()
2509 nghttp2_session_get_stream_local_window_size(ctx->h2, in http2_data_pause()
2510 stream->id); in http2_data_pause()
2512 window2, stream->id)); in http2_data_pause()
2555 struct cf_h2_ctx *ctx = cf->ctx; in cf_h2_data_pending()
2558 if(ctx && (!Curl_bufq_is_empty(&ctx->inbufq) in cf_h2_data_pending()
2559 || (stream && !Curl_bufq_is_empty(&stream->sendbuf)))) in cf_h2_data_pending()
2561 return cf->next? cf->next->cft->has_data_pending(cf->next, data) : FALSE; in cf_h2_data_pending()
2568 struct cf_h2_ctx *ctx = cf->ctx; in cf_h2_is_alive()
2573 result = (ctx && ctx->h2 && http2_connisalive(cf, data, input_pending)); in cf_h2_is_alive()
2574 CURL_TRC_CF(data, cf, "conn alive -> %d, input_pending=%d", in cf_h2_is_alive()
2596 struct cf_h2_ctx *ctx = cf->ctx; in cf_h2_query()
2605 if(nghttp2_session_check_request_allowed(ctx->h2) == 0) { in cf_h2_query()
2607 effective_max = CONN_INUSE(cf->conn); in cf_h2_query()
2610 effective_max = ctx->max_concurrent_streams; in cf_h2_query()
2617 *pres1 = stream? (int)stream->error : 0; in cf_h2_query()
2623 return cf->next? in cf_h2_query()
2624 cf->next->cft->query(cf->next, data, query, pres1, pres2) : in cf_h2_query()
2656 DEBUGASSERT(data->conn); in http2_cfilter_add()
2707 for(; cf; cf = cf->next) { in Curl_cf_is_http2()
2708 if(cf->cft == &Curl_cft_nghttp2) in Curl_cf_is_http2()
2710 if(cf->cft->flags & CF_TYPE_IP_CONNECT) in Curl_cf_is_http2()
2720 return conn? Curl_cf_is_http2(conn->cfilter[sockindex], data) : FALSE; in Curl_conn_is_http2()
2729 data->state.httpwant == CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE) { in Curl_http2_may_switch()
2731 if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) { in Curl_http2_may_switch()
2756 conn->httpversion = 20; /* we know we're on HTTP/2 now */ in Curl_http2_switch()
2757 conn->bits.multiplex = TRUE; /* at least potentially multiplexed */ in Curl_http2_switch()
2758 conn->bundle->multiuse = BUNDLE_MULTIPLEX; in Curl_http2_switch()
2759 Curl_multi_connchanged(data->multi); in Curl_http2_switch()
2761 if(cf->next) { in Curl_http2_switch()
2779 cf_h2 = cf->next; in Curl_http2_switch_at()
2780 cf->conn->httpversion = 20; /* we know we're on HTTP/2 now */ in Curl_http2_switch_at()
2781 cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */ in Curl_http2_switch_at()
2782 cf->conn->bundle->multiuse = BUNDLE_MULTIPLEX; in Curl_http2_switch_at()
2783 Curl_multi_connchanged(data->multi); in Curl_http2_switch_at()
2785 if(cf_h2->next) { in Curl_http2_switch_at()
2802 DEBUGASSERT(data->req.upgr101 == UPGR101_RECEIVED); in Curl_http2_upgrade()
2808 DEBUGASSERT(cf->cft == &Curl_cft_nghttp2); in Curl_http2_upgrade()
2809 ctx = cf->ctx; in Curl_http2_upgrade()
2817 copied = Curl_bufq_write(&ctx->inbufq, in Curl_http2_upgrade()
2833 conn->httpversion = 20; /* we know we're on HTTP/2 now */ in Curl_http2_upgrade()
2834 conn->bits.multiplex = TRUE; /* at least potentially multiplexed */ in Curl_http2_upgrade()
2835 conn->bundle->multiuse = BUNDLE_MULTIPLEX; in Curl_http2_upgrade()
2836 Curl_multi_connchanged(data->multi); in Curl_http2_upgrade()
2838 if(cf->next) { in Curl_http2_upgrade()
2849 if(Curl_conn_is_http2(data, data->conn, FIRSTSOCKET)) { in Curl_h2_http_1_1_error()
2850 int err = Curl_conn_get_stream_error(data, data->conn, FIRSTSOCKET); in Curl_h2_http_1_1_error()