diff options
| author | dartraiden <wowemuh@gmail.com> | 2025-06-04 09:49:23 +0300 |
|---|---|---|
| committer | dartraiden <wowemuh@gmail.com> | 2025-06-04 10:27:11 +0300 |
| commit | 86d1a677fd310d7d90d6f7545c02a4bd68e1d955 (patch) | |
| tree | 7fd5f46ef18038d10dcdf9fa19ffee547d51d6ad /libs/libcurl/src/http2.c | |
| parent | e8e2a816fbbcec0d6a64496928fecff19c281d82 (diff) | |
libcurl: update to 8.14.0
Diffstat (limited to 'libs/libcurl/src/http2.c')
| -rw-r--r-- | libs/libcurl/src/http2.c | 134 |
1 files changed, 83 insertions, 51 deletions
diff --git a/libs/libcurl/src/http2.c b/libs/libcurl/src/http2.c index a19ce0aff4..6d072b454c 100644 --- a/libs/libcurl/src/http2.c +++ b/libs/libcurl/src/http2.c @@ -29,13 +29,13 @@ #include <nghttp2/nghttp2.h>
#include "urldata.h"
#include "bufq.h"
-#include "hash_offt.h"
+#include "uint-hash.h"
#include "http1.h"
#include "http2.h"
#include "http.h"
#include "sendf.h"
#include "select.h"
-#include "curl_base64.h"
+#include "curlx/base64.h"
#include "strcase.h"
#include "multiif.h"
#include "url.h"
@@ -44,8 +44,9 @@ #include "connect.h"
#include "rand.h"
#include "strdup.h"
+#include "curlx/strparse.h"
#include "transfer.h"
-#include "dynbuf.h"
+#include "curlx/dynbuf.h"
#include "headers.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -135,12 +136,15 @@ struct cf_h2_ctx { struct bufc_pool stream_bufcp; /* spares for stream buffers */
struct dynbuf scratch; /* scratch buffer for temp use */
- struct Curl_hash_offt streams; /* hash of `data->mid` to `h2_stream_ctx` */
+ struct uint_hash streams; /* hash of `data->mid` to `h2_stream_ctx` */
size_t drain_total; /* sum of all stream's UrlState drain */
uint32_t max_concurrent_streams;
uint32_t goaway_error; /* goaway error code from server */
int32_t remote_max_sid; /* max id processed by server */
int32_t local_max_sid; /* max id processed by us */
+#ifdef DEBUGBUILD
+ int32_t stream_win_max; /* max h2 stream window size */
+#endif
BIT(initialized);
BIT(via_h1_upgrade);
BIT(conn_closed);
@@ -155,17 +159,29 @@ struct cf_h2_ctx { #define CF_CTX_CALL_DATA(cf) \
((struct cf_h2_ctx *)(cf)->ctx)->call_data
-static void h2_stream_hash_free(curl_off_t id, void *stream);
+static void h2_stream_hash_free(unsigned int id, void *stream);
static void cf_h2_ctx_init(struct cf_h2_ctx *ctx, bool via_h1_upgrade)
{
Curl_bufcp_init(&ctx->stream_bufcp, H2_CHUNK_SIZE, H2_STREAM_POOL_SPARES);
Curl_bufq_initp(&ctx->inbufq, &ctx->stream_bufcp, H2_NW_RECV_CHUNKS, 0);
Curl_bufq_initp(&ctx->outbufq, &ctx->stream_bufcp, H2_NW_SEND_CHUNKS, 0);
- Curl_dyn_init(&ctx->scratch, CURL_MAX_HTTP_HEADER);
- Curl_hash_offt_init(&ctx->streams, 63, h2_stream_hash_free);
+ curlx_dyn_init(&ctx->scratch, CURL_MAX_HTTP_HEADER);
+ Curl_uint_hash_init(&ctx->streams, 63, h2_stream_hash_free);
ctx->remote_max_sid = 2147483647;
ctx->via_h1_upgrade = via_h1_upgrade;
+#ifdef DEBUGBUILD
+ {
+ const char *p = getenv("CURL_H2_STREAM_WIN_MAX");
+
+ ctx->stream_win_max = H2_STREAM_WINDOW_SIZE_MAX;
+ if(p) {
+ curl_off_t l;
+ if(!curlx_str_number(&p, &l, INT_MAX))
+ ctx->stream_win_max = (int32_t)l;
+ }
+ }
+#endif
ctx->initialized = TRUE;
}
@@ -175,8 +191,8 @@ static void cf_h2_ctx_free(struct cf_h2_ctx *ctx) Curl_bufq_free(&ctx->inbufq);
Curl_bufq_free(&ctx->outbufq);
Curl_bufcp_free(&ctx->stream_bufcp);
- Curl_dyn_free(&ctx->scratch);
- Curl_hash_offt_destroy(&ctx->streams);
+ curlx_dyn_free(&ctx->scratch);
+ Curl_uint_hash_destroy(&ctx->streams);
memset(ctx, 0, sizeof(*ctx));
}
free(ctx);
@@ -190,7 +206,7 @@ static void cf_h2_ctx_close(struct cf_h2_ctx *ctx) }
static CURLcode h2_progress_egress(struct Curl_cfilter *cf,
- struct Curl_easy *data);
+ struct Curl_easy *data);
/**
* All about the H2 internals of a stream
@@ -221,8 +237,9 @@ struct h2_stream_ctx { BIT(write_paused); /* stream write is paused */
};
-#define H2_STREAM_CTX(ctx,data) ((struct h2_stream_ctx *)(\
- data? Curl_hash_offt_get(&(ctx)->streams, (data)->mid) : NULL))
+#define H2_STREAM_CTX(ctx,data) \
+ ((struct h2_stream_ctx *)( \
+ data? Curl_uint_hash_get(&(ctx)->streams, (data)->mid) : NULL))
static struct h2_stream_ctx *h2_stream_ctx_create(struct cf_h2_ctx *ctx)
{
@@ -266,7 +283,7 @@ static void h2_stream_ctx_free(struct h2_stream_ctx *stream) free(stream);
}
-static void h2_stream_hash_free(curl_off_t id, void *stream)
+static void h2_stream_hash_free(unsigned int id, void *stream)
{
(void)id;
DEBUGASSERT(stream);
@@ -285,7 +302,15 @@ static int32_t cf_h2_get_desired_local_win(struct Curl_cfilter *cf, * This gets less precise the higher the latency. */
return (int32_t)data->set.max_recv_speed;
}
+#ifdef DEBUGBUILD
+ else {
+ struct cf_h2_ctx *ctx = cf->ctx;
+ CURL_TRC_CF(data, cf, "stream_win_max=%d", ctx->stream_win_max);
+ return ctx->stream_win_max;
+ }
+#else
return H2_STREAM_WINDOW_SIZE_MAX;
+#endif
}
static CURLcode cf_h2_update_local_win(struct Curl_cfilter *cf,
@@ -302,6 +327,13 @@ static CURLcode cf_h2_update_local_win(struct Curl_cfilter *cf, int32_t wsize = nghttp2_session_get_stream_effective_local_window_size(
ctx->h2, stream->id);
if(dwsize > wsize) {
+ rv = nghttp2_session_set_local_window_size(ctx->h2, NGHTTP2_FLAG_NONE,
+ stream->id, dwsize);
+ if(rv) {
+ failf(data, "[%d] nghttp2 set_local_window_size(%d) failed: "
+ "%s(%d)", stream->id, dwsize, nghttp2_strerror(rv), rv);
+ return CURLE_HTTP2;
+ }
rv = nghttp2_submit_window_update(ctx->h2, NGHTTP2_FLAG_NONE,
stream->id, dwsize - wsize);
if(rv) {
@@ -383,7 +415,7 @@ static CURLcode http2_data_setup(struct Curl_cfilter *cf, if(!stream)
return CURLE_OUT_OF_MEMORY;
- if(!Curl_hash_offt_set(&ctx->streams, data->mid, stream)) {
+ if(!Curl_uint_hash_set(&ctx->streams, data->mid, stream)) {
h2_stream_ctx_free(stream);
return CURLE_OUT_OF_MEMORY;
}
@@ -421,7 +453,7 @@ static void http2_data_done(struct Curl_cfilter *cf, struct Curl_easy *data) nghttp2_session_send(ctx->h2);
}
- Curl_hash_offt_remove(&ctx->streams, data->mid);
+ Curl_uint_hash_remove(&ctx->streams, data->mid);
}
static int h2_client_new(struct Curl_cfilter *cf,
@@ -430,7 +462,7 @@ static int h2_client_new(struct Curl_cfilter *cf, struct cf_h2_ctx *ctx = cf->ctx;
nghttp2_option *o;
nghttp2_mem mem = {NULL, Curl_nghttp2_malloc, Curl_nghttp2_free,
- Curl_nghttp2_calloc, Curl_nghttp2_realloc};
+ Curl_nghttp2_calloc, Curl_nghttp2_realloc};
int rc = nghttp2_option_new(&o);
if(rc)
@@ -1030,8 +1062,8 @@ static int push_promise(struct Curl_cfilter *cf, newhandle->req.maxdownload = -1;
newhandle->req.size = -1;
- CURL_TRC_CF(data, cf, "promise easy handle added to multi, mid=%"
- FMT_OFF_T, newhandle->mid);
+ CURL_TRC_CF(data, cf, "promise easy handle added to multi, mid=%u",
+ newhandle->mid);
rv = nghttp2_session_set_stream_user_data(ctx->h2,
newstream->id,
newhandle);
@@ -1690,15 +1722,15 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame, cf_h2_header_error(cf, data_s, stream, result);
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
- Curl_dyn_reset(&ctx->scratch);
- result = Curl_dyn_addn(&ctx->scratch, STRCONST("HTTP/2 "));
+ curlx_dyn_reset(&ctx->scratch);
+ result = curlx_dyn_addn(&ctx->scratch, STRCONST("HTTP/2 "));
if(!result)
- result = Curl_dyn_addn(&ctx->scratch, value, valuelen);
+ result = curlx_dyn_addn(&ctx->scratch, value, valuelen);
if(!result)
- result = Curl_dyn_addn(&ctx->scratch, STRCONST(" \r\n"));
+ result = curlx_dyn_addn(&ctx->scratch, STRCONST(" \r\n"));
if(!result)
- h2_xfer_write_resp_hd(cf, data_s, stream, Curl_dyn_ptr(&ctx->scratch),
- Curl_dyn_len(&ctx->scratch), FALSE);
+ h2_xfer_write_resp_hd(cf, data_s, stream, curlx_dyn_ptr(&ctx->scratch),
+ curlx_dyn_len(&ctx->scratch), FALSE);
if(result) {
cf_h2_header_error(cf, data_s, stream, result);
return NGHTTP2_ERR_CALLBACK_FAILURE;
@@ -1715,17 +1747,17 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame, /* nghttp2 guarantees that namelen > 0, and :status was already
received, and this is not pseudo-header field . */
/* convert to an HTTP1-style header */
- Curl_dyn_reset(&ctx->scratch);
- result = Curl_dyn_addn(&ctx->scratch, (const char *)name, namelen);
+ curlx_dyn_reset(&ctx->scratch);
+ result = curlx_dyn_addn(&ctx->scratch, (const char *)name, namelen);
if(!result)
- result = Curl_dyn_addn(&ctx->scratch, STRCONST(": "));
+ result = curlx_dyn_addn(&ctx->scratch, STRCONST(": "));
if(!result)
- result = Curl_dyn_addn(&ctx->scratch, (const char *)value, valuelen);
+ result = curlx_dyn_addn(&ctx->scratch, (const char *)value, valuelen);
if(!result)
- result = Curl_dyn_addn(&ctx->scratch, STRCONST("\r\n"));
+ result = curlx_dyn_addn(&ctx->scratch, STRCONST("\r\n"));
if(!result)
- h2_xfer_write_resp_hd(cf, data_s, stream, Curl_dyn_ptr(&ctx->scratch),
- Curl_dyn_len(&ctx->scratch), FALSE);
+ h2_xfer_write_resp_hd(cf, data_s, stream, curlx_dyn_ptr(&ctx->scratch),
+ curlx_dyn_len(&ctx->scratch), FALSE);
if(result) {
cf_h2_header_error(cf, data_s, stream, result);
return NGHTTP2_ERR_CALLBACK_FAILURE;
@@ -1818,22 +1850,22 @@ CURLcode Curl_http2_request_upgrade(struct dynbuf *req, binlen = populate_binsettings(binsettings, data);
if(binlen <= 0) {
failf(data, "nghttp2 unexpectedly failed on pack_settings_payload");
- Curl_dyn_free(req);
+ curlx_dyn_free(req);
return CURLE_FAILED_INIT;
}
- result = Curl_base64url_encode((const char *)binsettings, (size_t)binlen,
- &base64, &blen);
+ result = curlx_base64url_encode((const char *)binsettings, (size_t)binlen,
+ &base64, &blen);
if(result) {
- Curl_dyn_free(req);
+ curlx_dyn_free(req);
return result;
}
- result = Curl_dyn_addf(req,
- "Connection: Upgrade, HTTP2-Settings\r\n"
- "Upgrade: %s\r\n"
- "HTTP2-Settings: %s\r\n",
- NGHTTP2_CLEARTEXT_PROTO_VERSION_ID, base64);
+ result = curlx_dyn_addf(req,
+ "Connection: Upgrade, HTTP2-Settings\r\n"
+ "Upgrade: %s\r\n"
+ "HTTP2-Settings: %s\r\n",
+ NGHTTP2_CLEARTEXT_PROTO_VERSION_ID, base64);
free(base64);
k->upgr101 = UPGR101_H2;
@@ -1893,25 +1925,25 @@ static ssize_t http2_handle_stream_close(struct Curl_cfilter *cf, size_t i;
*err = CURLE_OK;
- Curl_dyn_init(&dbuf, DYN_TRAILERS);
+ curlx_dyn_init(&dbuf, DYN_TRAILERS);
for(i = 0; i < Curl_dynhds_count(&stream->resp_trailers); ++i) {
e = Curl_dynhds_getn(&stream->resp_trailers, i);
if(!e)
break;
- Curl_dyn_reset(&dbuf);
- *err = Curl_dyn_addf(&dbuf, "%.*s: %.*s\x0d\x0a",
- (int)e->namelen, e->name,
- (int)e->valuelen, e->value);
+ curlx_dyn_reset(&dbuf);
+ *err = curlx_dyn_addf(&dbuf, "%.*s: %.*s\x0d\x0a",
+ (int)e->namelen, e->name,
+ (int)e->valuelen, e->value);
if(*err)
break;
- Curl_debug(data, CURLINFO_HEADER_IN, Curl_dyn_ptr(&dbuf),
- Curl_dyn_len(&dbuf));
+ Curl_debug(data, CURLINFO_HEADER_IN, curlx_dyn_ptr(&dbuf),
+ curlx_dyn_len(&dbuf));
*err = Curl_client_write(data, CLIENTWRITE_HEADER|CLIENTWRITE_TRAILER,
- Curl_dyn_ptr(&dbuf), Curl_dyn_len(&dbuf));
+ curlx_dyn_ptr(&dbuf), curlx_dyn_len(&dbuf));
if(*err)
break;
}
- Curl_dyn_free(&dbuf);
+ curlx_dyn_free(&dbuf);
if(*err)
goto out;
}
@@ -2123,7 +2155,7 @@ static ssize_t cf_h2_recv(struct Curl_cfilter *cf, struct Curl_easy *data, * a read() is called anyway. It is not clear what the calling sequence
* is for such a case. */
failf(data, "http/2 recv on a transfer never opened "
- "or already cleared, mid=%" FMT_OFF_T, data->mid);
+ "or already cleared, mid=%u", data->mid);
*err = CURLE_HTTP2;
return -1;
}
@@ -2775,7 +2807,7 @@ static CURLcode cf_h2_query(struct Curl_cfilter *cf, CF_DATA_SAVE(save, cf, data);
if(nghttp2_session_check_request_allowed(ctx->h2) == 0) {
/* the limit is what we have in use right now */
- effective_max = CONN_INUSE(cf->conn);
+ effective_max = CONN_ATTACHED(cf->conn);
}
else {
effective_max = ctx->max_concurrent_streams;
|
