diff -up curl-7.61.1/lib/http2.c.25a25f45 curl-7.61.1/lib/http2.c --- curl-7.61.1/lib/http2.c.25a25f45 2023-08-07 14:03:42.043463284 +0200 +++ curl-7.61.1/lib/http2.c 2023-08-07 14:10:24.769489855 +0200 @@ -1202,7 +1202,7 @@ CURLcode Curl_http2_request_upgrade(Curl 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_add_buffer_free(req); return CURLE_FAILED_INIT; @@ -1285,6 +1285,14 @@ static int h2_process_pending_input(stru 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")); @@ -1297,7 +1305,6 @@ static int h2_process_pending_input(stru } return -1; } - return 0; } @@ -1455,8 +1462,6 @@ static int h2_session_send(struct Curl_e 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; @@ -1519,8 +1524,7 @@ static ssize_t http2_recv(struct connect /* 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; } } @@ -1549,8 +1553,7 @@ static ssize_t http2_recv(struct connect 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; } } @@ -1573,7 +1576,6 @@ static ssize_t http2_recv(struct connect return -1; } else { - char *inbuf; /* remember where to store incoming data for this stream and how big the buffer is */ stream->mem = mem; @@ -1582,16 +1584,15 @@ static ssize_t http2_recv(struct connect 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; } @@ -1604,47 +1605,17 @@ static ssize_t http2_recv(struct connect 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; @@ -2108,7 +2079,6 @@ CURLcode Curl_http2_switched(struct 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; @@ -2186,39 +2156,10 @@ CURLcode Curl_http2_switched(struct conn memcpy(httpc->inbuf, mem, nread); httpc->inbuflen = nread; - nproc = nghttp2_session_mem_recv(httpc->h2, (const uint8_t *)httpc->inbuf, - httpc->inbuflen); + DEBUGASSERT(httpc->nread_inbuf == 0); - if(nghttp2_is_fatal((int)nproc)) { - failf(data, "nghttp2_session_mem_recv() failed: %s(%d)", - nghttp2_strerror((int)nproc), (int)nproc); + if(-1 == h2_process_pending_input(conn, httpc, &result)) 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); - - if(rv != 0) { - failf(data, "nghttp2_session_send() failed: %s(%d)", - nghttp2_strerror(rv), rv); - return CURLE_HTTP2; - } - - if(should_close_session(httpc)) { - H2BUGF(infof(data, - "nghttp2_session_send(): nothing to do in this session\n")); - return CURLE_HTTP2; - } return CURLE_OK; }