diff options
author | Brad King <brad.king@kitware.com> | 2020-12-09 16:45:25 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2020-12-09 16:45:25 (GMT) |
commit | 54931fdff020f72bbd157fd1640a0fef52e4f183 (patch) | |
tree | 31e7f9ea89fb8ab0e17fe17efd881ea947962a4a /Utilities/cmcurl/lib/http2.c | |
parent | 4cd65e5d882333e48155cf8b5bb52d088aa63cdf (diff) | |
parent | 5aacc593a961fe9ee1427c03d18fba8947a9e33d (diff) | |
download | CMake-54931fdff020f72bbd157fd1640a0fef52e4f183.zip CMake-54931fdff020f72bbd157fd1640a0fef52e4f183.tar.gz CMake-54931fdff020f72bbd157fd1640a0fef52e4f183.tar.bz2 |
Merge branch 'upstream-curl' into update-curl
* upstream-curl:
curl 2020-12-09 (e0528597)
Diffstat (limited to 'Utilities/cmcurl/lib/http2.c')
-rw-r--r-- | Utilities/cmcurl/lib/http2.c | 178 |
1 files changed, 60 insertions, 118 deletions
diff --git a/Utilities/cmcurl/lib/http2.c b/Utilities/cmcurl/lib/http2.c index d316da8..b138fb4 100644 --- a/Utilities/cmcurl/lib/http2.c +++ b/Utilities/cmcurl/lib/http2.c @@ -9,7 +9,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -257,7 +257,7 @@ static unsigned int http2_conncheck(struct connectdata *check, /* called from http_setup_conn */ void Curl_http2_setup_req(struct Curl_easy *data) { - struct HTTP *http = data->req.protop; + struct HTTP *http = data->req.p.http; http->bodystarted = FALSE; http->status_code = -1; http->pausedata = NULL; @@ -300,6 +300,7 @@ static const struct Curl_handler Curl_handler_http2 = { http2_conncheck, /* connection_check */ PORT_HTTP, /* defport */ CURLPROTO_HTTP, /* protocol */ + CURLPROTO_HTTP, /* family */ PROTOPT_STREAM /* flags */ }; @@ -321,6 +322,7 @@ static const struct Curl_handler Curl_handler_http2_ssl = { http2_conncheck, /* connection_check */ PORT_HTTP, /* defport */ CURLPROTO_HTTPS, /* protocol */ + CURLPROTO_HTTP, /* family */ PROTOPT_SSL | PROTOPT_STREAM /* flags */ }; @@ -391,7 +393,7 @@ char *curl_pushheader_bynum(struct curl_pushheaders *h, size_t num) if(!h || !GOOD_EASY_HANDLE(h->data)) return NULL; else { - struct HTTP *stream = h->data->req.protop; + struct HTTP *stream = h->data->req.p.http; if(num < stream->push_headers_used) return stream->push_headers[num]; } @@ -413,7 +415,7 @@ char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header) !strcmp(header, ":") || strchr(header + 1, ':')) return NULL; else { - struct HTTP *stream = h->data->req.protop; + struct HTTP *stream = h->data->req.p.http; size_t len = strlen(header); size_t i; for(i = 0; i<stream->push_headers_used; i++) { @@ -460,7 +462,7 @@ static struct Curl_easy *duphandle(struct Curl_easy *data) (void)Curl_close(&second); } else { - second->req.protop = http; + second->req.p.http = http; Curl_dyn_init(&http->header_recvbuf, DYN_H2_HEADERS); Curl_http2_setup_req(second); second->state.stream_weight = data->state.stream_weight; @@ -537,7 +539,7 @@ static int push_promise(struct Curl_easy *data, /* ask the application */ H2BUGF(infof(data, "Got PUSH_PROMISE, ask application!\n")); - stream = data->req.protop; + stream = data->req.p.http; if(!stream) { failf(data, "Internal NULL stream!\n"); (void)Curl_close(&newhandle); @@ -567,13 +569,13 @@ static int push_promise(struct Curl_easy *data, if(rv) { DEBUGASSERT((rv > CURL_PUSH_OK) && (rv <= CURL_PUSH_ERROROUT)); /* denied, kill off the new handle again */ - http2_stream_free(newhandle->req.protop); - newhandle->req.protop = NULL; + http2_stream_free(newhandle->req.p.http); + newhandle->req.p.http = NULL; (void)Curl_close(&newhandle); goto fail; } - newstream = newhandle->req.protop; + newstream = newhandle->req.p.http; newstream->stream_id = frame->promised_stream_id; newhandle->req.maxdownload = -1; newhandle->req.size = -1; @@ -583,8 +585,8 @@ static int push_promise(struct Curl_easy *data, rc = Curl_multi_add_perform(data->multi, newhandle, conn); if(rc) { infof(data, "failed to add handle to multi\n"); - http2_stream_free(newhandle->req.protop); - newhandle->req.protop = NULL; + http2_stream_free(newhandle->req.p.http); + newhandle->req.p.http = NULL; Curl_close(&newhandle); rv = CURL_PUSH_DENY; goto fail; @@ -667,7 +669,7 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame, return 0; } - stream = data_s->req.protop; + stream = data_s->req.p.http; if(!stream) { H2BUGF(infof(data_s, "No proto pointer for stream: %x\n", stream_id)); @@ -783,7 +785,7 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags, internal error more than anything else! */ return NGHTTP2_ERR_CALLBACK_FAILURE; - stream = data_s->req.protop; + stream = data_s->req.p.http; if(!stream) return NGHTTP2_ERR_CALLBACK_FAILURE; @@ -849,7 +851,7 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id, } H2BUGF(infof(data_s, "on_stream_close(), %s (err %d), stream %u\n", nghttp2_http2_strerror(error_code), error_code, stream_id)); - stream = data_s->req.protop; + stream = data_s->req.p.http; if(!stream) return NGHTTP2_ERR_CALLBACK_FAILURE; @@ -894,7 +896,7 @@ static int on_begin_headers(nghttp2_session *session, return 0; } - stream = data_s->req.protop; + stream = data_s->req.p.http; if(!stream || !stream->bodystarted) { return 0; } @@ -952,7 +954,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame, internal error more than anything else! */ return NGHTTP2_ERR_CALLBACK_FAILURE; - stream = data_s->req.protop; + stream = data_s->req.p.http; if(!stream) { failf(data_s, "Internal NULL stream! 5\n"); return NGHTTP2_ERR_CALLBACK_FAILURE; @@ -1100,7 +1102,7 @@ static ssize_t data_source_read_callback(nghttp2_session *session, internal error more than anything else! */ return NGHTTP2_ERR_CALLBACK_FAILURE; - stream = data_s->req.protop; + stream = data_s->req.p.http; if(!stream) return NGHTTP2_ERR_CALLBACK_FAILURE; } @@ -1161,7 +1163,7 @@ static void populate_settings(struct connectdata *conn, void Curl_http2_done(struct Curl_easy *data, bool premature) { - struct HTTP *http = data->req.protop; + struct HTTP *http = data->req.p.http; struct http_conn *httpc = &data->conn->proto.httpc; /* there might be allocated resources done before this got the 'h2' pointer @@ -1207,13 +1209,6 @@ void Curl_http2_done(struct Curl_easy *data, bool premature) } http->stream_id = 0; } - - if(0 == nghttp2_session_check_request_allowed(httpc->h2)) { - /* No more requests are allowed in the current session, so the connection - may not be reused. This is set when a GOAWAY frame has been received or - when the limit of stream identifiers has been reached. */ - connclose(data->conn, "http/2: No new requests allowed"); - } } /* @@ -1288,7 +1283,7 @@ CURLcode Curl_http2_request_upgrade(struct dynbuf *req, binlen = nghttp2_pack_settings_payload(binsettings, H2_BINSETTINGS_LEN, httpc->local_settings, httpc->local_settings_num); - if(!binlen) { + if(binlen <= 0) { failf(conn->data, "nghttp2 unexpectedly failed on pack_settings_payload"); Curl_dyn_free(req); return CURLE_FAILED_INIT; @@ -1371,6 +1366,14 @@ static int h2_process_pending_input(struct connectdata *conn, return -1; } + if(nghttp2_session_check_request_allowed(httpc->h2) == 0) { + /* No more requests are allowed in the current session, so + the connection may not be reused. This is set when a + GOAWAY frame has been received or when the limit of stream + identifiers has been reached. */ + connclose(conn, "http/2: No new requests allowed"); + } + if(should_close_session(httpc)) { H2BUGF(infof(data, "h2_process_pending_input: nothing to do in this session\n")); @@ -1383,7 +1386,6 @@ static int h2_process_pending_input(struct connectdata *conn, } return -1; } - return 0; } @@ -1398,7 +1400,7 @@ CURLcode Curl_http2_done_sending(struct connectdata *conn) (conn->handler == &Curl_handler_http2)) { /* make sure this is only attempted for HTTP/2 transfers */ - struct HTTP *stream = conn->data->req.protop; + struct HTTP *stream = conn->data->req.p.http; struct http_conn *httpc = &conn->proto.httpc; nghttp2_session *h2 = httpc->h2; @@ -1494,8 +1496,7 @@ static ssize_t http2_handle_stream_close(struct connectdata *conn, break; len = lf + 1 - trailp; - if(data->set.verbose) - Curl_debug(data, CURLINFO_HEADER_IN, trailp, len); + Curl_debug(data, CURLINFO_HEADER_IN, trailp, len); /* pass the trailers one by one to the callback */ result = Curl_client_write(conn, CLIENTWRITE_HEADER, trailp, len); if(result) { @@ -1522,7 +1523,7 @@ static void h2_pri_spec(struct Curl_easy *data, nghttp2_priority_spec *pri_spec) { struct HTTP *depstream = (data->set.stream_depends_on? - data->set.stream_depends_on->req.protop:NULL); + data->set.stream_depends_on->req.p.http:NULL); int32_t depstream_id = depstream? depstream->stream_id:0; nghttp2_priority_spec_init(pri_spec, depstream_id, data->set.stream_weight, data->set.stream_depends_e); @@ -1539,7 +1540,7 @@ static void h2_pri_spec(struct Curl_easy *data, static int h2_session_send(struct Curl_easy *data, nghttp2_session *h2) { - struct HTTP *stream = data->req.protop; + struct HTTP *stream = data->req.p.http; if((data->set.stream_weight != data->state.stream_weight) || (data->set.stream_depends_e != data->state.stream_depends_e) || (data->set.stream_depends_on != data->state.stream_depends_on) ) { @@ -1564,12 +1565,10 @@ static int h2_session_send(struct Curl_easy *data, static ssize_t http2_recv(struct connectdata *conn, int sockindex, char *mem, size_t len, CURLcode *err) { - CURLcode result = CURLE_OK; - ssize_t rv; ssize_t nread; struct http_conn *httpc = &conn->proto.httpc; struct Curl_easy *data = conn->data; - struct HTTP *stream = data->req.protop; + struct HTTP *stream = data->req.p.http; (void)sockindex; /* we always do HTTP2 on sockindex 0 */ @@ -1632,8 +1631,7 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex, /* We have paused nghttp2, but we have no pause data (see on_data_chunk_recv). */ httpc->pause_stream_id = 0; - if(h2_process_pending_input(conn, httpc, &result) != 0) { - *err = result; + if(h2_process_pending_input(conn, httpc, err) != 0) { return -1; } } @@ -1661,8 +1659,7 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex, frames, then we have to call it again with 0-length data. Without this, on_stream_close callback will not be called, and stream could be hanged. */ - if(h2_process_pending_input(conn, httpc, &result) != 0) { - *err = result; + if(h2_process_pending_input(conn, httpc, err) != 0) { return -1; } } @@ -1688,7 +1685,6 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex, return -1; } else { - char *inbuf; /* remember where to store incoming data for this stream and how big the buffer is */ stream->mem = mem; @@ -1697,16 +1693,15 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex, if(httpc->inbuflen == 0) { nread = ((Curl_recv *)httpc->recv_underlying)( - conn, FIRSTSOCKET, httpc->inbuf, H2_BUFSIZE, &result); + conn, FIRSTSOCKET, httpc->inbuf, H2_BUFSIZE, err); if(nread == -1) { - if(result != CURLE_AGAIN) + if(*err != CURLE_AGAIN) failf(data, "Failed receiving HTTP2 data"); else if(stream->closed) /* received when the stream was already closed! */ return http2_handle_stream_close(conn, data, stream, err); - *err = result; return -1; } @@ -1719,47 +1714,18 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex, H2BUGF(infof(data, "nread=%zd\n", nread)); httpc->inbuflen = nread; - inbuf = httpc->inbuf; + + DEBUGASSERT(httpc->nread_inbuf == 0); } else { nread = httpc->inbuflen - httpc->nread_inbuf; - inbuf = httpc->inbuf + httpc->nread_inbuf; - + (void)nread; /* silence warning, used in debug */ H2BUGF(infof(data, "Use data left in connection buffer, nread=%zd\n", nread)); } - rv = nghttp2_session_mem_recv(httpc->h2, (const uint8_t *)inbuf, nread); - if(nghttp2_is_fatal((int)rv)) { - failf(data, "nghttp2_session_mem_recv() returned %zd:%s\n", - rv, nghttp2_strerror((int)rv)); - *err = CURLE_RECV_ERROR; - return -1; - } - H2BUGF(infof(data, "nghttp2_session_mem_recv() returns %zd\n", rv)); - if(nread == rv) { - H2BUGF(infof(data, "All data in connection buffer processed\n")); - httpc->inbuflen = 0; - httpc->nread_inbuf = 0; - } - else { - httpc->nread_inbuf += rv; - H2BUGF(infof(data, "%zu bytes left in connection buffer\n", - httpc->inbuflen - httpc->nread_inbuf)); - } - /* Always send pending frames in nghttp2 session, because - nghttp2_session_mem_recv() may queue new frame */ - rv = h2_session_send(data, httpc->h2); - if(rv != 0) { - *err = CURLE_SEND_ERROR; - return -1; - } - - if(should_close_session(httpc)) { - H2BUGF(infof(data, "http2_recv: nothing to do in this session\n")); - *err = CURLE_HTTP2; + if(h2_process_pending_input(conn, httpc, err) != 0) return -1; - } } if(stream->memlen) { ssize_t retlen = stream->memlen; @@ -1874,7 +1840,7 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, */ int rv; struct http_conn *httpc = &conn->proto.httpc; - struct HTTP *stream = conn->data->req.protop; + struct HTTP *stream = conn->data->req.p.http; nghttp2_nv *nva = NULL; size_t nheader; size_t i; @@ -2104,7 +2070,7 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, if(acc > MAX_ACC) { infof(conn->data, "http2_send: Warning: The cumulative length of all " - "headers exceeds %zu bytes and that could cause the " + "headers exceeds %d bytes and that could cause the " "stream to be rejected.\n", MAX_ACC); } } @@ -2112,7 +2078,7 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, h2_pri_spec(conn->data, &pri_spec); H2BUGF(infof(conn->data, "http2_send request allowed %d (easy handle %p)\n", - nghttp2_session_check_request_allowed(h2), (void *)conn->data)); + nghttp2_session_check_request_allowed(h2), (void *)conn->data)); switch(conn->data->state.httpreq) { case HTTPREQ_POST: @@ -2138,7 +2104,9 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, Curl_safefree(nva); if(stream_id < 0) { - H2BUGF(infof(conn->data, "http2_send() send error\n")); + H2BUGF(infof(conn->data, + "http2_send() nghttp2_submit_request error (%s)%d\n", + nghttp2_strerror(stream_id), stream_id)); *err = CURLE_SEND_ERROR; return -1; } @@ -2148,10 +2116,13 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, stream->stream_id = stream_id; /* this does not call h2_session_send() since there can not have been any - * priority upodate since the nghttp2_submit_request() call above */ + * priority update since the nghttp2_submit_request() call above */ rv = nghttp2_session_send(h2); - if(rv != 0) { + H2BUGF(infof(conn->data, + "http2_send() nghttp2_session_send error (%s)%d\n", + nghttp2_strerror(rv), rv)); + *err = CURLE_SEND_ERROR; return -1; } @@ -2183,7 +2154,7 @@ CURLcode Curl_http2_setup(struct connectdata *conn) { CURLcode result; struct http_conn *httpc = &conn->proto.httpc; - struct HTTP *stream = conn->data->req.protop; + struct HTTP *stream = conn->data->req.p.http; DEBUGASSERT(conn->data->state.buffer); @@ -2236,9 +2207,8 @@ CURLcode Curl_http2_switched(struct connectdata *conn, CURLcode result; struct http_conn *httpc = &conn->proto.httpc; int rv; - ssize_t nproc; struct Curl_easy *data = conn->data; - struct HTTP *stream = conn->data->req.protop; + struct HTTP *stream = conn->data->req.p.http; result = Curl_http2_setup(conn); if(result) @@ -2299,7 +2269,7 @@ CURLcode Curl_http2_switched(struct connectdata *conn, data into stream->mem, overwriting data already there. */ if(H2_BUFSIZE < nread) { failf(data, "connection buffer size is too small to store data following " - "HTTP Upgrade response header: buflen=%zu, datalen=%zu", + "HTTP Upgrade response header: buflen=%d, datalen=%zu", H2_BUFSIZE, nread); return CURLE_HTTP2; } @@ -2310,41 +2280,13 @@ CURLcode Curl_http2_switched(struct connectdata *conn, if(nread) memcpy(httpc->inbuf, mem, nread); - httpc->inbuflen = nread; - - nproc = nghttp2_session_mem_recv(httpc->h2, (const uint8_t *)httpc->inbuf, - httpc->inbuflen); - - if(nghttp2_is_fatal((int)nproc)) { - failf(data, "nghttp2_session_mem_recv() failed: %s(%d)", - nghttp2_strerror((int)nproc), (int)nproc); - return CURLE_HTTP2; - } - - H2BUGF(infof(data, "nghttp2_session_mem_recv() returns %zd\n", nproc)); - - if((ssize_t)nread == nproc) { - httpc->inbuflen = 0; - httpc->nread_inbuf = 0; - } - else { - httpc->nread_inbuf += nproc; - } - /* Try to send some frames since we may read SETTINGS already. */ - rv = h2_session_send(data, httpc->h2); + httpc->inbuflen = nread; - if(rv != 0) { - failf(data, "nghttp2_session_send() failed: %s(%d)", - nghttp2_strerror(rv), rv); - return CURLE_HTTP2; - } + DEBUGASSERT(httpc->nread_inbuf == 0); - if(should_close_session(httpc)) { - H2BUGF(infof(data, - "nghttp2_session_send(): nothing to do in this session\n")); + if(-1 == h2_process_pending_input(conn, httpc, &result)) return CURLE_HTTP2; - } return CURLE_OK; } @@ -2358,7 +2300,7 @@ CURLcode Curl_http2_stream_pause(struct Curl_easy *data, bool pause) return CURLE_OK; #ifdef NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE else { - struct HTTP *stream = data->req.protop; + struct HTTP *stream = data->req.p.http; struct http_conn *httpc = &data->conn->proto.httpc; uint32_t window = !pause * HTTP2_HUGE_WINDOW_SIZE; int rv = nghttp2_session_set_local_window_size(httpc->h2, |