diff --git a/README.md b/README.md index 482faf1..75c5ee7 100644 --- a/README.md +++ b/README.md @@ -14,5 +14,5 @@ of third party libraries used in the Windows port of WebKit. | [icu](http://site.icu-project.org) | 77.1 | 2025-03-13 | CMake port. Upstream pinned to 74.1 | | [openssl](https://www.libressl.org/) | libressl | N/A | Map openssl to libressl | | [zlib](https://github.com/zlib-ng/zlib-ng) | zlib-ng | N/A | Map zlib to zlib-ng | -| [curl](https://curl.se) | 8.13.0 | 2025-04-02 | Customization of build options, and release candidates | +| [curl](https://curl.se) | 8.16.0 | 2025-09-10 | Customization of build options, and release candidates | | [cairo](https://gitlab.freedesktop.org/cairo/cairo) | 1.18.2 | 2024-09-01 | CMake port. Will remove when cairo taken out of WebKit | diff --git a/ports/curl/0001-cpool-cshutdown-force-close-connections-under-pressu.patch b/ports/curl/0001-cpool-cshutdown-force-close-connections-under-pressu.patch deleted file mode 100644 index 4147927..0000000 --- a/ports/curl/0001-cpool-cshutdown-force-close-connections-under-pressu.patch +++ /dev/null @@ -1,278 +0,0 @@ -From ff37657e4d94cf4db80ab9652ae8e6acb84f3019 Mon Sep 17 00:00:00 2001 -From: Stefan Eissing -Date: Fri, 11 Apr 2025 12:05:05 +0200 -Subject: [PATCH] cpool/cshutdown: force close connections under pressure - -when CURLMOPT_MAX_HOST_CONNECTIONS or CURLMOPT_MAX_TOTAL_CONNECTIONS -limits are reached, force close connections in shutdown to go below -limit when possible. - -Fixes #17020 -Reported-by: Fujii Hironori -Closes #17022 ---- - lib/conncache.c | 68 +++++++++++++++++++++------------- - lib/cshutdn.c | 30 +++++++++++++-- - lib/cshutdn.h | 6 +++ - lib/url.c | 9 +++-- - tests/http/test_19_shutdown.py | 31 +++++++++++++++- - 5 files changed, 109 insertions(+), 35 deletions(-) - -diff --git a/lib/conncache.c b/lib/conncache.c -index fe0b07dcb..072fdd44f 100644 ---- a/lib/conncache.c -+++ b/lib/conncache.c -@@ -375,24 +375,33 @@ int Curl_cpool_check_limits(struct Curl_easy *data, - - bundle = cpool_find_bundle(cpool, conn); - live = bundle ? Curl_llist_count(&bundle->conns) : 0; -- shutdowns = Curl_cshutdn_dest_count(data, conn->destination); -- while(!shutdowns && bundle && live >= dest_limit) { -- struct connectdata *oldest_idle = NULL; -- /* The bundle is full. Extract the oldest connection that may -- * be removed now, if there is one. */ -- oldest_idle = cpool_bundle_get_oldest_idle(bundle); -- if(!oldest_idle) -+ shutdowns = Curl_cshutdn_dest_count(data, conn->destination); -+ while((live + shutdowns) >= dest_limit) { -+ if(shutdowns) { -+ /* close one connection in shutdown right away, if we can */ -+ if(!Curl_cshutdn_close_oldest(data, conn->destination)) -+ break; -+ } -+ else if(!bundle) - break; -- /* disconnect the old conn and continue */ -- CURL_TRC_M(data, "Discarding connection #%" -- FMT_OFF_T " from %zu to reach destination " -- "limit of %zu", oldest_idle->connection_id, -- Curl_llist_count(&bundle->conns), dest_limit); -- Curl_conn_terminate(cpool->idata, oldest_idle, FALSE); -- -- /* in case the bundle was destroyed in disconnect, look it up again */ -- bundle = cpool_find_bundle(cpool, conn); -- live = bundle ? Curl_llist_count(&bundle->conns) : 0; -+ else { -+ struct connectdata *oldest_idle = NULL; -+ /* The bundle is full. Extract the oldest connection that may -+ * be removed now, if there is one. */ -+ oldest_idle = cpool_bundle_get_oldest_idle(bundle); -+ if(!oldest_idle) -+ break; -+ /* disconnect the old conn and continue */ -+ CURL_TRC_M(data, "Discarding connection #%" -+ FMT_OFF_T " from %zu to reach destination " -+ "limit of %zu", oldest_idle->connection_id, -+ Curl_llist_count(&bundle->conns), dest_limit); -+ Curl_conn_terminate(cpool->idata, oldest_idle, FALSE); -+ -+ /* in case the bundle was destroyed in disconnect, look it up again */ -+ bundle = cpool_find_bundle(cpool, conn); -+ live = bundle ? Curl_llist_count(&bundle->conns) : 0; -+ } - shutdowns = Curl_cshutdn_dest_count(cpool->idata, conn->destination); - } - if((live + shutdowns) >= dest_limit) { -@@ -404,15 +413,22 @@ int Curl_cpool_check_limits(struct Curl_easy *data, - if(total_limit) { - shutdowns = Curl_cshutdn_count(cpool->idata); - while((cpool->num_conn + shutdowns) >= total_limit) { -- struct connectdata *oldest_idle = cpool_get_oldest_idle(cpool); -- if(!oldest_idle) -- break; -- /* disconnect the old conn and continue */ -- CURL_TRC_M(data, "Discarding connection #%" -- FMT_OFF_T " from %zu to reach total " -- "limit of %zu", -- oldest_idle->connection_id, cpool->num_conn, total_limit); -- Curl_conn_terminate(cpool->idata, oldest_idle, FALSE); -+ if(shutdowns) { -+ /* close one connection in shutdown right away, if we can */ -+ if(!Curl_cshutdn_close_oldest(data, NULL)) -+ break; -+ } -+ else { -+ struct connectdata *oldest_idle = cpool_get_oldest_idle(cpool); -+ if(!oldest_idle) -+ break; -+ /* disconnect the old conn and continue */ -+ CURL_TRC_M(data, "Discarding connection #%" -+ FMT_OFF_T " from %zu to reach total " -+ "limit of %zu", -+ oldest_idle->connection_id, cpool->num_conn, total_limit); -+ Curl_conn_terminate(cpool->idata, oldest_idle, FALSE); -+ } - shutdowns = Curl_cshutdn_count(cpool->idata); - } - if((cpool->num_conn + shutdowns) >= total_limit) { -diff --git a/lib/cshutdn.c b/lib/cshutdn.c -index 45581bd08..83972e375 100644 ---- a/lib/cshutdn.c -+++ b/lib/cshutdn.c -@@ -166,7 +166,9 @@ void Curl_cshutdn_terminate(struct Curl_easy *data, - * not done so already. */ - cshutdn_run_once(admin, conn, &done); - } -- CURL_TRC_M(admin, "[SHUTDOWN] closing connection"); -+ CURL_TRC_M(admin, "[SHUTDOWN] %sclosing connection #%" FMT_OFF_T, -+ conn->bits.shutdown_filters ? "" : "force ", -+ conn->connection_id); - Curl_conn_close(admin, SECONDARYSOCKET); - Curl_conn_close(admin, FIRSTSOCKET); - Curl_detach_connection(admin); -@@ -181,13 +183,21 @@ void Curl_cshutdn_terminate(struct Curl_easy *data, - } - } - --static void cshutdn_destroy_oldest(struct cshutdn *cshutdn, -- struct Curl_easy *data) -+static bool cshutdn_destroy_oldest(struct cshutdn *cshutdn, -+ struct Curl_easy *data, -+ const char *destination) - { - struct Curl_llist_node *e; - struct connectdata *conn; - - e = Curl_llist_head(&cshutdn->list); -+ while(e) { -+ conn = Curl_node_elem(e); -+ if(!destination || !strcmp(destination, conn->destination)) -+ break; -+ e = Curl_node_next(e); -+ } -+ - if(e) { - SIGPIPE_VARIABLE(pipe_st); - conn = Curl_node_elem(e); -@@ -196,7 +206,19 @@ static void cshutdn_destroy_oldest(struct cshutdn *cshutdn, - sigpipe_apply(data, &pipe_st); - Curl_cshutdn_terminate(data, conn, FALSE); - sigpipe_restore(&pipe_st); -+ return TRUE; -+ } -+ return FALSE; -+} -+ -+bool Curl_cshutdn_close_oldest(struct Curl_easy *data, -+ const char *destination) -+{ -+ if(data && data->multi) { -+ struct cshutdn *csd = &data->multi->cshutdn; -+ return cshutdn_destroy_oldest(csd, data, destination); - } -+ return FALSE; - } - - #define NUM_POLLS_ON_STACK 10 -@@ -414,7 +436,7 @@ void Curl_cshutdn_add(struct cshutdn *cshutdn, - (conns_in_pool + Curl_llist_count(&cshutdn->list)))) { - CURL_TRC_M(data, "[SHUTDOWN] discarding oldest shutdown connection " - "due to connection limit of %zu", max_total); -- cshutdn_destroy_oldest(cshutdn, data); -+ cshutdn_destroy_oldest(cshutdn, data, NULL); - } - - if(cshutdn->multi->socket_cb) { -diff --git a/lib/cshutdn.h b/lib/cshutdn.h -index 202e86983..7b9514447 100644 ---- a/lib/cshutdn.h -+++ b/lib/cshutdn.h -@@ -75,6 +75,12 @@ size_t Curl_cshutdn_count(struct Curl_easy *data); - size_t Curl_cshutdn_dest_count(struct Curl_easy *data, - const char *destination); - -+/* Close the oldest connection in shutdown to destination or, -+ * when destination is NULL for any destination. -+ * Return TRUE if a connection has been closed. */ -+bool Curl_cshutdn_close_oldest(struct Curl_easy *data, -+ const char *destination); -+ - /* Add a connection to have it shut down. Will terminate the oldest - * connection when total connection limit of multi is being reached. */ - void Curl_cshutdn_add(struct cshutdn *cshutdn, -diff --git a/lib/url.c b/lib/url.c -index 2125a97af..d94a29375 100644 ---- a/lib/url.c -+++ b/lib/url.c -@@ -3597,10 +3597,12 @@ static CURLcode create_conn(struct Curl_easy *data, - conn->bits.tls_enable_alpn = TRUE; - } - -- if(waitpipe) -+ if(waitpipe) { - /* There is a connection that *might* become usable for multiplexing - "soon", and we wait for that */ -+ infof(data, "Waiting on connection to negotiate possible multiplexing."); - connections_available = FALSE; -+ } - else { - switch(Curl_cpool_check_limits(data, conn)) { - case CPOOL_LIMIT_DEST: -@@ -3614,7 +3616,8 @@ static CURLcode create_conn(struct Curl_easy *data, - else - #endif - { -- infof(data, "No connections available in cache"); -+ infof(data, "No connections available, total of %ld reached.", -+ data->multi->max_total_connections); - connections_available = FALSE; - } - break; -@@ -3624,8 +3627,6 @@ static CURLcode create_conn(struct Curl_easy *data, - } - - if(!connections_available) { -- infof(data, "No connections available."); -- - Curl_conn_free(data, conn); - *in_connect = NULL; - -diff --git a/tests/http/test_19_shutdown.py b/tests/http/test_19_shutdown.py -index ea6839135..fad1314fc 100644 ---- a/tests/http/test_19_shutdown.py -+++ b/tests/http/test_19_shutdown.py -@@ -153,7 +153,7 @@ class TestShutdown: - r.check_response(http_status=200, count=count) - # check that we closed all connections - closings = [line for line in r.trace_lines -- if re.match(r'.*SHUTDOWN\] closing', line)] -+ if re.match(r'.*SHUTDOWN\] (force )?closing', line)] - assert len(closings) == count, f'{closings}' - # check that all connection sockets were removed from event - removes = [line for line in r.trace_lines -@@ -180,3 +180,32 @@ class TestShutdown: - shutdowns = [line for line in r.trace_lines - if re.match(r'.*SHUTDOWN\] shutdown, done=1', line)] - assert len(shutdowns) == 1, f'{shutdowns}' -+ -+ # run connection pressure, many small transfers, not reusing connections, -+ # limited total -+ @pytest.mark.parametrize("proto", ['http/1.1']) -+ def test_19_07_shutdown_by_curl(self, env: Env, httpd, proto): -+ if not env.curl_is_debug(): -+ pytest.skip('only works for curl debug builds') -+ count = 500 -+ docname = 'data.json' -+ url = f'https://localhost:{env.https_port}/{docname}' -+ client = LocalClient(name='hx-download', env=env, run_env={ -+ 'CURL_GRACEFUL_SHUTDOWN': '2000', -+ 'CURL_DEBUG': 'ssl,multi' -+ }) -+ if not client.exists(): -+ pytest.skip(f'example client not built: {client.name}') -+ r = client.run(args=[ -+ '-n', f'{count}', #that many transfers -+ '-f', # forbid conn reuse -+ '-m', '10', # max parallel -+ '-T', '5', # max total conns at a time -+ '-V', proto, -+ url -+ ]) -+ r.check_exit_code(0) -+ shutdowns = [line for line in r.trace_lines -+ if re.match(r'.*SHUTDOWN\] shutdown, done=1', line)] -+ # we see less clean shutdowns as total limit forces early closes -+ assert len(shutdowns) < count, f'{shutdowns}' --- -2.49.0.windows.1 - diff --git a/ports/curl/portfile.cmake b/ports/curl/portfile.cmake index 594ded9..bebc59c 100644 --- a/ports/curl/portfile.cmake +++ b/ports/curl/portfile.cmake @@ -1,4 +1,4 @@ -set(VERSION 8.13.0) +set(VERSION 8.16.0) string(REPLACE "." "_" TAG ${VERSION}) set(FILENAME "curl-${VERSION}.tar.xz") @@ -15,11 +15,7 @@ endif () vcpkg_download_distfile(ARCHIVE URLS ${URLS} FILENAME ${FILENAME} - SHA512 d266e460f162ee455b56726e5b7247b2d1aa5265ae12081513fc0c5c79e785a594097bc71d505dc9bcd2c2f6f1ff6f4bab9dbd9d120bb76d06c5be8521a8ca7d -) - -set(PATCHES - 0001-cpool-cshutdown-force-close-connections-under-pressu.patch + SHA512 8262c3dc113cfd5744ef1b82dbccaa69448a9395ad5c094c22df5cf537a047a927d3332db2cb3be12a31a68a60d8d0fa8485b916e975eda36a4ebd860da4f621 ) # Extract archive diff --git a/ports/curl/vcpkg.json b/ports/curl/vcpkg.json index 2699df8..d60df95 100644 --- a/ports/curl/vcpkg.json +++ b/ports/curl/vcpkg.json @@ -1,6 +1,6 @@ { "name": "curl", - "version": "8.13.0", + "version": "8.16.0", "port-version": 1, "description": "A library for transferring data with URLs", "homepage": "https://curl.se/", @@ -34,7 +34,12 @@ "description": "Enable HTTP/3 support.", "dependencies": [ "nghttp3", - "ngtcp2" + { + "name": "ngtcp2", + "features": [ + "openssl" + ] + } ] }, "ipv6": { diff --git a/versions/baseline.json b/versions/baseline.json index 0ace547..c1fbbde 100644 --- a/versions/baseline.json +++ b/versions/baseline.json @@ -5,7 +5,7 @@ "port-version": 0 }, "curl": { - "baseline": "8.13.0", + "baseline": "8.16.0", "port-version": 1 }, "icu": {