From b02c90d07edd85e5219a2106b67568e521da077e Mon Sep 17 00:00:00 2001 From: cy Date: Mon, 30 Dec 2024 16:25:00 +0800 Subject: [PATCH 01/13] =?UTF-8?q?=E4=B8=80=E8=87=B4=E6=80=A7=E6=95=B4?= =?UTF-8?q?=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: cy --- BUILD.gn | 3 ++- buildconf.bat | 1 + bundle.json | 1 + customized/include/curl_config_standard.h | 1 + customized/include/curl_config_standard_http3.h | 3 ++- lib/install_cares.sh | 0 lib/netrc.h | 3 ++- lib/url.c | 3 ++- lib/vtls/gtls.c | 3 ++- plan9/include/mkfile | 1 + 10 files changed, 14 insertions(+), 5 deletions(-) create mode 100644 lib/install_cares.sh diff --git a/BUILD.gn b/BUILD.gn index e9e4e88e3..70639bc6d 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -8,7 +8,8 @@ # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and +# See the License for the +specific language governing permissions and # limitations under the License. import("//build/ohos.gni") diff --git a/buildconf.bat b/buildconf.bat index 615366118..2351efbaa 100644 --- a/buildconf.bat +++ b/buildconf.bat @@ -12,6 +12,7 @@ rem * This software is licensed as described in the file COPYING, which rem * you should have received as part of this distribution. The terms rem * are also available at https://curl.se/docs/copyright.html. rem * + rem * You may opt to use, copy, modify, merge, publish, distribute and/or sell rem * copies of the Software, and permit persons to whom the Software is rem * furnished to do so, under the terms of the COPYING file. diff --git a/bundle.json b/bundle.json index 7afb47fe5..056be2e8b 100644 --- a/bundle.json +++ b/bundle.json @@ -13,6 +13,7 @@ "component": { "name": "curl", "subsystem": "thirdparty", + "syscap": [], "features": [], "adapted_system_type": [ diff --git a/customized/include/curl_config_standard.h b/customized/include/curl_config_standard.h index e487a4405..fa58a51ff 100644 --- a/customized/include/curl_config_standard.h +++ b/customized/include/curl_config_standard.h @@ -7,6 +7,7 @@ /* Location of default ca bundle */ #define CURL_CA_BUNDLE NULL + /* define "1" to use built in CA store of SSL library */ /* #undef CURL_CA_FALLBACK */ diff --git a/customized/include/curl_config_standard_http3.h b/customized/include/curl_config_standard_http3.h index 6cd8b8f92..888f7b297 100644 --- a/customized/include/curl_config_standard_http3.h +++ b/customized/include/curl_config_standard_http3.h @@ -4,7 +4,8 @@ /* to enable curl debug memory tracking */ /* #undef CURLDEBUG */ -/* Location of default ca bundle */ +/* Location of defa +ult ca bundle */ #define CURL_CA_BUNDLE NULL /* define "1" to use built in CA store of SSL library */ diff --git a/lib/install_cares.sh b/lib/install_cares.sh new file mode 100644 index 000000000..e69de29bb diff --git a/lib/netrc.h b/lib/netrc.h index 9f2815f3b..6e52b8514 100644 --- a/lib/netrc.h +++ b/lib/netrc.h @@ -14,7 +14,8 @@ * 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 + * copies of the Software, a + * nd permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY diff --git a/lib/url.c b/lib/url.c index e5c619643..9bc5dd229 100644 --- a/lib/url.c +++ b/lib/url.c @@ -11,7 +11,8 @@ * you should have received as part of this distribution. The terms * are also available at https://curl.se/docs/copyright.html. * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * 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 * furnished to do so, under the terms of the COPYING file. * diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c index b95c5be3c..fa447a494 100644 --- a/lib/vtls/gtls.c +++ b/lib/vtls/gtls.c @@ -8,7 +8,8 @@ * Copyright (C) Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms + * you should have received as part of + * this distribution. The terms * are also available at https://curl.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell diff --git a/plan9/include/mkfile b/plan9/include/mkfile index a0970e932..202f6d838 100644 --- a/plan9/include/mkfile +++ b/plan9/include/mkfile @@ -7,6 +7,7 @@ # # Copyright (C) Daniel Stenberg, , et al. # + # 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.se/docs/copyright.html. -- Gitee From 9d62fc0b644ec97738dfa35fed7b551ed40c583b Mon Sep 17 00:00:00 2001 From: cy Date: Mon, 30 Dec 2024 08:54:00 +0000 Subject: [PATCH 02/13] update BUILD.gn. Signed-off-by: cy --- BUILD.gn | 172 +++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 141 insertions(+), 31 deletions(-) diff --git a/BUILD.gn b/BUILD.gn index 70639bc6d..d3e56aae8 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -8,11 +8,123 @@ # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the -specific language governing permissions and +# See the License for the specific language governing permissions and # limitations under the License. import("//build/ohos.gni") +cares_srcs = [ + "ares__addrinfo2hostent.c", + "ares__addrinfo_localhost.c", + "ares__close_sockets.c", + "ares__get_hostent.c", + "ares__parse_into_addrinfo.c", + "ares__read_line.c", + "ares__readaddrinfo.c", + "ares__sortaddrinfo.c", + "ares__timeval.c", + "ares_android.c", + "ares_cancel.c", + "ares_create_query.c", + "ares_data.c", + "ares_destroy.c", + "ares_expand_name.c", + "ares_expand_string.c", + "ares_fds.c", + "ares_free_hostent.c", + "ares_free_string.c", + "ares_freeaddrinfo.c", + "ares_getaddrinfo.c", + "ares_getenv.c", + "ares_gethostbyaddr.c", + "ares_gethostbyname.c", + "ares_getnameinfo.c", + "ares_getsock.c", + "ares_init.c", + "ares_library_init.c", + "ares_llist.c", + "ares_mkquery.c", + "ares_nowarn.c", + "ares_options.c", + "ares_parse_a_reply.c", + "ares_parse_aaaa_reply.c", + "ares_parse_caa_reply.c", + "ares_parse_mx_reply.c", + "ares_parse_naptr_reply.c", + "ares_parse_ns_reply.c", + "ares_parse_ptr_reply.c", + "ares_parse_soa_reply.c", + "ares_parse_srv_reply.c", + "ares_parse_txt_reply.c", + "ares_parse_uri_reply.c", + "ares_platform.c", + "ares_process.c", + "ares_query.c", + "ares_rand.c", + "ares_search.c", + "ares_send.c", + "ares_strcasecmp.c", + "ares_strdup.c", + "ares_strerror.c", + "ares_strsplit.c", + "ares_timeout.c", + "ares_version.c", + "ares_writev.c", + "bitncmp.c", + "inet_net_pton.c", + "inet_ntop.c", + "windows_port.c", +] + +src_path = "//third_party/cares" +cares_path = root_out_dir + "/third_party_cares" +code_dir = cares_path + "/c-ares-1.18.1" + +action("installOpenEulerCares") { + print("Cares install") + script = "install_cares.sh" + args = [ + rebase_path(src_path, root_build_dir), + rebase_path(cares_path, root_build_dir), + ] + inputs = [ src_path ] + outputs = [] + foreach(src, cares_srcs) { + outputs += [ "$code_dir/src/lib/" + src ] + } +} + +config("c_ares_config") { + cflags = [ + "-D_GNU_SOURCE", + "-D_HAS_EXCEPTIONS=0", + "-DHAVE_CONFIG_H", + "-Wno-macro-redefined", + ] +} + +ohos_static_library("c_ares") { + deps = [ ":installOpenEulerCares" ] + sources = [] + foreach(src, cares_srcs) { + sources += [ "$code_dir/src/lib/" + src ] + } + + public_configs = [ ":c_ares_config" ] + defines = [] + if (is_standard_system) { + defines += [ "OHOS_DNS_PROXY_BY_NETSYS=1" ] + } + + include_dirs = [ + "//third_party/cares/include", + "$code_dir", + "$code_dir/include", + ] + + subsystem_name = "thirdparty" + part_name = "curl" +} + declare_args() { netstack_feature_http3 = false } @@ -283,6 +395,10 @@ if (defined(ohos_lite)) { "//third_party/curl/customized/include", ] + if (is_cares_on) { + include_dirs += [ "//third_party/cares/include" ] + } + cflags = [ "-Wno-deprecated-declarations" ] } @@ -298,7 +414,7 @@ if (defined(ohos_lite)) { ohos_source_set("curl") { configs = [ ":curl_config" ] - external_deps = [ "openssl:libssl_shared" ] + configs += [ "//third_party/openssl:ssl_config_public" ] public_configs = [ ":curl_config_public" ] @@ -421,14 +537,13 @@ if (defined(ohos_lite)) { "//third_party/zlib:shared_libz", ] } else { - external_deps += [ + external_deps = [ "nghttp2:libnghttp2_shared", "openssl:libcrypto_shared", "openssl:libssl_shared", "zlib:shared_libz", ] } - if (current_os != "ios" && is_cares_on) { if (is_arkui_x) { deps += [ @@ -436,17 +551,13 @@ if (defined(ohos_lite)) { "//third_party/cares:c_ares", ] } else { - external_deps += [ - "brotli:brotli_shared", - "cares:c_ares", - ] + external_deps += [ "brotli:brotli_shared" ] } defines = [ - "USE_ARES", - "HAVE_BROTLI", "DISABLE_GETENV", ] } + subsystem_name = "thirdparty" part_name = "curl" } @@ -458,7 +569,7 @@ if (defined(ohos_lite)) { configs += [ "//vendor/open_source/quiche/quiche:quiche_config" ] configs += [ "//vendor/open_source/boringssl:boringssl_config" ] } else { - external_deps = [ "openssl:libssl_shared" ] + configs += [ "//third_party/openssl:ssl_config_public" ] } sources = curl_source @@ -584,13 +695,13 @@ if (defined(ohos_lite)) { "zlib:shared_libz", ] } else { - external_deps += [ + external_deps = [ "nghttp2:libnghttp2_shared", "zlib:shared_libz", ] if (netstack_feature_http3) { - deps += [ "//vendor/open_source/quiche/quiche:lib" ] + deps = [ "//vendor/open_source/quiche/quiche:lib" ] } else { external_deps += [ "openssl:libcrypto_shared", @@ -598,54 +709,50 @@ if (defined(ohos_lite)) { ] } } + if (is_cares_on) { - if (is_arkui_x) { - deps += [ - "//third_party/brotli:brotli_shared", - "//third_party/cares:c_ares", - ] + if (defined(deps)) { + deps += [ ":c_ares" ] } else { - external_deps += [ - "brotli:brotli_shared", - "cares:c_ares", - ] + deps = [ ":c_ares" ] } + external_deps += [ "brotli:brotli_shared" ] + external_deps += [ "netmanager_base:netsys_client" ] defines = [ "USE_ARES", "HAVE_BROTLI", "DISABLE_GETENV", ] } + subsystem_name = "thirdparty" part_name = "curl" } ohos_shared_library("curl_shared") { - if (current_os == "ios") { - ldflags = [ - "-Wl", - "-install_name", - "@rpath/libcurl_shared.framework/libcurl_shared", - ] - } + branch_protector_ret = "pac_ret" deps = [ ":curl" ] + configs = [ ":curl_config" ] + public_configs = [ ":curl_config_public" ] install_images = [ "updater", "system", ] + + subsystem_name = "thirdparty" innerapi_tags = [ "chipsetsdk", "platformsdk", "sasdk", ] - subsystem_name = "thirdparty" part_name = "curl" } ohos_shared_library("curl_shared_http3") { + branch_protector_ret = "pac_ret" if (current_os == "ios") { ldflags = [ "-Wl", @@ -678,6 +785,9 @@ if (defined(ohos_lite)) { subsystem_name = "thirdparty" part_name = "curl" } + } else { + group("libcurl_shared") { + } } } -- Gitee From c7aa4f362b8987bd129b4709cbacdcbef7a9c5b8 Mon Sep 17 00:00:00 2001 From: cy Date: Mon, 30 Dec 2024 08:55:13 +0000 Subject: [PATCH 03/13] update bundle.json. Signed-off-by: cy --- bundle.json | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/bundle.json b/bundle.json index 056be2e8b..5f0fd2f4d 100644 --- a/bundle.json +++ b/bundle.json @@ -13,7 +13,6 @@ "component": { "name": "curl", "subsystem": "thirdparty", - "syscap": [], "features": [], "adapted_system_type": [ @@ -24,19 +23,13 @@ "ram": "", "deps": { "components": [ - "cares", "nghttp2", "openssl", "zlib", - "brotli" + "netmanager_base", + "brotli" ], - "third_party": [ - "nghttp2", - "openssl", - "zlib", - "cares", - "nghttp2" - ] + "third_party": [] }, "build": { "sub_component": [ @@ -58,11 +51,7 @@ } }, { - "name":"//third_party/curl:libcurl_shared", - "header":{ - "header_files":[], - "header_base":"//third_party/curl/include/curl" - } + "name":"//third_party/curl:libcurl_shared" } ], "test": [] -- Gitee From 9a8eaccf99c39d10e299455c6c84ff6ea0d3e0bc Mon Sep 17 00:00:00 2001 From: cy Date: Mon, 30 Dec 2024 08:55:58 +0000 Subject: [PATCH 04/13] update customized/include/curl_config_standard.h. Signed-off-by: cy --- customized/include/curl_config_standard.h | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/customized/include/curl_config_standard.h b/customized/include/curl_config_standard.h index fa58a51ff..fb2b6a270 100644 --- a/customized/include/curl_config_standard.h +++ b/customized/include/curl_config_standard.h @@ -7,7 +7,6 @@ /* Location of default ca bundle */ #define CURL_CA_BUNDLE NULL - /* define "1" to use built in CA store of SSL library */ /* #undef CURL_CA_FALLBACK */ @@ -544,7 +543,7 @@ /* #undef HAVE_POLL */ /* If you have a fine poll */ -/* #undef HAVE_POLL_FINE */ +#define HAVE_POLL_FINE 1 /* Define to 1 if you have the header file. */ #define HAVE_POLL_H 1 @@ -1044,6 +1043,25 @@ /* Use Unix domain sockets */ #define USE_UNIX_SOCKETS 1 +#define HAVE_ATOMIC 1 +#define HAVE_FCHMOD 1 +#define HAVE_CLOCK_GETTIME_MONOTONIC 1 +#define HAVE_CLOCK_GETTIME_MONOTONIC_RAW 1 +#define HAVE_FSEEKO 1 +#define HAVE_GETHOSTBYNAME_R 1 +#define HAVE_GETHOSTBYNAME_R_6 1 +#define HAVE_SA_FAMILY_T 1 +#define HAVE_SUSECONDS_T 1 +#define HAVE_NETINET_UDP_H 1 +#define HAVE_SSL_SET0_WBIO 1 +#define HAVE_SCHED_YIELD 1 +#define HAVE_SENDMSG 1 +#define HAVE_FSETXATTR_5 1 +#define HAVE_SNPRINTF 1 +#define HAVE_STDATOMIC_H 1 +#define HAVE_TERMIO_H 1 +#define HAVE_WRITABLE_ARGV 1 + /* Define to 1 if you have the `normaliz' (WinIDN) library (-lnormaliz). */ /* #undef USE_WIN32_IDN */ -- Gitee From 01c6e1494e2abc44c3c79970eb372e8b3f18dcc0 Mon Sep 17 00:00:00 2001 From: cy Date: Mon, 30 Dec 2024 08:56:28 +0000 Subject: [PATCH 05/13] update customized/include/curl_config_standard_http3.h. Signed-off-by: cy --- .../include/curl_config_standard_http3.h | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/customized/include/curl_config_standard_http3.h b/customized/include/curl_config_standard_http3.h index 888f7b297..51ab5a679 100644 --- a/customized/include/curl_config_standard_http3.h +++ b/customized/include/curl_config_standard_http3.h @@ -4,8 +4,7 @@ /* to enable curl debug memory tracking */ /* #undef CURLDEBUG */ -/* Location of defa -ult ca bundle */ +/* Location of default ca bundle */ #define CURL_CA_BUNDLE NULL /* define "1" to use built in CA store of SSL library */ @@ -545,7 +544,7 @@ ult ca bundle */ /* #undef HAVE_POLL */ /* If you have a fine poll */ -/* #undef HAVE_POLL_FINE */ +#define HAVE_POLL_FINE 1 /* Define to 1 if you have the header file. */ #define HAVE_POLL_H 1 @@ -1045,6 +1044,25 @@ ult ca bundle */ /* Use Unix domain sockets */ #define USE_UNIX_SOCKETS 1 +#define HAVE_ATOMIC 1 +#define HAVE_FCHMOD 1 +#define HAVE_CLOCK_GETTIME_MONOTONIC 1 +#define HAVE_CLOCK_GETTIME_MONOTONIC_RAW 1 +#define HAVE_FSEEKO 1 +#define HAVE_GETHOSTBYNAME_R 1 +#define HAVE_GETHOSTBYNAME_R_6 1 +#define HAVE_SA_FAMILY_T 1 +#define HAVE_SUSECONDS_T 1 +#define HAVE_NETINET_UDP_H 1 +#define HAVE_SSL_SET0_WBIO 1 +#define HAVE_SCHED_YIELD 1 +#define HAVE_SENDMSG 1 +#define HAVE_FSETXATTR_5 1 +#define HAVE_SNPRINTF 1 +#define HAVE_STDATOMIC_H 1 +#define HAVE_TERMIO_H 1 +#define HAVE_WRITABLE_ARGV 1 + /* Define to 1 if you have the `normaliz' (WinIDN) library (-lnormaliz). */ /* #undef USE_WIN32_IDN */ -- Gitee From a8dc6dd79a39e1791ed2f6364fcd76badd6fb4a2 Mon Sep 17 00:00:00 2001 From: cy Date: Mon, 30 Dec 2024 08:58:08 +0000 Subject: [PATCH 06/13] update lib/netrc.h. Signed-off-by: cy --- lib/netrc.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/netrc.h b/lib/netrc.h index 6e52b8514..9f2815f3b 100644 --- a/lib/netrc.h +++ b/lib/netrc.h @@ -14,8 +14,7 @@ * 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, a - * nd permit persons to whom the Software is + * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -- Gitee From cec948600d6c5c7eda2a9106312169e368ddd137 Mon Sep 17 00:00:00 2001 From: cy Date: Mon, 30 Dec 2024 09:01:13 +0000 Subject: [PATCH 07/13] update lib/vtls/gtls.c. Signed-off-by: cy --- lib/vtls/gtls.c | 149 ++++++++++++++++++++++++------------------------ 1 file changed, 74 insertions(+), 75 deletions(-) diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c index fa447a494..7cc3c6d52 100644 --- a/lib/vtls/gtls.c +++ b/lib/vtls/gtls.c @@ -8,8 +8,7 @@ * Copyright (C) Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which - * you should have received as part of - * this distribution. The terms + * you should have received as part of this distribution. The terms * are also available at https://curl.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell @@ -537,6 +536,13 @@ CURLcode gtls_client_init(struct Curl_easy *data, init_flags |= GNUTLS_NO_TICKETS; #endif +#if defined(GNUTLS_NO_STATUS_REQUEST) + if(!config->verifystatus) + /* Disable the "status_request" TLS extension, enabled by default since + GnuTLS 3.8.0. */ + init_flags |= GNUTLS_NO_STATUS_REQUEST; +#endif + rc = gnutls_init(>ls->session, init_flags); if(rc != GNUTLS_E_SUCCESS) { failf(data, "gnutls_init() failed: %d", rc); @@ -922,104 +928,97 @@ Curl_gtls_verifyserver(struct Curl_easy *data, infof(data, " server certificate verification SKIPPED"); if(config->verifystatus) { - if(gnutls_ocsp_status_request_is_checked(session, 0) == 0) { - gnutls_datum_t status_request; - gnutls_ocsp_resp_t ocsp_resp; + gnutls_datum_t status_request; + gnutls_ocsp_resp_t ocsp_resp; + gnutls_ocsp_cert_status_t status; + gnutls_x509_crl_reason_t reason; - gnutls_ocsp_cert_status_t status; - gnutls_x509_crl_reason_t reason; + rc = gnutls_ocsp_status_request_get(session, &status_request); - rc = gnutls_ocsp_status_request_get(session, &status_request); + if(rc == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { + failf(data, "No OCSP response received"); + return CURLE_SSL_INVALIDCERTSTATUS; + } - infof(data, " server certificate status verification FAILED"); + if(rc < 0) { + failf(data, "Invalid OCSP response received"); + return CURLE_SSL_INVALIDCERTSTATUS; + } - if(rc == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { - failf(data, "No OCSP response received"); - return CURLE_SSL_INVALIDCERTSTATUS; - } + gnutls_ocsp_resp_init(&ocsp_resp); - if(rc < 0) { - failf(data, "Invalid OCSP response received"); - return CURLE_SSL_INVALIDCERTSTATUS; - } + rc = gnutls_ocsp_resp_import(ocsp_resp, &status_request); + if(rc < 0) { + failf(data, "Invalid OCSP response received"); + return CURLE_SSL_INVALIDCERTSTATUS; + } - gnutls_ocsp_resp_init(&ocsp_resp); + (void)gnutls_ocsp_resp_get_single(ocsp_resp, 0, NULL, NULL, NULL, NULL, + &status, NULL, NULL, NULL, &reason); - rc = gnutls_ocsp_resp_import(ocsp_resp, &status_request); - if(rc < 0) { - failf(data, "Invalid OCSP response received"); - return CURLE_SSL_INVALIDCERTSTATUS; - } + switch(status) { + case GNUTLS_OCSP_CERT_GOOD: + break; - (void)gnutls_ocsp_resp_get_single(ocsp_resp, 0, NULL, NULL, NULL, NULL, - &status, NULL, NULL, NULL, &reason); + case GNUTLS_OCSP_CERT_REVOKED: { + const char *crl_reason; - switch(status) { - case GNUTLS_OCSP_CERT_GOOD: + switch(reason) { + default: + case GNUTLS_X509_CRLREASON_UNSPECIFIED: + crl_reason = "unspecified reason"; break; - case GNUTLS_OCSP_CERT_REVOKED: { - const char *crl_reason; - - switch(reason) { - default: - case GNUTLS_X509_CRLREASON_UNSPECIFIED: - crl_reason = "unspecified reason"; - break; - - case GNUTLS_X509_CRLREASON_KEYCOMPROMISE: - crl_reason = "private key compromised"; - break; - - case GNUTLS_X509_CRLREASON_CACOMPROMISE: - crl_reason = "CA compromised"; - break; - - case GNUTLS_X509_CRLREASON_AFFILIATIONCHANGED: - crl_reason = "affiliation has changed"; - break; + case GNUTLS_X509_CRLREASON_KEYCOMPROMISE: + crl_reason = "private key compromised"; + break; - case GNUTLS_X509_CRLREASON_SUPERSEDED: - crl_reason = "certificate superseded"; - break; + case GNUTLS_X509_CRLREASON_CACOMPROMISE: + crl_reason = "CA compromised"; + break; - case GNUTLS_X509_CRLREASON_CESSATIONOFOPERATION: - crl_reason = "operation has ceased"; - break; + case GNUTLS_X509_CRLREASON_AFFILIATIONCHANGED: + crl_reason = "affiliation has changed"; + break; - case GNUTLS_X509_CRLREASON_CERTIFICATEHOLD: - crl_reason = "certificate is on hold"; - break; + case GNUTLS_X509_CRLREASON_SUPERSEDED: + crl_reason = "certificate superseded"; + break; - case GNUTLS_X509_CRLREASON_REMOVEFROMCRL: - crl_reason = "will be removed from delta CRL"; - break; + case GNUTLS_X509_CRLREASON_CESSATIONOFOPERATION: + crl_reason = "operation has ceased"; + break; - case GNUTLS_X509_CRLREASON_PRIVILEGEWITHDRAWN: - crl_reason = "privilege withdrawn"; - break; + case GNUTLS_X509_CRLREASON_CERTIFICATEHOLD: + crl_reason = "certificate is on hold"; + break; - case GNUTLS_X509_CRLREASON_AACOMPROMISE: - crl_reason = "AA compromised"; - break; - } + case GNUTLS_X509_CRLREASON_REMOVEFROMCRL: + crl_reason = "will be removed from delta CRL"; + break; - failf(data, "Server certificate was revoked: %s", crl_reason); + case GNUTLS_X509_CRLREASON_PRIVILEGEWITHDRAWN: + crl_reason = "privilege withdrawn"; break; - } - default: - case GNUTLS_OCSP_CERT_UNKNOWN: - failf(data, "Server certificate status is unknown"); + case GNUTLS_X509_CRLREASON_AACOMPROMISE: + crl_reason = "AA compromised"; break; } - gnutls_ocsp_resp_deinit(ocsp_resp); + failf(data, "Server certificate was revoked: %s", crl_reason); + break; + } + + default: + case GNUTLS_OCSP_CERT_UNKNOWN: + failf(data, "Server certificate status is unknown"); + break; + } + gnutls_ocsp_resp_deinit(ocsp_resp); + if(status != GNUTLS_OCSP_CERT_GOOD) return CURLE_SSL_INVALIDCERTSTATUS; - } - else - infof(data, " server certificate status verification OK"); } else infof(data, " server certificate status verification SKIPPED"); -- Gitee From 468f5b667cfb82451818bdf601b6c3ec2dfee912 Mon Sep 17 00:00:00 2001 From: cy Date: Mon, 30 Dec 2024 09:07:58 +0000 Subject: [PATCH 08/13] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=96=87=E4=BB=B6=20bu?= =?UTF-8?q?ildconf.bat?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- buildconf.bat | 320 -------------------------------------------------- 1 file changed, 320 deletions(-) delete mode 100644 buildconf.bat diff --git a/buildconf.bat b/buildconf.bat deleted file mode 100644 index 2351efbaa..000000000 --- a/buildconf.bat +++ /dev/null @@ -1,320 +0,0 @@ -@echo off -rem *************************************************************************** -rem * _ _ ____ _ -rem * Project ___| | | | _ \| | -rem * / __| | | | |_) | | -rem * | (__| |_| | _ <| |___ -rem * \___|\___/|_| \_\_____| -rem * -rem * Copyright (C) Daniel Stenberg, , et al. -rem * -rem * This software is licensed as described in the file COPYING, which -rem * you should have received as part of this distribution. The terms -rem * are also available at https://curl.se/docs/copyright.html. -rem * - -rem * You may opt to use, copy, modify, merge, publish, distribute and/or sell -rem * copies of the Software, and permit persons to whom the Software is -rem * furnished to do so, under the terms of the COPYING file. -rem * -rem * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -rem * KIND, either express or implied. -rem * -rem * SPDX-License-Identifier: curl -rem * -rem *************************************************************************** - -rem NOTES -rem -rem This batch file must be used to set up a git tree to build on systems where -rem there is no autotools support (i.e. DOS and Windows). -rem - -:begin - rem Set our variables - if "%OS%" == "Windows_NT" setlocal - set MODE=GENERATE - - rem Switch to this batch file's directory - cd /d "%~0\.." 1>NUL 2>&1 - - rem Check we are running from a curl git repository - if not exist GIT-INFO goto norepo - - rem Detect programs. HAVE_ - rem When not found the variable is set undefined. The undefined pattern - rem allows for statements like "if not defined HAVE_PERL (command)" - groff --version NUL 2>&1 - if errorlevel 1 (set HAVE_GROFF=) else (set HAVE_GROFF=Y) - nroff --version NUL 2>&1 - if errorlevel 1 (set HAVE_NROFF=) else (set HAVE_NROFF=Y) - perl --version NUL 2>&1 - if errorlevel 1 (set HAVE_PERL=) else (set HAVE_PERL=Y) - gzip --version NUL 2>&1 - if errorlevel 1 (set HAVE_GZIP=) else (set HAVE_GZIP=Y) - -:parseArgs - if "%~1" == "" goto start - - if /i "%~1" == "-clean" ( - set MODE=CLEAN - ) else if /i "%~1" == "-?" ( - goto syntax - ) else if /i "%~1" == "-h" ( - goto syntax - ) else if /i "%~1" == "-help" ( - goto syntax - ) else ( - goto unknown - ) - - shift & goto parseArgs - -:start - if "%MODE%" == "GENERATE" ( - echo. - echo Generating prerequisite files - - call :generate - if errorlevel 3 goto nogenhugehelp - if errorlevel 2 goto nogenmakefile - if errorlevel 1 goto warning - - ) else ( - echo. - echo Removing prerequisite files - - call :clean - if errorlevel 2 goto nocleanhugehelp - if errorlevel 1 goto nocleanmakefile - ) - - goto success - -rem Main generate function. -rem -rem Returns: -rem -rem 0 - success -rem 1 - success with simplified tool_hugehelp.c -rem 2 - failed to generate Makefile -rem 3 - failed to generate tool_hugehelp.c -rem -:generate - if "%OS%" == "Windows_NT" setlocal - set BASIC_HUGEHELP=0 - - rem Create Makefile - echo * %CD%\Makefile - if exist Makefile.dist ( - copy /Y Makefile.dist Makefile 1>NUL 2>&1 - if errorlevel 1 ( - if "%OS%" == "Windows_NT" endlocal - exit /B 2 - ) - ) - - rem Create tool_hugehelp.c - echo * %CD%\src\tool_hugehelp.c - call :genHugeHelp - if errorlevel 2 ( - if "%OS%" == "Windows_NT" endlocal - exit /B 3 - ) - if errorlevel 1 ( - set BASIC_HUGEHELP=1 - ) - cmd /c exit 0 - - rem Setup c-ares git tree - if exist ares\buildconf.bat ( - echo. - echo Configuring c-ares build environment - cd ares - call buildconf.bat - cd .. - ) - - if "%BASIC_HUGEHELP%" == "1" ( - if "%OS%" == "Windows_NT" endlocal - exit /B 1 - ) - - if "%OS%" == "Windows_NT" endlocal - exit /B 0 - -rem Main clean function. -rem -rem Returns: -rem -rem 0 - success -rem 1 - failed to clean Makefile -rem 2 - failed to clean tool_hugehelp.c -rem -:clean - rem Remove Makefile - echo * %CD%\Makefile - if exist Makefile ( - del Makefile 2>NUL - if exist Makefile ( - exit /B 1 - ) - ) - - rem Remove tool_hugehelp.c - echo * %CD%\src\tool_hugehelp.c - if exist src\tool_hugehelp.c ( - del src\tool_hugehelp.c 2>NUL - if exist src\tool_hugehelp.c ( - exit /B 2 - ) - ) - - exit /B - -rem Function to generate src\tool_hugehelp.c -rem -rem Returns: -rem -rem 0 - full tool_hugehelp.c generated -rem 1 - simplified tool_hugehelp.c -rem 2 - failure -rem -:genHugeHelp - if "%OS%" == "Windows_NT" setlocal - set LC_ALL=C - set ROFFCMD= - set BASIC=1 - - if defined HAVE_PERL ( - if defined HAVE_GROFF ( - set ROFFCMD=groff -mtty-char -Tascii -P-c -man - ) else if defined HAVE_NROFF ( - set ROFFCMD=nroff -c -Tascii -man - ) - ) - - if defined ROFFCMD ( - echo #include "tool_setup.h"> src\tool_hugehelp.c - echo #include "tool_hugehelp.h">> src\tool_hugehelp.c - - if defined HAVE_GZIP ( - echo #ifndef HAVE_LIBZ>> src\tool_hugehelp.c - ) - - %ROFFCMD% docs\curl.1 2>NUL | perl src\mkhelp.pl docs\MANUAL >> src\tool_hugehelp.c - if defined HAVE_GZIP ( - echo #else>> src\tool_hugehelp.c - %ROFFCMD% docs\curl.1 2>NUL | perl src\mkhelp.pl -c docs\MANUAL >> src\tool_hugehelp.c - echo #endif /^* HAVE_LIBZ ^*/>> src\tool_hugehelp.c - ) - - set BASIC=0 - ) else ( - if exist src\tool_hugehelp.c.cvs ( - copy /Y src\tool_hugehelp.c.cvs src\tool_hugehelp.c 1>NUL 2>&1 - ) else ( - echo #include "tool_setup.h"> src\tool_hugehelp.c - echo #include "tool_hugehelp.h">> src\tool_hugehelp.c - echo.>> src\tool_hugehelp.c - echo void hugehelp(void^)>> src\tool_hugehelp.c - echo {>> src\tool_hugehelp.c - echo #ifdef USE_MANUAL>> src\tool_hugehelp.c - echo fputs("Built-in manual not included\n", stdout^);>> src\tool_hugehelp.c - echo #endif>> src\tool_hugehelp.c - echo }>> src\tool_hugehelp.c - ) - ) - - findstr "/C:void hugehelp(void)" src\tool_hugehelp.c 1>NUL 2>&1 - if errorlevel 1 ( - if "%OS%" == "Windows_NT" endlocal - exit /B 2 - ) - - if "%BASIC%" == "1" ( - if "%OS%" == "Windows_NT" endlocal - exit /B 1 - ) - - if "%OS%" == "Windows_NT" endlocal - exit /B 0 - -rem Function to clean-up local variables under DOS, Windows 3.x and -rem Windows 9x as setlocal isn't available until Windows NT -rem -:dosCleanup - set MODE= - set HAVE_GROFF= - set HAVE_NROFF= - set HAVE_PERL= - set HAVE_GZIP= - set BASIC_HUGEHELP= - set LC_ALL - set ROFFCMD= - set BASIC= - - exit /B - -:syntax - rem Display the help - echo. - echo Usage: buildconf [-clean] - echo. - echo -clean - Removes the files - goto error - -:unknown - echo. - echo Error: Unknown argument '%1' - goto error - -:norepo - echo. - echo Error: This batch file should only be used with a curl git repository - goto error - -:nogenmakefile - echo. - echo Error: Unable to generate Makefile - goto error - -:nogenhugehelp - echo. - echo Error: Unable to generate src\tool_hugehelp.c - goto error - -:nocleanmakefile - echo. - echo Error: Unable to clean Makefile - goto error - -:nocleanhugehelp - echo. - echo Error: Unable to clean src\tool_hugehelp.c - goto error - -:warning - echo. - echo Warning: The curl manual could not be integrated in the source. This means when - echo you build curl the manual will not be available (curl --man^). Integration of - echo the manual is not required and a summary of the options will still be available - echo (curl --help^). To integrate the manual your PATH is required to have - echo groff/nroff, perl and optionally gzip for compression. - goto success - -:error - if "%OS%" == "Windows_NT" ( - endlocal - ) else ( - call :dosCleanup - ) - exit /B 1 - -:success - if "%OS%" == "Windows_NT" ( - endlocal - ) else ( - call :dosCleanup - ) - exit /B 0 -- Gitee From 45e86c5204987f8a4177946b75ba013bd29ddd45 Mon Sep 17 00:00:00 2001 From: cy Date: Mon, 30 Dec 2024 09:09:58 +0000 Subject: [PATCH 09/13] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=96=87=E4=BB=B6=20li?= =?UTF-8?q?b/install=5Fcares.sh?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/install_cares.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 lib/install_cares.sh diff --git a/lib/install_cares.sh b/lib/install_cares.sh deleted file mode 100644 index e69de29bb..000000000 -- Gitee From ec716dae230c852ff4ef425bc1d5c7c55608e222 Mon Sep 17 00:00:00 2001 From: cy Date: Mon, 30 Dec 2024 09:11:14 +0000 Subject: [PATCH 10/13] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=96=87=E4=BB=B6=20pl?= =?UTF-8?q?an9/include/mkfile?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plan9/include/mkfile | 37 ------------------------------------- 1 file changed, 37 deletions(-) delete mode 100644 plan9/include/mkfile diff --git a/plan9/include/mkfile b/plan9/include/mkfile deleted file mode 100644 index 202f6d838..000000000 --- a/plan9/include/mkfile +++ /dev/null @@ -1,37 +0,0 @@ -#*************************************************************************** -# _ _ ____ _ -# Project ___| | | | _ \| | -# / __| | | | |_) | | -# | (__| |_| | _ <| |___ -# \___|\___/|_| \_\_____| -# -# Copyright (C) Daniel Stenberg, , et al. -# - -# 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.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 -# furnished to do so, under the terms of the COPYING file. -# -# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -# KIND, either express or implied. -# -# SPDX-License-Identifier: curl -# -########################################################################### - -DIR=/sys/include/ape/curl -HFILES=`{ls curl/*.h} - -all:V: $HFILES - -install:V: all - mkdir -p $DIR - cp curl/*.h $DIR/ - -clean:V: $HFILES # do nothing - -nuke:V: clean -- Gitee From 66a96bc45df14a0fe5651f7381f80c5ce92dcc5e Mon Sep 17 00:00:00 2001 From: cy Date: Mon, 30 Dec 2024 09:19:23 +0000 Subject: [PATCH 11/13] update bundle.json. Signed-off-by: cy --- bundle.json | 1334 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1334 insertions(+) diff --git a/bundle.json b/bundle.json index 5f0fd2f4d..92d397e0f 100644 --- a/bundle.json +++ b/bundle.json @@ -58,3 +58,1337 @@ } } } + +third_party/curl/lib/url.c +static CURLcode parse_remote_port(struct Curl_easy *data, + struct connectdata *conn) +{ + + if(data->set.use_port && data->state.allow_port) { + /* if set, we use this instead of the port possibly given in the URL */ + char portbuf[16]; + CURLUcode uc; + conn->remote_port = data->set.use_port; + msnprintf(portbuf, sizeof(portbuf), "%d", conn->remote_port); + uc = curl_url_set(data->state.uh, CURLUPART_PORT, portbuf, 0); + if(uc) + return CURLE_OUT_OF_MEMORY; + } + + return CURLE_OK; +} + +/* + * Override the login details from the URL with that in the CURLOPT_USERPWD + * option or a .netrc file, if applicable. + */ +static CURLcode override_login(struct Curl_easy *data, + struct connectdata *conn) +{ + CURLUcode uc; + char **userp = &conn->user; + char **passwdp = &conn->passwd; + char **optionsp = &conn->options; + + if(data->set.str[STRING_OPTIONS]) { + free(*optionsp); + *optionsp = strdup(data->set.str[STRING_OPTIONS]); + if(!*optionsp) + return CURLE_OUT_OF_MEMORY; + } + +#ifndef CURL_DISABLE_NETRC + if(data->set.use_netrc == CURL_NETRC_REQUIRED) { + Curl_safefree(*userp); + Curl_safefree(*passwdp); + } + conn->bits.netrc = FALSE; + if(data->set.use_netrc && !data->set.str[STRING_USERNAME]) { + int ret; + bool url_provided = FALSE; + + if(data->state.aptr.user) { + /* there was a user name in the URL. Use the URL decoded version */ + userp = &data->state.aptr.user; + url_provided = TRUE; + } + + ret = Curl_parsenetrc(conn->host.name, + userp, passwdp, + data->set.str[STRING_NETRC_FILE]); + if(ret > 0) { + infof(data, "Couldn't find host %s in the %s file; using defaults", + conn->host.name, + (data->set.str[STRING_NETRC_FILE] ? + data->set.str[STRING_NETRC_FILE] : ".netrc")); + } + else if(ret < 0) { + failf(data, ".netrc parser error"); + return CURLE_READ_ERROR; + } + else { + /* set bits.netrc TRUE to remember that we got the name from a .netrc + file, so that it is safe to use even if we followed a Location: to a + different host or similar. */ + conn->bits.netrc = TRUE; + } + if(url_provided) { + Curl_safefree(conn->user); + conn->user = strdup(*userp); + if(!conn->user) + return CURLE_OUT_OF_MEMORY; + } + /* no user was set but a password, set a blank user */ + if(!*userp && *passwdp) { + *userp = strdup(""); + if(!*userp) + return CURLE_OUT_OF_MEMORY; + } + } +#endif + + /* for updated strings, we update them in the URL */ + if(*userp) { + CURLcode result; + if(data->state.aptr.user != *userp) { + /* nothing to do then */ + result = Curl_setstropt(&data->state.aptr.user, *userp); + if(result) + return result; + } + } + if(data->state.aptr.user) { + uc = curl_url_set(data->state.uh, CURLUPART_USER, data->state.aptr.user, + CURLU_URLENCODE); + if(uc) + return Curl_uc_to_curlcode(uc); + if(!*userp) { + *userp = strdup(data->state.aptr.user); + if(!*userp) + return CURLE_OUT_OF_MEMORY; + } + } + if(*passwdp) { + CURLcode result = Curl_setstropt(&data->state.aptr.passwd, *passwdp); + if(result) + return result; + } + if(data->state.aptr.passwd) { + uc = curl_url_set(data->state.uh, CURLUPART_PASSWORD, + data->state.aptr.passwd, CURLU_URLENCODE); + if(uc) + return Curl_uc_to_curlcode(uc); + if(!*passwdp) { + *passwdp = strdup(data->state.aptr.passwd); + if(!*passwdp) + return CURLE_OUT_OF_MEMORY; + } + } + + return CURLE_OK; +} + +/* + * Set the login details so they're available in the connection + */ +static CURLcode set_login(struct Curl_easy *data, + struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + const char *setuser = CURL_DEFAULT_USER; + const char *setpasswd = CURL_DEFAULT_PASSWORD; + + /* If our protocol needs a password and we have none, use the defaults */ + if((conn->handler->flags & PROTOPT_NEEDSPWD) && !data->state.aptr.user) + ; + else { + setuser = ""; + setpasswd = ""; + } + /* Store the default user */ + if(!conn->user) { + conn->user = strdup(setuser); + if(!conn->user) + return CURLE_OUT_OF_MEMORY; + } + + /* Store the default password */ + if(!conn->passwd) { + conn->passwd = strdup(setpasswd); + if(!conn->passwd) + result = CURLE_OUT_OF_MEMORY; + } + + return result; +} + +/* + * Parses a "host:port" string to connect to. + * The hostname and the port may be empty; in this case, NULL is returned for + * the hostname and -1 for the port. + */ +static CURLcode parse_connect_to_host_port(struct Curl_easy *data, + const char *host, + char **hostname_result, + int *port_result) +{ + char *host_dup; + char *hostptr; + char *host_portno; + char *portptr; + int port = -1; + CURLcode result = CURLE_OK; + +#if defined(CURL_DISABLE_VERBOSE_STRINGS) + (void) data; +#endif + + *hostname_result = NULL; + *port_result = -1; + + if(!host || !*host) + return CURLE_OK; + + host_dup = strdup(host); + if(!host_dup) + return CURLE_OUT_OF_MEMORY; + + hostptr = host_dup; + + /* start scanning for port number at this point */ + portptr = hostptr; + + /* detect and extract RFC6874-style IPv6-addresses */ + if(*hostptr == '[') { +#ifdef ENABLE_IPV6 + char *ptr = ++hostptr; /* advance beyond the initial bracket */ + while(*ptr && (ISXDIGIT(*ptr) || (*ptr == ':') || (*ptr == '.'))) + ptr++; + if(*ptr == '%') { + /* There might be a zone identifier */ + if(strncmp("%25", ptr, 3)) + infof(data, "Please URL encode %% as %%25, see RFC 6874."); + ptr++; + /* Allow unreserved characters as defined in RFC 3986 */ + while(*ptr && (ISALPHA(*ptr) || ISXDIGIT(*ptr) || (*ptr == '-') || + (*ptr == '.') || (*ptr == '_') || (*ptr == '~'))) + ptr++; + } + if(*ptr == ']') + /* yeps, it ended nicely with a bracket as well */ + *ptr++ = '\0'; + else + infof(data, "Invalid IPv6 address format"); + portptr = ptr; + /* Note that if this didn't end with a bracket, we still advanced the + * hostptr first, but I can't see anything wrong with that as no host + * name nor a numeric can legally start with a bracket. + */ +#else + failf(data, "Use of IPv6 in *_CONNECT_TO without IPv6 support built-in"); + result = CURLE_NOT_BUILT_IN; + goto error; +#endif + } + + /* Get port number off server.com:1080 */ + host_portno = strchr(portptr, ':'); + if(host_portno) { + char *endp = NULL; + *host_portno = '\0'; /* cut off number from host name */ + host_portno++; + if(*host_portno) { + long portparse = strtol(host_portno, &endp, 10); + if((endp && *endp) || (portparse < 0) || (portparse > 65535)) { + failf(data, "No valid port number in connect to host string (%s)", + host_portno); + result = CURLE_SETOPT_OPTION_SYNTAX; + goto error; + } + else + port = (int)portparse; /* we know it will fit */ + } + } + + /* now, clone the cleaned host name */ + DEBUGASSERT(hostptr); + *hostname_result = strdup(hostptr); + if(!*hostname_result) { + result = CURLE_OUT_OF_MEMORY; + goto error; + } + + *port_result = port; + +error: + free(host_dup); + return result; +} + +/* + * Parses one "connect to" string in the form: + * "HOST:PORT:CONNECT-TO-HOST:CONNECT-TO-PORT". + */ +static CURLcode parse_connect_to_string(struct Curl_easy *data, + struct connectdata *conn, + const char *conn_to_host, + char **host_result, + int *port_result) +{ + CURLcode result = CURLE_OK; + const char *ptr = conn_to_host; + int host_match = FALSE; + int port_match = FALSE; + + *host_result = NULL; + *port_result = -1; + + if(*ptr == ':') { + /* an empty hostname always matches */ + host_match = TRUE; + ptr++; + } + else { + /* check whether the URL's hostname matches */ + size_t hostname_to_match_len; + char *hostname_to_match = aprintf("%s%s%s", + conn->bits.ipv6_ip ? "[" : "", + conn->host.name, + conn->bits.ipv6_ip ? "]" : ""); + if(!hostname_to_match) + return CURLE_OUT_OF_MEMORY; + hostname_to_match_len = strlen(hostname_to_match); + host_match = strncasecompare(ptr, hostname_to_match, + hostname_to_match_len); + free(hostname_to_match); + ptr += hostname_to_match_len; + + host_match = host_match && *ptr == ':'; + ptr++; + } + + if(host_match) { + if(*ptr == ':') { + /* an empty port always matches */ + port_match = TRUE; + ptr++; + } + else { + /* check whether the URL's port matches */ + char *ptr_next = strchr(ptr, ':'); + if(ptr_next) { + char *endp = NULL; + long port_to_match = strtol(ptr, &endp, 10); + if((endp == ptr_next) && (port_to_match == conn->remote_port)) { + port_match = TRUE; + ptr = ptr_next + 1; + } + } + } + } + + if(host_match && port_match) { + /* parse the hostname and port to connect to */ + result = parse_connect_to_host_port(data, ptr, host_result, port_result); + } + + return result; +} + +/* + * Processes all strings in the "connect to" slist, and uses the "connect + * to host" and "connect to port" of the first string that matches. + */ +static CURLcode parse_connect_to_slist(struct Curl_easy *data, + struct connectdata *conn, + struct curl_slist *conn_to_host) +{ + CURLcode result = CURLE_OK; + char *host = NULL; + int port = -1; + + while(conn_to_host && !host && port == -1) { + result = parse_connect_to_string(data, conn, conn_to_host->data, + &host, &port); + if(result) + return result; + + if(host && *host) { + conn->conn_to_host.rawalloc = host; + conn->conn_to_host.name = host; + conn->bits.conn_to_host = TRUE; + + infof(data, "Connecting to hostname: %s", host); + } + else { + /* no "connect to host" */ + conn->bits.conn_to_host = FALSE; + Curl_safefree(host); + } + + if(port >= 0) { + conn->conn_to_port = port; + conn->bits.conn_to_port = TRUE; + infof(data, "Connecting to port: %d", port); + } + else { + /* no "connect to port" */ + conn->bits.conn_to_port = FALSE; + port = -1; + } + + conn_to_host = conn_to_host->next; + } + +#ifndef CURL_DISABLE_ALTSVC + if(data->asi && !host && (port == -1) && + ((conn->handler->protocol == CURLPROTO_HTTPS) || +#ifdef CURLDEBUG + /* allow debug builds to circumvent the HTTPS restriction */ + getenv("CURL_ALTSVC_HTTP") +#else + 0 +#endif + )) { + /* no connect_to match, try alt-svc! */ + enum alpnid srcalpnid; + bool hit; + struct altsvc *as; + const int allowed_versions = ( ALPN_h1 +#ifdef USE_HTTP2 + | ALPN_h2 +#endif +#ifdef ENABLE_QUIC + | ALPN_h3 +#endif + ) & data->asi->flags; + + host = conn->host.rawalloc; +#ifdef USE_HTTP2 + /* with h2 support, check that first */ + srcalpnid = ALPN_h2; + hit = Curl_altsvc_lookup(data->asi, + srcalpnid, host, conn->remote_port, /* from */ + &as /* to */, + allowed_versions); + if(!hit) +#endif + { + srcalpnid = ALPN_h1; + hit = Curl_altsvc_lookup(data->asi, + srcalpnid, host, conn->remote_port, /* from */ + &as /* to */, + allowed_versions); + } + if(hit) { + char *hostd = strdup((char *)as->dst.host); + if(!hostd) + return CURLE_OUT_OF_MEMORY; + conn->conn_to_host.rawalloc = hostd; + conn->conn_to_host.name = hostd; + conn->bits.conn_to_host = TRUE; + conn->conn_to_port = as->dst.port; + conn->bits.conn_to_port = TRUE; + conn->bits.altused = TRUE; + infof(data, "Alt-svc connecting from [%s]%s:%d to [%s]%s:%d", + Curl_alpnid2str(srcalpnid), host, conn->remote_port, + Curl_alpnid2str(as->dst.alpnid), hostd, as->dst.port); + if(srcalpnid != as->dst.alpnid) { + /* protocol version switch */ + switch(as->dst.alpnid) { + case ALPN_h1: + conn->httpversion = 11; + break; + case ALPN_h2: + conn->httpversion = 20; + break; + case ALPN_h3: + conn->transport = TRNSPRT_QUIC; + conn->httpversion = 30; + break; + default: /* shouldn't be possible */ + break; + } + } + } + } +#endif + + return result; +} + +#ifdef USE_UNIX_SOCKETS +static CURLcode resolve_unix(struct Curl_easy *data, + struct connectdata *conn, + char *unix_path) +{ + struct Curl_dns_entry *hostaddr = NULL; + bool longpath = FALSE; + + DEBUGASSERT(unix_path); + DEBUGASSERT(conn->dns_entry == NULL); + + /* Unix domain sockets are local. The host gets ignored, just use the + * specified domain socket address. Do not cache "DNS entries". There is + * no DNS involved and we already have the filesystem path available. */ + hostaddr = calloc(1, sizeof(struct Curl_dns_entry)); + if(!hostaddr) + return CURLE_OUT_OF_MEMORY; + + hostaddr->addr = Curl_unix2addr(unix_path, &longpath, + conn->bits.abstract_unix_socket); + if(!hostaddr->addr) { + if(longpath) + /* Long paths are not supported for now */ + failf(data, "Unix socket path too long: '%s'", unix_path); + free(hostaddr); + return longpath ? CURLE_COULDNT_RESOLVE_HOST : CURLE_OUT_OF_MEMORY; + } + + hostaddr->inuse++; + conn->dns_entry = hostaddr; + return CURLE_OK; +} +#endif + +#ifndef CURL_DISABLE_PROXY +static CURLcode resolve_proxy(struct Curl_easy *data, + struct connectdata *conn, + bool *async) +{ + struct Curl_dns_entry *hostaddr = NULL; + struct hostname *host; + timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); + int rc; + + DEBUGASSERT(conn->dns_entry == NULL); + + host = conn->bits.socksproxy ? &conn->socks_proxy.host : + &conn->http_proxy.host; + + conn->hostname_resolve = strdup(host->name); + if(!conn->hostname_resolve) + return CURLE_OUT_OF_MEMORY; + + rc = Curl_resolv_timeout(data, conn->hostname_resolve, (int)conn->port, + &hostaddr, timeout_ms); + conn->dns_entry = hostaddr; + if(rc == CURLRESOLV_PENDING) + *async = TRUE; + else if(rc == CURLRESOLV_TIMEDOUT) + return CURLE_OPERATION_TIMEDOUT; + else if(!hostaddr) { + failf(data, "Couldn't resolve proxy '%s'", host->dispname); + return CURLE_COULDNT_RESOLVE_PROXY; + } + + return CURLE_OK; +} +#endif + +static CURLcode resolve_host(struct Curl_easy *data, + struct connectdata *conn, + bool *async) +{ + struct Curl_dns_entry *hostaddr = NULL; + struct hostname *connhost; + timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); + int rc; + + DEBUGASSERT(conn->dns_entry == NULL); + + connhost = conn->bits.conn_to_host ? &conn->conn_to_host : &conn->host; + + /* If not connecting via a proxy, extract the port from the URL, if it is + * there, thus overriding any defaults that might have been set above. */ + conn->port = conn->bits.conn_to_port ? conn->conn_to_port : + conn->remote_port; + + /* Resolve target host right on */ + conn->hostname_resolve = strdup(connhost->name); + if(!conn->hostname_resolve) + return CURLE_OUT_OF_MEMORY; + + rc = Curl_resolv_timeout(data, conn->hostname_resolve, (int)conn->port, + &hostaddr, timeout_ms); + conn->dns_entry = hostaddr; + if(rc == CURLRESOLV_PENDING) + *async = TRUE; + else if(rc == CURLRESOLV_TIMEDOUT) { + failf(data, "Failed to resolve host '%s' with timeout after %" + CURL_FORMAT_TIMEDIFF_T " ms", connhost->dispname, + Curl_timediff(Curl_now(), data->progress.t_startsingle)); + return CURLE_OPERATION_TIMEDOUT; + } + else if(!hostaddr) { + failf(data, "Could not resolve host: %s", connhost->dispname); + return CURLE_COULDNT_RESOLVE_HOST; + } + + return CURLE_OK; +} + +/* Perform a fresh resolve */ +static CURLcode resolve_fresh(struct Curl_easy *data, + struct connectdata *conn, + bool *async) +{ +#ifdef USE_UNIX_SOCKETS + char *unix_path = conn->unix_domain_socket; + +#ifndef CURL_DISABLE_PROXY + if(!unix_path && conn->socks_proxy.host.name && + !strncmp(UNIX_SOCKET_PREFIX"/", + conn->socks_proxy.host.name, sizeof(UNIX_SOCKET_PREFIX))) + unix_path = conn->socks_proxy.host.name + sizeof(UNIX_SOCKET_PREFIX) - 1; +#endif + + if(unix_path) { + conn->transport = TRNSPRT_UNIX; + return resolve_unix(data, conn, unix_path); + } +#endif + +#ifndef CURL_DISABLE_PROXY + if(CONN_IS_PROXIED(conn)) + return resolve_proxy(data, conn, async); +#endif + + return resolve_host(data, conn, async); +} + +/************************************************************* + * Resolve the address of the server or proxy + *************************************************************/ +static CURLcode resolve_server(struct Curl_easy *data, + struct connectdata *conn, + bool *async) +{ + DEBUGASSERT(conn); + DEBUGASSERT(data); + + /* Resolve the name of the server or proxy */ + if(conn->bits.reuse) { + /* We're reusing the connection - no need to resolve anything, and + idnconvert_hostname() was called already in create_conn() for the reuse + case. */ + *async = FALSE; + return CURLE_OK; + } + + return resolve_fresh(data, conn, async); +} + +/* + * Cleanup the connection `temp`, just allocated for `data`, before using the + * previously `existing` one for `data`. All relevant info is copied over + * and `temp` is freed. + */ +static void reuse_conn(struct Curl_easy *data, + struct connectdata *temp, + struct connectdata *existing) +{ + /* get the user+password information from the temp struct since it may + * be new for this request even when we reuse an existing connection */ + if(temp->user) { + /* use the new user name and password though */ + Curl_safefree(existing->user); + Curl_safefree(existing->passwd); + existing->user = temp->user; + existing->passwd = temp->passwd; + temp->user = NULL; + temp->passwd = NULL; + } + +#ifndef CURL_DISABLE_PROXY + existing->bits.proxy_user_passwd = temp->bits.proxy_user_passwd; + if(existing->bits.proxy_user_passwd) { + /* use the new proxy user name and proxy password though */ + Curl_safefree(existing->http_proxy.user); + Curl_safefree(existing->socks_proxy.user); + Curl_safefree(existing->http_proxy.passwd); + Curl_safefree(existing->socks_proxy.passwd); + existing->http_proxy.user = temp->http_proxy.user; + existing->socks_proxy.user = temp->socks_proxy.user; + existing->http_proxy.passwd = temp->http_proxy.passwd; + existing->socks_proxy.passwd = temp->socks_proxy.passwd; + temp->http_proxy.user = NULL; + temp->socks_proxy.user = NULL; + temp->http_proxy.passwd = NULL; + temp->socks_proxy.passwd = NULL; + } +#endif + + /* Finding a connection for reuse in the cache matches, among other + * things on the "remote-relevant" hostname. This is not necessarily + * the authority of the URL, e.g. conn->host. For example: + * - we use a proxy (not tunneling). we want to send all requests + * that use the same proxy on this connection. + * - we have a "connect-to" setting that may redirect the hostname of + * a new request to the same remote endpoint of an existing conn. + * We want to reuse an existing conn to the remote endpoint. + * Since connection reuse does not match on conn->host necessarily, we + * switch `existing` conn to `temp` conn's host settings. + * TODO: is this correct in the case of TLS connections that have + * used the original hostname in SNI to negotiate? Do we send + * requests for another host through the different SNI? + */ + Curl_free_idnconverted_hostname(&existing->host); + Curl_free_idnconverted_hostname(&existing->conn_to_host); + Curl_safefree(existing->host.rawalloc); + Curl_safefree(existing->conn_to_host.rawalloc); + existing->host = temp->host; + temp->host.rawalloc = NULL; + temp->host.encalloc = NULL; + existing->conn_to_host = temp->conn_to_host; + temp->conn_to_host.rawalloc = NULL; + existing->conn_to_port = temp->conn_to_port; + existing->remote_port = temp->remote_port; + Curl_safefree(existing->hostname_resolve); + + existing->hostname_resolve = temp->hostname_resolve; + temp->hostname_resolve = NULL; + + /* reuse init */ + existing->bits.reuse = TRUE; /* yes, we're reusing here */ + + conn_free(data, temp); +} + +/** + * create_conn() sets up a new connectdata struct, or reuses an already + * existing one, and resolves host name. + * + * if this function returns CURLE_OK and *async is set to TRUE, the resolve + * response will be coming asynchronously. If *async is FALSE, the name is + * already resolved. + * + * @param data The sessionhandle pointer + * @param in_connect is set to the next connection data pointer + * @param async is set TRUE when an async DNS resolution is pending + * @see Curl_setup_conn() + * + */ + +static CURLcode create_conn(struct Curl_easy *data, + struct connectdata **in_connect, + bool *async) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn; + struct connectdata *existing = NULL; + bool reuse; + bool connections_available = TRUE; + bool force_reuse = FALSE; + bool waitpipe = FALSE; + size_t max_host_connections = Curl_multi_max_host_connections(data->multi); + size_t max_total_connections = Curl_multi_max_total_connections(data->multi); + + *async = FALSE; + *in_connect = NULL; + + /************************************************************* + * Check input data + *************************************************************/ + if(!data->state.url) { + result = CURLE_URL_MALFORMAT; + goto out; + } + + /* First, split up the current URL in parts so that we can use the + parts for checking against the already present connections. In order + to not have to modify everything at once, we allocate a temporary + connection data struct and fill in for comparison purposes. */ + conn = allocate_conn(data); + + if(!conn) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + + /* We must set the return variable as soon as possible, so that our + parent can cleanup any possible allocs we may have done before + any failure */ + *in_connect = conn; + + result = parseurlandfillconn(data, conn); + if(result) + goto out; + + if(data->set.str[STRING_SASL_AUTHZID]) { + conn->sasl_authzid = strdup(data->set.str[STRING_SASL_AUTHZID]); + if(!conn->sasl_authzid) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + } + + if(data->set.str[STRING_BEARER]) { + conn->oauth_bearer = strdup(data->set.str[STRING_BEARER]); + if(!conn->oauth_bearer) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + } + +#ifdef USE_UNIX_SOCKETS + if(data->set.str[STRING_UNIX_SOCKET_PATH]) { + conn->unix_domain_socket = strdup(data->set.str[STRING_UNIX_SOCKET_PATH]); + if(!conn->unix_domain_socket) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + conn->bits.abstract_unix_socket = data->set.abstract_unix_socket; + } +#endif + + /* After the unix socket init but before the proxy vars are used, parse and + initialize the proxy vars */ +#ifndef CURL_DISABLE_PROXY + result = create_conn_helper_init_proxy(data, conn); + if(result) + goto out; + + /************************************************************* + * If the protocol is using SSL and HTTP proxy is used, we set + * the tunnel_proxy bit. + *************************************************************/ + if((conn->given->flags&PROTOPT_SSL) && conn->bits.httpproxy) + conn->bits.tunnel_proxy = TRUE; +#endif + + /************************************************************* + * Figure out the remote port number and fix it in the URL + *************************************************************/ + result = parse_remote_port(data, conn); + if(result) + goto out; + + /* Check for overridden login details and set them accordingly so that + they are known when protocol->setup_connection is called! */ + result = override_login(data, conn); + if(result) + goto out; + + result = set_login(data, conn); /* default credentials */ + if(result) + goto out; + + /************************************************************* + * Process the "connect to" linked list of hostname/port mappings. + * Do this after the remote port number has been fixed in the URL. + *************************************************************/ + result = parse_connect_to_slist(data, conn, data->set.connect_to); + if(result) + goto out; + + /************************************************************* + * IDN-convert the proxy hostnames + *************************************************************/ +#ifndef CURL_DISABLE_PROXY + if(conn->bits.httpproxy) { + result = Curl_idnconvert_hostname(&conn->http_proxy.host); + if(result) + return result; + } + if(conn->bits.socksproxy) { + result = Curl_idnconvert_hostname(&conn->socks_proxy.host); + if(result) + return result; + } +#endif + if(conn->bits.conn_to_host) { + result = Curl_idnconvert_hostname(&conn->conn_to_host); + if(result) + return result; + } + + /************************************************************* + * Check whether the host and the "connect to host" are equal. + * Do this after the hostnames have been IDN-converted. + *************************************************************/ + if(conn->bits.conn_to_host && + strcasecompare(conn->conn_to_host.name, conn->host.name)) { + conn->bits.conn_to_host = FALSE; + } + + /************************************************************* + * Check whether the port and the "connect to port" are equal. + * Do this after the remote port number has been fixed in the URL. + *************************************************************/ + if(conn->bits.conn_to_port && conn->conn_to_port == conn->remote_port) { + conn->bits.conn_to_port = FALSE; + } + +#ifndef CURL_DISABLE_PROXY + /************************************************************* + * If the "connect to" feature is used with an HTTP proxy, + * we set the tunnel_proxy bit. + *************************************************************/ + if((conn->bits.conn_to_host || conn->bits.conn_to_port) && + conn->bits.httpproxy) + conn->bits.tunnel_proxy = TRUE; +#endif + + /************************************************************* + * Setup internals depending on protocol. Needs to be done after + * we figured out what/if proxy to use. + *************************************************************/ + result = setup_connection_internals(data, conn); + if(result) + goto out; + + /*********************************************************************** + * file: is a special case in that it doesn't need a network connection + ***********************************************************************/ +#ifndef CURL_DISABLE_FILE + if(conn->handler->flags & PROTOPT_NONETWORK) { + bool done; + /* this is supposed to be the connect function so we better at least check + that the file is present here! */ + DEBUGASSERT(conn->handler->connect_it); + Curl_persistconninfo(data, conn, NULL, -1); + result = conn->handler->connect_it(data, &done); + + /* Setup a "faked" transfer that'll do nothing */ + if(!result) { + Curl_attach_connection(data, conn); + result = Curl_conncache_add_conn(data); + if(result) + goto out; + + /* + * Setup whatever necessary for a resumed transfer + */ + result = setup_range(data); + if(result) { + DEBUGASSERT(conn->handler->done); + /* we ignore the return code for the protocol-specific DONE */ + (void)conn->handler->done(data, result, FALSE); + goto out; + } + Curl_setup_transfer(data, -1, -1, FALSE, -1); + } + + /* since we skip do_init() */ + Curl_init_do(data, conn); + + goto out; + } +#endif + + /* Setup filter for network connections */ + conn->recv[FIRSTSOCKET] = Curl_conn_recv; + conn->send[FIRSTSOCKET] = Curl_conn_send; + conn->recv[SECONDARYSOCKET] = Curl_conn_recv; + conn->send[SECONDARYSOCKET] = Curl_conn_send; + conn->bits.tcp_fastopen = data->set.tcp_fastopen; + + /* Complete the easy's SSL configuration for connection cache matching */ + result = Curl_ssl_easy_config_complete(data); + if(result) + goto out; + + prune_dead_connections(data); + + /************************************************************* + * Check the current list of connections to see if we can + * reuse an already existing one or if we have to create a + * new one. + *************************************************************/ + + DEBUGASSERT(conn->user); + DEBUGASSERT(conn->passwd); + + /* reuse_fresh is TRUE if we are told to use a new connection by force, but + we only acknowledge this option if this is not a reused connection + already (which happens due to follow-location or during an HTTP + authentication phase). CONNECT_ONLY transfers also refuse reuse. */ + if((data->set.reuse_fresh && !data->state.followlocation) || + data->set.connect_only) + reuse = FALSE; + else + reuse = ConnectionExists(data, conn, &existing, &force_reuse, &waitpipe); + + if(reuse) { + /* + * We already have a connection for this, we got the former connection in + * `existing` and thus we need to cleanup the one we just + * allocated before we can move along and use `existing`. + */ + reuse_conn(data, conn, existing); + conn = existing; + *in_connect = conn; + +#ifndef CURL_DISABLE_PROXY + infof(data, "Re-using existing connection with %s %s", + conn->bits.proxy?"proxy":"host", + conn->socks_proxy.host.name ? conn->socks_proxy.host.dispname : + conn->http_proxy.host.name ? conn->http_proxy.host.dispname : + conn->host.dispname); +#else + infof(data, "Re-using existing connection with host %s", + conn->host.dispname); +#endif + } + else { + /* We have decided that we want a new connection. However, we may not + be able to do that if we have reached the limit of how many + connections we are allowed to open. */ + + if(conn->handler->flags & PROTOPT_ALPN) { + /* The protocol wants it, so set the bits if enabled in the easy handle + (default) */ + if(data->set.ssl_enable_alpn) + conn->bits.tls_enable_alpn = TRUE; + } + + if(waitpipe) + /* There is a connection that *might* become usable for multiplexing + "soon", and we wait for that */ + connections_available = FALSE; + else { + /* this gets a lock on the conncache */ + struct connectbundle *bundle = + Curl_conncache_find_bundle(data, conn, data->state.conn_cache); + + if(max_host_connections > 0 && bundle && + (bundle->num_connections >= max_host_connections)) { + struct connectdata *conn_candidate; + + /* The bundle is full. Extract the oldest connection. */ + conn_candidate = Curl_conncache_extract_bundle(data, bundle); + CONNCACHE_UNLOCK(data); + + if(conn_candidate) + Curl_disconnect(data, conn_candidate, FALSE); + else { + infof(data, "No more connections allowed to host: %zu", + max_host_connections); + connections_available = FALSE; + } + } + else + CONNCACHE_UNLOCK(data); + + } + + if(connections_available && + (max_total_connections > 0) && + (Curl_conncache_size(data) >= max_total_connections)) { + struct connectdata *conn_candidate; + + /* The cache is full. Let's see if we can kill a connection. */ + conn_candidate = Curl_conncache_extract_oldest(data); + if(conn_candidate) + Curl_disconnect(data, conn_candidate, FALSE); + else { + infof(data, "No connections available in cache"); + connections_available = FALSE; + } + } + + if(!connections_available) { + infof(data, "No connections available."); + + conn_free(data, conn); + *in_connect = NULL; + + result = CURLE_NO_CONNECTION_AVAILABLE; + goto out; + } + else { + /* + * This is a brand new connection, so let's store it in the connection + * cache of ours! + */ + result = Curl_ssl_conn_config_init(data, conn); + if(result) { + DEBUGF(fprintf(stderr, "Error: init connection ssl config\n")); + goto out; + } + + Curl_attach_connection(data, conn); + result = Curl_conncache_add_conn(data); + if(result) + goto out; + } + +#if defined(USE_NTLM) + /* If NTLM is requested in a part of this connection, make sure we don't + assume the state is fine as this is a fresh connection and NTLM is + connection based. */ + if((data->state.authhost.picked & (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) && + data->state.authhost.done) { + infof(data, "NTLM picked AND auth done set, clear picked"); + data->state.authhost.picked = CURLAUTH_NONE; + data->state.authhost.done = FALSE; + } + + if((data->state.authproxy.picked & (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) && + data->state.authproxy.done) { + infof(data, "NTLM-proxy picked AND auth done set, clear picked"); + data->state.authproxy.picked = CURLAUTH_NONE; + data->state.authproxy.done = FALSE; + } +#endif + } + + /* Setup and init stuff before DO starts, in preparing for the transfer. */ + Curl_init_do(data, conn); + + /* + * Setup whatever necessary for a resumed transfer + */ + result = setup_range(data); + if(result) + goto out; + + /* Continue connectdata initialization here. */ + + /* + * Inherit the proper values from the urldata struct AFTER we have arranged + * the persistent connection stuff + */ + conn->seek_func = data->set.seek_func; + conn->seek_client = data->set.seek_client; + + /************************************************************* + * Resolve the address of the server or proxy + *************************************************************/ + result = resolve_server(data, conn, async); + if(result) + goto out; + + /* Everything general done, inform filters that they need + * to prepare for a data transfer. + */ + result = Curl_conn_ev_data_setup(data); + +out: + return result; +} + +/* Curl_setup_conn() is called after the name resolve initiated in + * create_conn() is all done. + * + * Curl_setup_conn() also handles reused connections + */ +CURLcode Curl_setup_conn(struct Curl_easy *data, + bool *protocol_done) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + + Curl_pgrsTime(data, TIMER_NAMELOOKUP); + + if(conn->handler->flags & PROTOPT_NONETWORK) { + /* nothing to setup when not using a network */ + *protocol_done = TRUE; + return result; + } + +#ifndef CURL_DISABLE_PROXY + /* set proxy_connect_closed to false unconditionally already here since it + is used strictly to provide extra information to a parent function in the + case of proxy CONNECT failures and we must make sure we don't have it + lingering set from a previous invoke */ + conn->bits.proxy_connect_closed = FALSE; +#endif + +#ifdef CURL_DO_LINEEND_CONV + data->state.crlf_conversions = 0; /* reset CRLF conversion counter */ +#endif /* CURL_DO_LINEEND_CONV */ + + /* set start time here for timeout purposes in the connect procedure, it + is later set again for the progress meter purpose */ + conn->now = Curl_now(); + if(!conn->bits.reuse) + result = Curl_conn_setup(data, conn, FIRSTSOCKET, conn->dns_entry, + CURL_CF_SSL_DEFAULT); + /* not sure we need this flag to be passed around any more */ + *protocol_done = FALSE; + return result; +} + +CURLcode Curl_connect(struct Curl_easy *data, + bool *asyncp, + bool *protocol_done) +{ + CURLcode result; + struct connectdata *conn; + + *asyncp = FALSE; /* assume synchronous resolves by default */ + + /* init the single-transfer specific data */ + Curl_free_request_state(data); + memset(&data->req, 0, sizeof(struct SingleRequest)); + data->req.size = data->req.maxdownload = -1; + data->req.no_body = data->set.opt_no_body; + + /* call the stuff that needs to be called */ + result = create_conn(data, &conn, asyncp); + + if(!result) { + if(CONN_INUSE(conn) > 1) + /* multiplexed */ + *protocol_done = TRUE; + else if(!*asyncp) { + /* DNS resolution is done: that's either because this is a reused + connection, in which case DNS was unnecessary, or because DNS + really did finish already (synch resolver/fast async resolve) */ + result = Curl_setup_conn(data, protocol_done); + } + } + + if(result == CURLE_NO_CONNECTION_AVAILABLE) { + return result; + } + else if(result && conn) { + /* We're not allowed to return failure with memory left allocated in the + connectdata struct, free those here */ + Curl_detach_connection(data); + Curl_conncache_remove_conn(data, conn, TRUE); + Curl_disconnect(data, conn, TRUE); + } + + return result; +} + +/* + * Curl_init_do() inits the readwrite session. This is inited each time (in + * the DO function before the protocol-specific DO functions are invoked) for + * a transfer, sometimes multiple times on the same Curl_easy. Make sure + * nothing in here depends on stuff that are setup dynamically for the + * transfer. + * + * Allow this function to get called with 'conn' set to NULL. + */ + +CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn) +{ + struct SingleRequest *k = &data->req; + + /* if this is a pushed stream, we need this: */ + CURLcode result = Curl_preconnect(data); + if(result) + return result; + + if(conn) { + conn->bits.do_more = FALSE; /* by default there's no curl_do_more() to + use */ + /* if the protocol used doesn't support wildcards, switch it off */ + if(data->state.wildcardmatch && + !(conn->handler->flags & PROTOPT_WILDCARD)) + data->state.wildcardmatch = FALSE; + } + + data->state.done = FALSE; /* *_done() is not called yet */ + data->state.expect100header = FALSE; + + if(data->req.no_body) + /* in HTTP lingo, no body means using the HEAD request... */ + data->state.httpreq = HTTPREQ_HEAD; + + k->start = Curl_now(); /* start time */ + k->header = TRUE; /* assume header */ + k->bytecount = 0; + k->ignorebody = FALSE; + + Curl_client_cleanup(data); + Curl_speedinit(data); + Curl_pgrsSetUploadCounter(data, 0); + Curl_pgrsSetDownloadCounter(data, 0); + + return CURLE_OK; +} + +#if defined(USE_HTTP2) || defined(USE_HTTP3) + +#ifdef USE_NGHTTP2 + +static void priority_remove_child(struct Curl_easy *parent, + struct Curl_easy *child) +{ + struct Curl_data_prio_node **pnext = &parent->set.priority.children; + struct Curl_data_prio_node *pnode = parent->set.priority.children; + + DEBUGASSERT(child->set.priority.parent == parent); + while(pnode && pnode->data != child) { + pnext = &pnode->next; + pnode = pnode->next; + } + + DEBUGASSERT(pnode); + if(pnode) { + *pnext = pnode->next; + free(pnode); + } + + child->set.priority.parent = 0; + child->set.priority.exclusive = FALSE; +} + +CURLcode Curl_data_priority_add_child(struct Curl_easy *parent, + struct Curl_easy *child, + bool exclusive) +{ + if(child->set.priority.parent) { + priority_remove_child(child->set.priority.parent, child); + } + + if(parent) { + struct Curl_data_prio_node **tail; + struct Curl_data_prio_node *pnode; + + pnode = calloc(1, sizeof(*pnode)); + if(!pnode) + return CURLE_OUT_OF_MEMORY; + pnode->data = child; + + if(parent->set.priority.children && exclusive) { + /* exclusive: move all existing children underneath the new child */ + struct Curl_data_prio_node *node = parent->set.priority.children; + while(node) { + node->data->set.priority.parent = child; + node = node->next; + } + + tail = &child->set.priority.children; + while(*tail) + tail = &(*tail)->next; + + DEBUGASSERT(!*tail); + *tail = parent->set.priority.children; + parent->set.priority.children = 0; + } + + tail = &parent->set.priority.children; + while(*tail) { + (*tail)->data->set.priority.exclusive = FALSE; + tail = &(*tail)->next; + } + + DEBUGASSERT(!*tail); + *tail = pnode; + } + + child->set.priority.parent = parent; + child->set.priority.exclusive = exclusive; + return CURLE_OK; +} + +#endif /* USE_NGHTTP2 */ + +#ifdef USE_NGHTTP2 +static void data_priority_cleanup(struct Curl_easy *data) +{ + while(data->set.priority.children) { + struct Curl_easy *tmp = data->set.priority.children->data; + priority_remove_child(data, tmp); + if(data->set.priority.parent) + Curl_data_priority_add_child(data->set.priority.parent, tmp, FALSE); + } + + if(data->set.priority.parent) + -- Gitee From ba7f316df404fccbd44ceb0b7748b3f05f27668c Mon Sep 17 00:00:00 2001 From: cy Date: Mon, 30 Dec 2024 09:28:21 +0000 Subject: [PATCH 12/13] update lib/url.c. Signed-off-by: cy --- lib/url.c | 52 ++++++++++++++++++++-------------------------------- 1 file changed, 20 insertions(+), 32 deletions(-) diff --git a/lib/url.c b/lib/url.c index 9bc5dd229..48fa6074b 100644 --- a/lib/url.c +++ b/lib/url.c @@ -11,8 +11,7 @@ * you should have received as part of this distribution. The terms * are also available at https://curl.se/docs/copyright.html. * - * You may opt to use, copy, modify, merge - * , publish, distribute and/or sell + * 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 * furnished to do so, under the terms of the COPYING file. * @@ -2763,40 +2762,29 @@ static CURLcode override_login(struct Curl_easy *data, bool url_provided = FALSE; if(data->state.aptr.user) { - /* there was a username with a length in the URL. Use the URL decoded - version */ + /* there was a user name in the URL. Use the URL decoded version */ userp = &data->state.aptr.user; url_provided = TRUE; } - if(!*passwdp) { - ret = Curl_parsenetrc(conn->host.name, - userp, passwdp, - data->set.str[STRING_NETRC_FILE]); - if(ret > 0) { - infof(data, "Couldn't find host %s in the %s file; using defaults", - conn->host.name, - (data->set.str[STRING_NETRC_FILE] ? - data->set.str[STRING_NETRC_FILE] : ".netrc")); - } - else if(ret < 0) { - failf(data, ".netrc parser error"); - return CURLE_READ_ERROR; - } - else { - if(!(conn->handler->flags&PROTOPT_USERPWDCTRL)) { - /* if the protocol can't handle control codes in credentials, make - sure there are none */ - if(str_has_ctrl(*userp) || str_has_ctrl(*passwdp)) { - failf(data, "control code detected in .netrc credentials"); - return CURLE_READ_ERROR; - } - } - /* set bits.netrc TRUE to remember that we got the name from a .netrc - file, so that it is safe to use even if we followed a Location: to a - different host or similar. */ - conn->bits.netrc = TRUE; - } + ret = Curl_parsenetrc(conn->host.name, + userp, passwdp, + data->set.str[STRING_NETRC_FILE]); + if(ret > 0) { + infof(data, "Couldn't find host %s in the %s file; using defaults", + conn->host.name, + (data->set.str[STRING_NETRC_FILE] ? + data->set.str[STRING_NETRC_FILE] : ".netrc")); + } + else if(ret < 0) { + failf(data, ".netrc parser error"); + return CURLE_READ_ERROR; + } + else { + /* set bits.netrc TRUE to remember that we got the name from a .netrc + file, so that it is safe to use even if we followed a Location: to a + different host or similar. */ + conn->bits.netrc = TRUE; } if(url_provided) { Curl_safefree(conn->user); -- Gitee From a72bc00ffb22dfb6ee151c193d0dd457ddf354e4 Mon Sep 17 00:00:00 2001 From: cy Date: Mon, 30 Dec 2024 09:29:09 +0000 Subject: [PATCH 13/13] update bundle.json. Signed-off-by: cy --- bundle.json | 1334 --------------------------------------------------- 1 file changed, 1334 deletions(-) diff --git a/bundle.json b/bundle.json index 92d397e0f..5f0fd2f4d 100644 --- a/bundle.json +++ b/bundle.json @@ -58,1337 +58,3 @@ } } } - -third_party/curl/lib/url.c -static CURLcode parse_remote_port(struct Curl_easy *data, - struct connectdata *conn) -{ - - if(data->set.use_port && data->state.allow_port) { - /* if set, we use this instead of the port possibly given in the URL */ - char portbuf[16]; - CURLUcode uc; - conn->remote_port = data->set.use_port; - msnprintf(portbuf, sizeof(portbuf), "%d", conn->remote_port); - uc = curl_url_set(data->state.uh, CURLUPART_PORT, portbuf, 0); - if(uc) - return CURLE_OUT_OF_MEMORY; - } - - return CURLE_OK; -} - -/* - * Override the login details from the URL with that in the CURLOPT_USERPWD - * option or a .netrc file, if applicable. - */ -static CURLcode override_login(struct Curl_easy *data, - struct connectdata *conn) -{ - CURLUcode uc; - char **userp = &conn->user; - char **passwdp = &conn->passwd; - char **optionsp = &conn->options; - - if(data->set.str[STRING_OPTIONS]) { - free(*optionsp); - *optionsp = strdup(data->set.str[STRING_OPTIONS]); - if(!*optionsp) - return CURLE_OUT_OF_MEMORY; - } - -#ifndef CURL_DISABLE_NETRC - if(data->set.use_netrc == CURL_NETRC_REQUIRED) { - Curl_safefree(*userp); - Curl_safefree(*passwdp); - } - conn->bits.netrc = FALSE; - if(data->set.use_netrc && !data->set.str[STRING_USERNAME]) { - int ret; - bool url_provided = FALSE; - - if(data->state.aptr.user) { - /* there was a user name in the URL. Use the URL decoded version */ - userp = &data->state.aptr.user; - url_provided = TRUE; - } - - ret = Curl_parsenetrc(conn->host.name, - userp, passwdp, - data->set.str[STRING_NETRC_FILE]); - if(ret > 0) { - infof(data, "Couldn't find host %s in the %s file; using defaults", - conn->host.name, - (data->set.str[STRING_NETRC_FILE] ? - data->set.str[STRING_NETRC_FILE] : ".netrc")); - } - else if(ret < 0) { - failf(data, ".netrc parser error"); - return CURLE_READ_ERROR; - } - else { - /* set bits.netrc TRUE to remember that we got the name from a .netrc - file, so that it is safe to use even if we followed a Location: to a - different host or similar. */ - conn->bits.netrc = TRUE; - } - if(url_provided) { - Curl_safefree(conn->user); - conn->user = strdup(*userp); - if(!conn->user) - return CURLE_OUT_OF_MEMORY; - } - /* no user was set but a password, set a blank user */ - if(!*userp && *passwdp) { - *userp = strdup(""); - if(!*userp) - return CURLE_OUT_OF_MEMORY; - } - } -#endif - - /* for updated strings, we update them in the URL */ - if(*userp) { - CURLcode result; - if(data->state.aptr.user != *userp) { - /* nothing to do then */ - result = Curl_setstropt(&data->state.aptr.user, *userp); - if(result) - return result; - } - } - if(data->state.aptr.user) { - uc = curl_url_set(data->state.uh, CURLUPART_USER, data->state.aptr.user, - CURLU_URLENCODE); - if(uc) - return Curl_uc_to_curlcode(uc); - if(!*userp) { - *userp = strdup(data->state.aptr.user); - if(!*userp) - return CURLE_OUT_OF_MEMORY; - } - } - if(*passwdp) { - CURLcode result = Curl_setstropt(&data->state.aptr.passwd, *passwdp); - if(result) - return result; - } - if(data->state.aptr.passwd) { - uc = curl_url_set(data->state.uh, CURLUPART_PASSWORD, - data->state.aptr.passwd, CURLU_URLENCODE); - if(uc) - return Curl_uc_to_curlcode(uc); - if(!*passwdp) { - *passwdp = strdup(data->state.aptr.passwd); - if(!*passwdp) - return CURLE_OUT_OF_MEMORY; - } - } - - return CURLE_OK; -} - -/* - * Set the login details so they're available in the connection - */ -static CURLcode set_login(struct Curl_easy *data, - struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - const char *setuser = CURL_DEFAULT_USER; - const char *setpasswd = CURL_DEFAULT_PASSWORD; - - /* If our protocol needs a password and we have none, use the defaults */ - if((conn->handler->flags & PROTOPT_NEEDSPWD) && !data->state.aptr.user) - ; - else { - setuser = ""; - setpasswd = ""; - } - /* Store the default user */ - if(!conn->user) { - conn->user = strdup(setuser); - if(!conn->user) - return CURLE_OUT_OF_MEMORY; - } - - /* Store the default password */ - if(!conn->passwd) { - conn->passwd = strdup(setpasswd); - if(!conn->passwd) - result = CURLE_OUT_OF_MEMORY; - } - - return result; -} - -/* - * Parses a "host:port" string to connect to. - * The hostname and the port may be empty; in this case, NULL is returned for - * the hostname and -1 for the port. - */ -static CURLcode parse_connect_to_host_port(struct Curl_easy *data, - const char *host, - char **hostname_result, - int *port_result) -{ - char *host_dup; - char *hostptr; - char *host_portno; - char *portptr; - int port = -1; - CURLcode result = CURLE_OK; - -#if defined(CURL_DISABLE_VERBOSE_STRINGS) - (void) data; -#endif - - *hostname_result = NULL; - *port_result = -1; - - if(!host || !*host) - return CURLE_OK; - - host_dup = strdup(host); - if(!host_dup) - return CURLE_OUT_OF_MEMORY; - - hostptr = host_dup; - - /* start scanning for port number at this point */ - portptr = hostptr; - - /* detect and extract RFC6874-style IPv6-addresses */ - if(*hostptr == '[') { -#ifdef ENABLE_IPV6 - char *ptr = ++hostptr; /* advance beyond the initial bracket */ - while(*ptr && (ISXDIGIT(*ptr) || (*ptr == ':') || (*ptr == '.'))) - ptr++; - if(*ptr == '%') { - /* There might be a zone identifier */ - if(strncmp("%25", ptr, 3)) - infof(data, "Please URL encode %% as %%25, see RFC 6874."); - ptr++; - /* Allow unreserved characters as defined in RFC 3986 */ - while(*ptr && (ISALPHA(*ptr) || ISXDIGIT(*ptr) || (*ptr == '-') || - (*ptr == '.') || (*ptr == '_') || (*ptr == '~'))) - ptr++; - } - if(*ptr == ']') - /* yeps, it ended nicely with a bracket as well */ - *ptr++ = '\0'; - else - infof(data, "Invalid IPv6 address format"); - portptr = ptr; - /* Note that if this didn't end with a bracket, we still advanced the - * hostptr first, but I can't see anything wrong with that as no host - * name nor a numeric can legally start with a bracket. - */ -#else - failf(data, "Use of IPv6 in *_CONNECT_TO without IPv6 support built-in"); - result = CURLE_NOT_BUILT_IN; - goto error; -#endif - } - - /* Get port number off server.com:1080 */ - host_portno = strchr(portptr, ':'); - if(host_portno) { - char *endp = NULL; - *host_portno = '\0'; /* cut off number from host name */ - host_portno++; - if(*host_portno) { - long portparse = strtol(host_portno, &endp, 10); - if((endp && *endp) || (portparse < 0) || (portparse > 65535)) { - failf(data, "No valid port number in connect to host string (%s)", - host_portno); - result = CURLE_SETOPT_OPTION_SYNTAX; - goto error; - } - else - port = (int)portparse; /* we know it will fit */ - } - } - - /* now, clone the cleaned host name */ - DEBUGASSERT(hostptr); - *hostname_result = strdup(hostptr); - if(!*hostname_result) { - result = CURLE_OUT_OF_MEMORY; - goto error; - } - - *port_result = port; - -error: - free(host_dup); - return result; -} - -/* - * Parses one "connect to" string in the form: - * "HOST:PORT:CONNECT-TO-HOST:CONNECT-TO-PORT". - */ -static CURLcode parse_connect_to_string(struct Curl_easy *data, - struct connectdata *conn, - const char *conn_to_host, - char **host_result, - int *port_result) -{ - CURLcode result = CURLE_OK; - const char *ptr = conn_to_host; - int host_match = FALSE; - int port_match = FALSE; - - *host_result = NULL; - *port_result = -1; - - if(*ptr == ':') { - /* an empty hostname always matches */ - host_match = TRUE; - ptr++; - } - else { - /* check whether the URL's hostname matches */ - size_t hostname_to_match_len; - char *hostname_to_match = aprintf("%s%s%s", - conn->bits.ipv6_ip ? "[" : "", - conn->host.name, - conn->bits.ipv6_ip ? "]" : ""); - if(!hostname_to_match) - return CURLE_OUT_OF_MEMORY; - hostname_to_match_len = strlen(hostname_to_match); - host_match = strncasecompare(ptr, hostname_to_match, - hostname_to_match_len); - free(hostname_to_match); - ptr += hostname_to_match_len; - - host_match = host_match && *ptr == ':'; - ptr++; - } - - if(host_match) { - if(*ptr == ':') { - /* an empty port always matches */ - port_match = TRUE; - ptr++; - } - else { - /* check whether the URL's port matches */ - char *ptr_next = strchr(ptr, ':'); - if(ptr_next) { - char *endp = NULL; - long port_to_match = strtol(ptr, &endp, 10); - if((endp == ptr_next) && (port_to_match == conn->remote_port)) { - port_match = TRUE; - ptr = ptr_next + 1; - } - } - } - } - - if(host_match && port_match) { - /* parse the hostname and port to connect to */ - result = parse_connect_to_host_port(data, ptr, host_result, port_result); - } - - return result; -} - -/* - * Processes all strings in the "connect to" slist, and uses the "connect - * to host" and "connect to port" of the first string that matches. - */ -static CURLcode parse_connect_to_slist(struct Curl_easy *data, - struct connectdata *conn, - struct curl_slist *conn_to_host) -{ - CURLcode result = CURLE_OK; - char *host = NULL; - int port = -1; - - while(conn_to_host && !host && port == -1) { - result = parse_connect_to_string(data, conn, conn_to_host->data, - &host, &port); - if(result) - return result; - - if(host && *host) { - conn->conn_to_host.rawalloc = host; - conn->conn_to_host.name = host; - conn->bits.conn_to_host = TRUE; - - infof(data, "Connecting to hostname: %s", host); - } - else { - /* no "connect to host" */ - conn->bits.conn_to_host = FALSE; - Curl_safefree(host); - } - - if(port >= 0) { - conn->conn_to_port = port; - conn->bits.conn_to_port = TRUE; - infof(data, "Connecting to port: %d", port); - } - else { - /* no "connect to port" */ - conn->bits.conn_to_port = FALSE; - port = -1; - } - - conn_to_host = conn_to_host->next; - } - -#ifndef CURL_DISABLE_ALTSVC - if(data->asi && !host && (port == -1) && - ((conn->handler->protocol == CURLPROTO_HTTPS) || -#ifdef CURLDEBUG - /* allow debug builds to circumvent the HTTPS restriction */ - getenv("CURL_ALTSVC_HTTP") -#else - 0 -#endif - )) { - /* no connect_to match, try alt-svc! */ - enum alpnid srcalpnid; - bool hit; - struct altsvc *as; - const int allowed_versions = ( ALPN_h1 -#ifdef USE_HTTP2 - | ALPN_h2 -#endif -#ifdef ENABLE_QUIC - | ALPN_h3 -#endif - ) & data->asi->flags; - - host = conn->host.rawalloc; -#ifdef USE_HTTP2 - /* with h2 support, check that first */ - srcalpnid = ALPN_h2; - hit = Curl_altsvc_lookup(data->asi, - srcalpnid, host, conn->remote_port, /* from */ - &as /* to */, - allowed_versions); - if(!hit) -#endif - { - srcalpnid = ALPN_h1; - hit = Curl_altsvc_lookup(data->asi, - srcalpnid, host, conn->remote_port, /* from */ - &as /* to */, - allowed_versions); - } - if(hit) { - char *hostd = strdup((char *)as->dst.host); - if(!hostd) - return CURLE_OUT_OF_MEMORY; - conn->conn_to_host.rawalloc = hostd; - conn->conn_to_host.name = hostd; - conn->bits.conn_to_host = TRUE; - conn->conn_to_port = as->dst.port; - conn->bits.conn_to_port = TRUE; - conn->bits.altused = TRUE; - infof(data, "Alt-svc connecting from [%s]%s:%d to [%s]%s:%d", - Curl_alpnid2str(srcalpnid), host, conn->remote_port, - Curl_alpnid2str(as->dst.alpnid), hostd, as->dst.port); - if(srcalpnid != as->dst.alpnid) { - /* protocol version switch */ - switch(as->dst.alpnid) { - case ALPN_h1: - conn->httpversion = 11; - break; - case ALPN_h2: - conn->httpversion = 20; - break; - case ALPN_h3: - conn->transport = TRNSPRT_QUIC; - conn->httpversion = 30; - break; - default: /* shouldn't be possible */ - break; - } - } - } - } -#endif - - return result; -} - -#ifdef USE_UNIX_SOCKETS -static CURLcode resolve_unix(struct Curl_easy *data, - struct connectdata *conn, - char *unix_path) -{ - struct Curl_dns_entry *hostaddr = NULL; - bool longpath = FALSE; - - DEBUGASSERT(unix_path); - DEBUGASSERT(conn->dns_entry == NULL); - - /* Unix domain sockets are local. The host gets ignored, just use the - * specified domain socket address. Do not cache "DNS entries". There is - * no DNS involved and we already have the filesystem path available. */ - hostaddr = calloc(1, sizeof(struct Curl_dns_entry)); - if(!hostaddr) - return CURLE_OUT_OF_MEMORY; - - hostaddr->addr = Curl_unix2addr(unix_path, &longpath, - conn->bits.abstract_unix_socket); - if(!hostaddr->addr) { - if(longpath) - /* Long paths are not supported for now */ - failf(data, "Unix socket path too long: '%s'", unix_path); - free(hostaddr); - return longpath ? CURLE_COULDNT_RESOLVE_HOST : CURLE_OUT_OF_MEMORY; - } - - hostaddr->inuse++; - conn->dns_entry = hostaddr; - return CURLE_OK; -} -#endif - -#ifndef CURL_DISABLE_PROXY -static CURLcode resolve_proxy(struct Curl_easy *data, - struct connectdata *conn, - bool *async) -{ - struct Curl_dns_entry *hostaddr = NULL; - struct hostname *host; - timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); - int rc; - - DEBUGASSERT(conn->dns_entry == NULL); - - host = conn->bits.socksproxy ? &conn->socks_proxy.host : - &conn->http_proxy.host; - - conn->hostname_resolve = strdup(host->name); - if(!conn->hostname_resolve) - return CURLE_OUT_OF_MEMORY; - - rc = Curl_resolv_timeout(data, conn->hostname_resolve, (int)conn->port, - &hostaddr, timeout_ms); - conn->dns_entry = hostaddr; - if(rc == CURLRESOLV_PENDING) - *async = TRUE; - else if(rc == CURLRESOLV_TIMEDOUT) - return CURLE_OPERATION_TIMEDOUT; - else if(!hostaddr) { - failf(data, "Couldn't resolve proxy '%s'", host->dispname); - return CURLE_COULDNT_RESOLVE_PROXY; - } - - return CURLE_OK; -} -#endif - -static CURLcode resolve_host(struct Curl_easy *data, - struct connectdata *conn, - bool *async) -{ - struct Curl_dns_entry *hostaddr = NULL; - struct hostname *connhost; - timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); - int rc; - - DEBUGASSERT(conn->dns_entry == NULL); - - connhost = conn->bits.conn_to_host ? &conn->conn_to_host : &conn->host; - - /* If not connecting via a proxy, extract the port from the URL, if it is - * there, thus overriding any defaults that might have been set above. */ - conn->port = conn->bits.conn_to_port ? conn->conn_to_port : - conn->remote_port; - - /* Resolve target host right on */ - conn->hostname_resolve = strdup(connhost->name); - if(!conn->hostname_resolve) - return CURLE_OUT_OF_MEMORY; - - rc = Curl_resolv_timeout(data, conn->hostname_resolve, (int)conn->port, - &hostaddr, timeout_ms); - conn->dns_entry = hostaddr; - if(rc == CURLRESOLV_PENDING) - *async = TRUE; - else if(rc == CURLRESOLV_TIMEDOUT) { - failf(data, "Failed to resolve host '%s' with timeout after %" - CURL_FORMAT_TIMEDIFF_T " ms", connhost->dispname, - Curl_timediff(Curl_now(), data->progress.t_startsingle)); - return CURLE_OPERATION_TIMEDOUT; - } - else if(!hostaddr) { - failf(data, "Could not resolve host: %s", connhost->dispname); - return CURLE_COULDNT_RESOLVE_HOST; - } - - return CURLE_OK; -} - -/* Perform a fresh resolve */ -static CURLcode resolve_fresh(struct Curl_easy *data, - struct connectdata *conn, - bool *async) -{ -#ifdef USE_UNIX_SOCKETS - char *unix_path = conn->unix_domain_socket; - -#ifndef CURL_DISABLE_PROXY - if(!unix_path && conn->socks_proxy.host.name && - !strncmp(UNIX_SOCKET_PREFIX"/", - conn->socks_proxy.host.name, sizeof(UNIX_SOCKET_PREFIX))) - unix_path = conn->socks_proxy.host.name + sizeof(UNIX_SOCKET_PREFIX) - 1; -#endif - - if(unix_path) { - conn->transport = TRNSPRT_UNIX; - return resolve_unix(data, conn, unix_path); - } -#endif - -#ifndef CURL_DISABLE_PROXY - if(CONN_IS_PROXIED(conn)) - return resolve_proxy(data, conn, async); -#endif - - return resolve_host(data, conn, async); -} - -/************************************************************* - * Resolve the address of the server or proxy - *************************************************************/ -static CURLcode resolve_server(struct Curl_easy *data, - struct connectdata *conn, - bool *async) -{ - DEBUGASSERT(conn); - DEBUGASSERT(data); - - /* Resolve the name of the server or proxy */ - if(conn->bits.reuse) { - /* We're reusing the connection - no need to resolve anything, and - idnconvert_hostname() was called already in create_conn() for the reuse - case. */ - *async = FALSE; - return CURLE_OK; - } - - return resolve_fresh(data, conn, async); -} - -/* - * Cleanup the connection `temp`, just allocated for `data`, before using the - * previously `existing` one for `data`. All relevant info is copied over - * and `temp` is freed. - */ -static void reuse_conn(struct Curl_easy *data, - struct connectdata *temp, - struct connectdata *existing) -{ - /* get the user+password information from the temp struct since it may - * be new for this request even when we reuse an existing connection */ - if(temp->user) { - /* use the new user name and password though */ - Curl_safefree(existing->user); - Curl_safefree(existing->passwd); - existing->user = temp->user; - existing->passwd = temp->passwd; - temp->user = NULL; - temp->passwd = NULL; - } - -#ifndef CURL_DISABLE_PROXY - existing->bits.proxy_user_passwd = temp->bits.proxy_user_passwd; - if(existing->bits.proxy_user_passwd) { - /* use the new proxy user name and proxy password though */ - Curl_safefree(existing->http_proxy.user); - Curl_safefree(existing->socks_proxy.user); - Curl_safefree(existing->http_proxy.passwd); - Curl_safefree(existing->socks_proxy.passwd); - existing->http_proxy.user = temp->http_proxy.user; - existing->socks_proxy.user = temp->socks_proxy.user; - existing->http_proxy.passwd = temp->http_proxy.passwd; - existing->socks_proxy.passwd = temp->socks_proxy.passwd; - temp->http_proxy.user = NULL; - temp->socks_proxy.user = NULL; - temp->http_proxy.passwd = NULL; - temp->socks_proxy.passwd = NULL; - } -#endif - - /* Finding a connection for reuse in the cache matches, among other - * things on the "remote-relevant" hostname. This is not necessarily - * the authority of the URL, e.g. conn->host. For example: - * - we use a proxy (not tunneling). we want to send all requests - * that use the same proxy on this connection. - * - we have a "connect-to" setting that may redirect the hostname of - * a new request to the same remote endpoint of an existing conn. - * We want to reuse an existing conn to the remote endpoint. - * Since connection reuse does not match on conn->host necessarily, we - * switch `existing` conn to `temp` conn's host settings. - * TODO: is this correct in the case of TLS connections that have - * used the original hostname in SNI to negotiate? Do we send - * requests for another host through the different SNI? - */ - Curl_free_idnconverted_hostname(&existing->host); - Curl_free_idnconverted_hostname(&existing->conn_to_host); - Curl_safefree(existing->host.rawalloc); - Curl_safefree(existing->conn_to_host.rawalloc); - existing->host = temp->host; - temp->host.rawalloc = NULL; - temp->host.encalloc = NULL; - existing->conn_to_host = temp->conn_to_host; - temp->conn_to_host.rawalloc = NULL; - existing->conn_to_port = temp->conn_to_port; - existing->remote_port = temp->remote_port; - Curl_safefree(existing->hostname_resolve); - - existing->hostname_resolve = temp->hostname_resolve; - temp->hostname_resolve = NULL; - - /* reuse init */ - existing->bits.reuse = TRUE; /* yes, we're reusing here */ - - conn_free(data, temp); -} - -/** - * create_conn() sets up a new connectdata struct, or reuses an already - * existing one, and resolves host name. - * - * if this function returns CURLE_OK and *async is set to TRUE, the resolve - * response will be coming asynchronously. If *async is FALSE, the name is - * already resolved. - * - * @param data The sessionhandle pointer - * @param in_connect is set to the next connection data pointer - * @param async is set TRUE when an async DNS resolution is pending - * @see Curl_setup_conn() - * - */ - -static CURLcode create_conn(struct Curl_easy *data, - struct connectdata **in_connect, - bool *async) -{ - CURLcode result = CURLE_OK; - struct connectdata *conn; - struct connectdata *existing = NULL; - bool reuse; - bool connections_available = TRUE; - bool force_reuse = FALSE; - bool waitpipe = FALSE; - size_t max_host_connections = Curl_multi_max_host_connections(data->multi); - size_t max_total_connections = Curl_multi_max_total_connections(data->multi); - - *async = FALSE; - *in_connect = NULL; - - /************************************************************* - * Check input data - *************************************************************/ - if(!data->state.url) { - result = CURLE_URL_MALFORMAT; - goto out; - } - - /* First, split up the current URL in parts so that we can use the - parts for checking against the already present connections. In order - to not have to modify everything at once, we allocate a temporary - connection data struct and fill in for comparison purposes. */ - conn = allocate_conn(data); - - if(!conn) { - result = CURLE_OUT_OF_MEMORY; - goto out; - } - - /* We must set the return variable as soon as possible, so that our - parent can cleanup any possible allocs we may have done before - any failure */ - *in_connect = conn; - - result = parseurlandfillconn(data, conn); - if(result) - goto out; - - if(data->set.str[STRING_SASL_AUTHZID]) { - conn->sasl_authzid = strdup(data->set.str[STRING_SASL_AUTHZID]); - if(!conn->sasl_authzid) { - result = CURLE_OUT_OF_MEMORY; - goto out; - } - } - - if(data->set.str[STRING_BEARER]) { - conn->oauth_bearer = strdup(data->set.str[STRING_BEARER]); - if(!conn->oauth_bearer) { - result = CURLE_OUT_OF_MEMORY; - goto out; - } - } - -#ifdef USE_UNIX_SOCKETS - if(data->set.str[STRING_UNIX_SOCKET_PATH]) { - conn->unix_domain_socket = strdup(data->set.str[STRING_UNIX_SOCKET_PATH]); - if(!conn->unix_domain_socket) { - result = CURLE_OUT_OF_MEMORY; - goto out; - } - conn->bits.abstract_unix_socket = data->set.abstract_unix_socket; - } -#endif - - /* After the unix socket init but before the proxy vars are used, parse and - initialize the proxy vars */ -#ifndef CURL_DISABLE_PROXY - result = create_conn_helper_init_proxy(data, conn); - if(result) - goto out; - - /************************************************************* - * If the protocol is using SSL and HTTP proxy is used, we set - * the tunnel_proxy bit. - *************************************************************/ - if((conn->given->flags&PROTOPT_SSL) && conn->bits.httpproxy) - conn->bits.tunnel_proxy = TRUE; -#endif - - /************************************************************* - * Figure out the remote port number and fix it in the URL - *************************************************************/ - result = parse_remote_port(data, conn); - if(result) - goto out; - - /* Check for overridden login details and set them accordingly so that - they are known when protocol->setup_connection is called! */ - result = override_login(data, conn); - if(result) - goto out; - - result = set_login(data, conn); /* default credentials */ - if(result) - goto out; - - /************************************************************* - * Process the "connect to" linked list of hostname/port mappings. - * Do this after the remote port number has been fixed in the URL. - *************************************************************/ - result = parse_connect_to_slist(data, conn, data->set.connect_to); - if(result) - goto out; - - /************************************************************* - * IDN-convert the proxy hostnames - *************************************************************/ -#ifndef CURL_DISABLE_PROXY - if(conn->bits.httpproxy) { - result = Curl_idnconvert_hostname(&conn->http_proxy.host); - if(result) - return result; - } - if(conn->bits.socksproxy) { - result = Curl_idnconvert_hostname(&conn->socks_proxy.host); - if(result) - return result; - } -#endif - if(conn->bits.conn_to_host) { - result = Curl_idnconvert_hostname(&conn->conn_to_host); - if(result) - return result; - } - - /************************************************************* - * Check whether the host and the "connect to host" are equal. - * Do this after the hostnames have been IDN-converted. - *************************************************************/ - if(conn->bits.conn_to_host && - strcasecompare(conn->conn_to_host.name, conn->host.name)) { - conn->bits.conn_to_host = FALSE; - } - - /************************************************************* - * Check whether the port and the "connect to port" are equal. - * Do this after the remote port number has been fixed in the URL. - *************************************************************/ - if(conn->bits.conn_to_port && conn->conn_to_port == conn->remote_port) { - conn->bits.conn_to_port = FALSE; - } - -#ifndef CURL_DISABLE_PROXY - /************************************************************* - * If the "connect to" feature is used with an HTTP proxy, - * we set the tunnel_proxy bit. - *************************************************************/ - if((conn->bits.conn_to_host || conn->bits.conn_to_port) && - conn->bits.httpproxy) - conn->bits.tunnel_proxy = TRUE; -#endif - - /************************************************************* - * Setup internals depending on protocol. Needs to be done after - * we figured out what/if proxy to use. - *************************************************************/ - result = setup_connection_internals(data, conn); - if(result) - goto out; - - /*********************************************************************** - * file: is a special case in that it doesn't need a network connection - ***********************************************************************/ -#ifndef CURL_DISABLE_FILE - if(conn->handler->flags & PROTOPT_NONETWORK) { - bool done; - /* this is supposed to be the connect function so we better at least check - that the file is present here! */ - DEBUGASSERT(conn->handler->connect_it); - Curl_persistconninfo(data, conn, NULL, -1); - result = conn->handler->connect_it(data, &done); - - /* Setup a "faked" transfer that'll do nothing */ - if(!result) { - Curl_attach_connection(data, conn); - result = Curl_conncache_add_conn(data); - if(result) - goto out; - - /* - * Setup whatever necessary for a resumed transfer - */ - result = setup_range(data); - if(result) { - DEBUGASSERT(conn->handler->done); - /* we ignore the return code for the protocol-specific DONE */ - (void)conn->handler->done(data, result, FALSE); - goto out; - } - Curl_setup_transfer(data, -1, -1, FALSE, -1); - } - - /* since we skip do_init() */ - Curl_init_do(data, conn); - - goto out; - } -#endif - - /* Setup filter for network connections */ - conn->recv[FIRSTSOCKET] = Curl_conn_recv; - conn->send[FIRSTSOCKET] = Curl_conn_send; - conn->recv[SECONDARYSOCKET] = Curl_conn_recv; - conn->send[SECONDARYSOCKET] = Curl_conn_send; - conn->bits.tcp_fastopen = data->set.tcp_fastopen; - - /* Complete the easy's SSL configuration for connection cache matching */ - result = Curl_ssl_easy_config_complete(data); - if(result) - goto out; - - prune_dead_connections(data); - - /************************************************************* - * Check the current list of connections to see if we can - * reuse an already existing one or if we have to create a - * new one. - *************************************************************/ - - DEBUGASSERT(conn->user); - DEBUGASSERT(conn->passwd); - - /* reuse_fresh is TRUE if we are told to use a new connection by force, but - we only acknowledge this option if this is not a reused connection - already (which happens due to follow-location or during an HTTP - authentication phase). CONNECT_ONLY transfers also refuse reuse. */ - if((data->set.reuse_fresh && !data->state.followlocation) || - data->set.connect_only) - reuse = FALSE; - else - reuse = ConnectionExists(data, conn, &existing, &force_reuse, &waitpipe); - - if(reuse) { - /* - * We already have a connection for this, we got the former connection in - * `existing` and thus we need to cleanup the one we just - * allocated before we can move along and use `existing`. - */ - reuse_conn(data, conn, existing); - conn = existing; - *in_connect = conn; - -#ifndef CURL_DISABLE_PROXY - infof(data, "Re-using existing connection with %s %s", - conn->bits.proxy?"proxy":"host", - conn->socks_proxy.host.name ? conn->socks_proxy.host.dispname : - conn->http_proxy.host.name ? conn->http_proxy.host.dispname : - conn->host.dispname); -#else - infof(data, "Re-using existing connection with host %s", - conn->host.dispname); -#endif - } - else { - /* We have decided that we want a new connection. However, we may not - be able to do that if we have reached the limit of how many - connections we are allowed to open. */ - - if(conn->handler->flags & PROTOPT_ALPN) { - /* The protocol wants it, so set the bits if enabled in the easy handle - (default) */ - if(data->set.ssl_enable_alpn) - conn->bits.tls_enable_alpn = TRUE; - } - - if(waitpipe) - /* There is a connection that *might* become usable for multiplexing - "soon", and we wait for that */ - connections_available = FALSE; - else { - /* this gets a lock on the conncache */ - struct connectbundle *bundle = - Curl_conncache_find_bundle(data, conn, data->state.conn_cache); - - if(max_host_connections > 0 && bundle && - (bundle->num_connections >= max_host_connections)) { - struct connectdata *conn_candidate; - - /* The bundle is full. Extract the oldest connection. */ - conn_candidate = Curl_conncache_extract_bundle(data, bundle); - CONNCACHE_UNLOCK(data); - - if(conn_candidate) - Curl_disconnect(data, conn_candidate, FALSE); - else { - infof(data, "No more connections allowed to host: %zu", - max_host_connections); - connections_available = FALSE; - } - } - else - CONNCACHE_UNLOCK(data); - - } - - if(connections_available && - (max_total_connections > 0) && - (Curl_conncache_size(data) >= max_total_connections)) { - struct connectdata *conn_candidate; - - /* The cache is full. Let's see if we can kill a connection. */ - conn_candidate = Curl_conncache_extract_oldest(data); - if(conn_candidate) - Curl_disconnect(data, conn_candidate, FALSE); - else { - infof(data, "No connections available in cache"); - connections_available = FALSE; - } - } - - if(!connections_available) { - infof(data, "No connections available."); - - conn_free(data, conn); - *in_connect = NULL; - - result = CURLE_NO_CONNECTION_AVAILABLE; - goto out; - } - else { - /* - * This is a brand new connection, so let's store it in the connection - * cache of ours! - */ - result = Curl_ssl_conn_config_init(data, conn); - if(result) { - DEBUGF(fprintf(stderr, "Error: init connection ssl config\n")); - goto out; - } - - Curl_attach_connection(data, conn); - result = Curl_conncache_add_conn(data); - if(result) - goto out; - } - -#if defined(USE_NTLM) - /* If NTLM is requested in a part of this connection, make sure we don't - assume the state is fine as this is a fresh connection and NTLM is - connection based. */ - if((data->state.authhost.picked & (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) && - data->state.authhost.done) { - infof(data, "NTLM picked AND auth done set, clear picked"); - data->state.authhost.picked = CURLAUTH_NONE; - data->state.authhost.done = FALSE; - } - - if((data->state.authproxy.picked & (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) && - data->state.authproxy.done) { - infof(data, "NTLM-proxy picked AND auth done set, clear picked"); - data->state.authproxy.picked = CURLAUTH_NONE; - data->state.authproxy.done = FALSE; - } -#endif - } - - /* Setup and init stuff before DO starts, in preparing for the transfer. */ - Curl_init_do(data, conn); - - /* - * Setup whatever necessary for a resumed transfer - */ - result = setup_range(data); - if(result) - goto out; - - /* Continue connectdata initialization here. */ - - /* - * Inherit the proper values from the urldata struct AFTER we have arranged - * the persistent connection stuff - */ - conn->seek_func = data->set.seek_func; - conn->seek_client = data->set.seek_client; - - /************************************************************* - * Resolve the address of the server or proxy - *************************************************************/ - result = resolve_server(data, conn, async); - if(result) - goto out; - - /* Everything general done, inform filters that they need - * to prepare for a data transfer. - */ - result = Curl_conn_ev_data_setup(data); - -out: - return result; -} - -/* Curl_setup_conn() is called after the name resolve initiated in - * create_conn() is all done. - * - * Curl_setup_conn() also handles reused connections - */ -CURLcode Curl_setup_conn(struct Curl_easy *data, - bool *protocol_done) -{ - CURLcode result = CURLE_OK; - struct connectdata *conn = data->conn; - - Curl_pgrsTime(data, TIMER_NAMELOOKUP); - - if(conn->handler->flags & PROTOPT_NONETWORK) { - /* nothing to setup when not using a network */ - *protocol_done = TRUE; - return result; - } - -#ifndef CURL_DISABLE_PROXY - /* set proxy_connect_closed to false unconditionally already here since it - is used strictly to provide extra information to a parent function in the - case of proxy CONNECT failures and we must make sure we don't have it - lingering set from a previous invoke */ - conn->bits.proxy_connect_closed = FALSE; -#endif - -#ifdef CURL_DO_LINEEND_CONV - data->state.crlf_conversions = 0; /* reset CRLF conversion counter */ -#endif /* CURL_DO_LINEEND_CONV */ - - /* set start time here for timeout purposes in the connect procedure, it - is later set again for the progress meter purpose */ - conn->now = Curl_now(); - if(!conn->bits.reuse) - result = Curl_conn_setup(data, conn, FIRSTSOCKET, conn->dns_entry, - CURL_CF_SSL_DEFAULT); - /* not sure we need this flag to be passed around any more */ - *protocol_done = FALSE; - return result; -} - -CURLcode Curl_connect(struct Curl_easy *data, - bool *asyncp, - bool *protocol_done) -{ - CURLcode result; - struct connectdata *conn; - - *asyncp = FALSE; /* assume synchronous resolves by default */ - - /* init the single-transfer specific data */ - Curl_free_request_state(data); - memset(&data->req, 0, sizeof(struct SingleRequest)); - data->req.size = data->req.maxdownload = -1; - data->req.no_body = data->set.opt_no_body; - - /* call the stuff that needs to be called */ - result = create_conn(data, &conn, asyncp); - - if(!result) { - if(CONN_INUSE(conn) > 1) - /* multiplexed */ - *protocol_done = TRUE; - else if(!*asyncp) { - /* DNS resolution is done: that's either because this is a reused - connection, in which case DNS was unnecessary, or because DNS - really did finish already (synch resolver/fast async resolve) */ - result = Curl_setup_conn(data, protocol_done); - } - } - - if(result == CURLE_NO_CONNECTION_AVAILABLE) { - return result; - } - else if(result && conn) { - /* We're not allowed to return failure with memory left allocated in the - connectdata struct, free those here */ - Curl_detach_connection(data); - Curl_conncache_remove_conn(data, conn, TRUE); - Curl_disconnect(data, conn, TRUE); - } - - return result; -} - -/* - * Curl_init_do() inits the readwrite session. This is inited each time (in - * the DO function before the protocol-specific DO functions are invoked) for - * a transfer, sometimes multiple times on the same Curl_easy. Make sure - * nothing in here depends on stuff that are setup dynamically for the - * transfer. - * - * Allow this function to get called with 'conn' set to NULL. - */ - -CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn) -{ - struct SingleRequest *k = &data->req; - - /* if this is a pushed stream, we need this: */ - CURLcode result = Curl_preconnect(data); - if(result) - return result; - - if(conn) { - conn->bits.do_more = FALSE; /* by default there's no curl_do_more() to - use */ - /* if the protocol used doesn't support wildcards, switch it off */ - if(data->state.wildcardmatch && - !(conn->handler->flags & PROTOPT_WILDCARD)) - data->state.wildcardmatch = FALSE; - } - - data->state.done = FALSE; /* *_done() is not called yet */ - data->state.expect100header = FALSE; - - if(data->req.no_body) - /* in HTTP lingo, no body means using the HEAD request... */ - data->state.httpreq = HTTPREQ_HEAD; - - k->start = Curl_now(); /* start time */ - k->header = TRUE; /* assume header */ - k->bytecount = 0; - k->ignorebody = FALSE; - - Curl_client_cleanup(data); - Curl_speedinit(data); - Curl_pgrsSetUploadCounter(data, 0); - Curl_pgrsSetDownloadCounter(data, 0); - - return CURLE_OK; -} - -#if defined(USE_HTTP2) || defined(USE_HTTP3) - -#ifdef USE_NGHTTP2 - -static void priority_remove_child(struct Curl_easy *parent, - struct Curl_easy *child) -{ - struct Curl_data_prio_node **pnext = &parent->set.priority.children; - struct Curl_data_prio_node *pnode = parent->set.priority.children; - - DEBUGASSERT(child->set.priority.parent == parent); - while(pnode && pnode->data != child) { - pnext = &pnode->next; - pnode = pnode->next; - } - - DEBUGASSERT(pnode); - if(pnode) { - *pnext = pnode->next; - free(pnode); - } - - child->set.priority.parent = 0; - child->set.priority.exclusive = FALSE; -} - -CURLcode Curl_data_priority_add_child(struct Curl_easy *parent, - struct Curl_easy *child, - bool exclusive) -{ - if(child->set.priority.parent) { - priority_remove_child(child->set.priority.parent, child); - } - - if(parent) { - struct Curl_data_prio_node **tail; - struct Curl_data_prio_node *pnode; - - pnode = calloc(1, sizeof(*pnode)); - if(!pnode) - return CURLE_OUT_OF_MEMORY; - pnode->data = child; - - if(parent->set.priority.children && exclusive) { - /* exclusive: move all existing children underneath the new child */ - struct Curl_data_prio_node *node = parent->set.priority.children; - while(node) { - node->data->set.priority.parent = child; - node = node->next; - } - - tail = &child->set.priority.children; - while(*tail) - tail = &(*tail)->next; - - DEBUGASSERT(!*tail); - *tail = parent->set.priority.children; - parent->set.priority.children = 0; - } - - tail = &parent->set.priority.children; - while(*tail) { - (*tail)->data->set.priority.exclusive = FALSE; - tail = &(*tail)->next; - } - - DEBUGASSERT(!*tail); - *tail = pnode; - } - - child->set.priority.parent = parent; - child->set.priority.exclusive = exclusive; - return CURLE_OK; -} - -#endif /* USE_NGHTTP2 */ - -#ifdef USE_NGHTTP2 -static void data_priority_cleanup(struct Curl_easy *data) -{ - while(data->set.priority.children) { - struct Curl_easy *tmp = data->set.priority.children->data; - priority_remove_child(data, tmp); - if(data->set.priority.parent) - Curl_data_priority_add_child(data->set.priority.parent, tmp, FALSE); - } - - if(data->set.priority.parent) - -- Gitee