diff --git a/.github/workflows/build-win.yaml b/.github/workflows/build-win.yaml index b92c6fe7..e602c817 100644 --- a/.github/workflows/build-win.yaml +++ b/.github/workflows/build-win.yaml @@ -61,6 +61,7 @@ jobs: mingw-w64-${{ matrix.env }}-nasm mingw-w64-${{ matrix.env }}-gcc mingw-w64-${{ matrix.env }}-go + mingw-w64-${{ matrix.env }}-libuv - name: Copy and patch shell: msys2 {0} diff --git a/Makefile.in b/Makefile.in index e36ae352..41d73245 100644 --- a/Makefile.in +++ b/Makefile.in @@ -9,16 +9,17 @@ SHELL := bash # MAKEFLAGS += --no-builtin-rules SUBJOBS := 4 -BROTLI_VERSION := 1.0.9 +BROTLI_VERSION := 1.1.0 # In case this is changed, update build-and-test-make.yml as well # In case this is changed, update build-and-test-make.yml as well BORING_SSL_COMMIT := d24a38200fef19150eef00cad35b138936c08767 -NGHTTP2_VERSION := nghttp2-1.56.0 -NGHTTP2_URL := https://github.com/nghttp2/nghttp2/releases/download/v1.56.0/nghttp2-1.56.0.tar.bz2 -CURL_VERSION := curl-8_5_0 +NGHTTP2_VERSION := nghttp2-1.61.0 +NGHTTP2_URL := https://github.com/nghttp2/nghttp2/releases/download/v1.61.0/nghttp2-1.61.0.tar.bz2 +CURL_VERSION := curl-8_7_1 +# https://github.com/google/brotli/commit/641bec0e30bea648b3da1cd90fc6b44deb429f71 brotli_install_dir := $(abspath brotli-$(BROTLI_VERSION)/out/installed) -brotli_static_libs := $(brotli_install_dir)/lib/libbrotlicommon-static.a $(brotli_install_dir)/lib/libbrotlidec-static.a +brotli_static_libs := $(brotli_install_dir)/lib/libbrotlicommon.a $(brotli_install_dir)/lib/libbrotlidec.a boringssl_install_dir := $(abspath boringssl/build) boringssl_static_libs := $(boringssl_install_dir)/lib/libssl.a $(boringssl_install_dir)/lib/libcrypto.a nghttp2_install_dir := $(abspath $(NGHTTP2_VERSION)/installed) @@ -144,6 +145,7 @@ $(brotli_static_libs): brotli-$(BROTLI_VERSION).tar.gz -DCMAKE_C_FLAGS="$(CFLAGS)" \ -DCMAKE_SYSTEM_NAME=$$system_name \ -DCMAKE_SYSTEM_PROCESSOR=$(host_cpu) \ + -DBUILD_SHARED_LIBS=OFF \ .. @cmake@ --build . --config Release --target install --parallel $(SUBJOBS) diff --git a/README.md b/README.md index 366a9ee1..8f461f09 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ > 2. ZSTD compression support introduced in Chrome 123. > 3. X25519Kyber768 curve introduced in Chrome 124. > 4. More options for impersonation Akamai http/2 fingerprints, especially for Safari. -> 5. Upgrade to more recent version of curl, 8.5.0 as of April, 2024. +> 5. Upgrade to more recent version of curl, 8.7.1 as of April, 2024. > 6. Ability to change extension orders and enable/disable TLS grease. > 7. (In progress) Single binary to support both Webkit-based and Gecko-based browsers, i.e. Chrome and Firefox. diff --git a/chrome/curl_chrome100 b/chrome/curl_chrome100 index 085e1a63..30120ced 100755 --- a/chrome/curl_chrome100 +++ b/chrome/curl_chrome100 @@ -23,6 +23,8 @@ dir=${0%/*} --http2 \ --http2-settings '1:65536;3:1000;4:6291456;6:262144' \ --http2-window-update 15663105 \ + --http2-stream-weight 256 \ + --http2-stream-exclusive 1 \ --compressed \ --tlsv1.2 --alps \ --cert-compression brotli \ diff --git a/chrome/curl_chrome101 b/chrome/curl_chrome101 index d77ef41d..90d4c43f 100755 --- a/chrome/curl_chrome101 +++ b/chrome/curl_chrome101 @@ -23,6 +23,8 @@ dir=${0%/*} --http2 \ --http2-settings '1:65536;3:1000;4:6291456;6:262144' \ --http2-window-update 15663105 \ + --http2-stream-weight 256 \ + --http2-stream-exclusive 1 \ --compressed \ --tlsv1.2 --alps \ --cert-compression brotli \ diff --git a/chrome/curl_chrome104 b/chrome/curl_chrome104 index 0d9ed592..aa237e18 100755 --- a/chrome/curl_chrome104 +++ b/chrome/curl_chrome104 @@ -23,6 +23,8 @@ dir=${0%/*} --http2 \ --http2-settings '1:65536;3:1000;4:6291456;6:262144' \ --http2-window-update 15663105 \ + --http2-stream-weight 256 \ + --http2-stream-exclusive 1 \ --compressed \ --tlsv1.2 --alps \ --cert-compression brotli \ diff --git a/chrome/curl_chrome107 b/chrome/curl_chrome107 index 32fad580..6fa69775 100755 --- a/chrome/curl_chrome107 +++ b/chrome/curl_chrome107 @@ -23,6 +23,8 @@ dir=${0%/*} --http2 \ --http2-settings '1:65536;2:0;3:1000;4:6291456;6:262144' \ --http2-window-update 15663105 \ + --http2-stream-weight 256 \ + --http2-stream-exclusive 1 \ --compressed \ --tlsv1.2 --alps \ --cert-compression brotli \ diff --git a/chrome/curl_chrome110 b/chrome/curl_chrome110 index 50826dbd..c0b53f46 100755 --- a/chrome/curl_chrome110 +++ b/chrome/curl_chrome110 @@ -23,6 +23,8 @@ dir=${0%/*} --http2 \ --http2-settings '1:65536;2:0;3:1000;4:6291456;6:262144' \ --http2-window-update 15663105 \ + --http2-stream-weight 256 \ + --http2-stream-exclusive 1 \ --compressed \ --tlsv1.2 --alps --tls-permute-extensions \ --cert-compression brotli \ diff --git a/chrome/curl_chrome116 b/chrome/curl_chrome116 index d5b14d45..13972f41 100755 --- a/chrome/curl_chrome116 +++ b/chrome/curl_chrome116 @@ -23,6 +23,8 @@ dir=${0%/*} --http2 \ --http2-settings '1:65536;2:0;3:1000;4:6291456;6:262144' \ --http2-window-update 15663105 \ + --http2-stream-weight 256 \ + --http2-stream-exclusive 1 \ --compressed \ --tlsv1.2 --alps --tls-permute-extensions \ --cert-compression brotli \ diff --git a/chrome/curl_chrome119 b/chrome/curl_chrome119 index dd3629c9..75fad132 100755 --- a/chrome/curl_chrome119 +++ b/chrome/curl_chrome119 @@ -23,6 +23,8 @@ dir=${0%/*} --http2 \ --http2-settings '1:65536;2:0;4:6291456;6:262144' \ --http2-window-update 15663105 \ + --http2-stream-weight 256 \ + --http2-stream-exclusive 1 \ --compressed \ --ech GREASE \ --tlsv1.2 --alps --tls-permute-extensions \ diff --git a/chrome/curl_chrome120 b/chrome/curl_chrome120 index 8218e242..d02ce4ff 100755 --- a/chrome/curl_chrome120 +++ b/chrome/curl_chrome120 @@ -23,6 +23,8 @@ dir=${0%/*} --http2 \ --http2-settings '1:65536;2:0;4:6291456;6:262144' \ --http2-window-update 15663105 \ + --http2-stream-weight 256 \ + --http2-stream-exclusive 1 \ --compressed \ --ech GREASE \ --tlsv1.2 --alps --tls-permute-extensions \ diff --git a/chrome/curl_chrome123 b/chrome/curl_chrome123 index a4c50cc1..6a4dba96 100755 --- a/chrome/curl_chrome123 +++ b/chrome/curl_chrome123 @@ -26,6 +26,8 @@ dir=${0%/*} --http2 \ --http2-settings '1:65536;2:0;4:6291456;6:262144' \ --http2-window-update 15663105 \ + --http2-stream-weight 256 \ + --http2-stream-exclusive 1 \ --compressed \ --ech GREASE \ --tlsv1.2 --alps --tls-permute-extensions \ diff --git a/chrome/curl_chrome124 b/chrome/curl_chrome124 index 0b481ad6..0468a366 100755 --- a/chrome/curl_chrome124 +++ b/chrome/curl_chrome124 @@ -29,6 +29,8 @@ dir=${0%/*} --http2 \ --http2-settings '1:65536;2:0;4:6291456;6:262144' \ --http2-window-update 15663105 \ + --http2-stream-weight 256 \ + --http2-stream-exclusive 1 \ --compressed \ --ech GREASE \ --tlsv1.2 --alps --tls-permute-extensions \ diff --git a/chrome/curl_chrome99 b/chrome/curl_chrome99 index 20ef1cf4..2c643921 100755 --- a/chrome/curl_chrome99 +++ b/chrome/curl_chrome99 @@ -23,6 +23,8 @@ dir=${0%/*} --http2 \ --http2-settings '1:65536;3:1000;4:6291456;6:262144' \ --http2-window-update 15663105 \ + --http2-stream-weight 256 \ + --http2-stream-exclusive 1 \ --compressed \ --tlsv1.2 --alps \ --cert-compression brotli \ diff --git a/chrome/curl_chrome99_android b/chrome/curl_chrome99_android index 79277699..5435fad8 100755 --- a/chrome/curl_chrome99_android +++ b/chrome/curl_chrome99_android @@ -23,6 +23,8 @@ dir=${0%/*} --http2 \ --http2-settings '1:65536;3:1000;4:6291456;6:262144' \ --http2-window-update 15663105 \ + --http2-stream-weight 256 \ + --http2-stream-exclusive 1 \ --compressed \ --tlsv1.2 --alps \ --cert-compression brotli \ diff --git a/chrome/curl_edge101 b/chrome/curl_edge101 index 6193dec1..d9dd10de 100755 --- a/chrome/curl_edge101 +++ b/chrome/curl_edge101 @@ -23,6 +23,8 @@ dir=${0%/*} --http2 \ --http2-settings '1:65536;3:1000;4:6291456;6:262144' \ --http2-window-update 15663105 \ + --http2-stream-weight 256 \ + --http2-stream-exclusive 1 \ --compressed \ --tlsv1.2 --alps \ --cert-compression brotli \ diff --git a/chrome/curl_edge99 b/chrome/curl_edge99 index cd8e1a65..8e025be3 100755 --- a/chrome/curl_edge99 +++ b/chrome/curl_edge99 @@ -23,6 +23,8 @@ dir=${0%/*} --http2 \ --http2-settings '1:65536;3:1000;4:6291456;6:262144' \ --http2-window-update 15663105 \ + --http2-stream-weight 256 \ + --http2-stream-exclusive 1 \ --compressed \ --tlsv1.2 --alps \ --cert-compression brotli \ diff --git a/chrome/curl_safari15_3 b/chrome/curl_safari15_3 index 0d78f445..ef8cc1f9 100755 --- a/chrome/curl_safari15_3 +++ b/chrome/curl_safari15_3 @@ -18,6 +18,8 @@ dir=${0%/*} --http2-settings '4:4194304;3:100' \ --http2-pseudo-headers-order 'mspa' \ --http2-window-update 10485760 \ + --http2-stream-weight 255 \ + --http2-stream-exclusive 0 \ --compressed \ --tlsv1.0 --no-tls-session-ticket \ --tls-grease \ diff --git a/chrome/curl_safari15_5 b/chrome/curl_safari15_5 index a565cd6a..931d1dff 100755 --- a/chrome/curl_safari15_5 +++ b/chrome/curl_safari15_5 @@ -18,6 +18,8 @@ dir=${0%/*} --http2-settings '4:4194304;3:100' \ --http2-pseudo-headers-order 'mspa' \ --http2-window-update 10485760 \ + --http2-stream-weight 255 \ + --http2-stream-exclusive 0 \ --compressed \ --tlsv1.0 --no-tls-session-ticket \ --cert-compression zlib \ diff --git a/chrome/curl_safari17_0 b/chrome/curl_safari17_0 index 7c06c1dc..1ca523a9 100755 --- a/chrome/curl_safari17_0 +++ b/chrome/curl_safari17_0 @@ -21,6 +21,8 @@ dir=${0%/*} --http2-settings '2:0;4:4194304;3:100' \ --http2-pseudo-headers-order 'mspa' \ --http2-window-update 10485760 \ + --http2-stream-weight 255 \ + --http2-stream-exclusive 0 \ --compressed \ --tlsv1.0 --no-tls-session-ticket \ --cert-compression zlib \ diff --git a/chrome/curl_safari17_2_ios b/chrome/curl_safari17_2_ios index ca5c576d..e9743e00 100755 --- a/chrome/curl_safari17_2_ios +++ b/chrome/curl_safari17_2_ios @@ -21,6 +21,8 @@ dir=${0%/*} --http2-settings '2:0;4:2097152;3:100' \ --http2-pseudo-headers-order 'mspa' \ --http2-window-update 10485760 \ + --http2-stream-weight 255 \ + --http2-stream-exclusive 0 \ --compressed \ --tlsv1.0 --no-tls-session-ticket \ --cert-compression zlib \ diff --git a/chrome/patches/boringssl.patch b/chrome/patches/boringssl.patch index 85183aee..d3adf2de 100644 --- a/chrome/patches/boringssl.patch +++ b/chrome/patches/boringssl.patch @@ -1,33 +1,39 @@ diff --git a/export.sh b/export.sh new file mode 100755 -index 000000000..2e1f397aa +index 000000000..678d1ca41 --- /dev/null +++ b/export.sh @@ -0,0 +1,4 @@ +#!/bin/bash + -+git df d24a382 > boringssl.patch ++git diff d24a382 > boringssl.patch +mv boringssl.patch ../curl-impersonate/chrome/patches/boringssl.patch diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h -index e500dd76e..487945969 100644 +index e500dd76e..e75bca26b 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h -@@ -1560,6 +1560,9 @@ OPENSSL_EXPORT int SSL_CTX_set_strict_cipher_list(SSL_CTX *ctx, +@@ -1560,6 +1560,12 @@ OPENSSL_EXPORT int SSL_CTX_set_strict_cipher_list(SSL_CTX *ctx, // garbage inputs, unless an empty cipher list results. OPENSSL_EXPORT int SSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str); +// curl-impersonate: set the extension order by given string +OPENSSL_EXPORT int SSL_CTX_set_extension_order(SSL_CTX *ctx, char *order); ++ ++// curl-impersonate ++OPENSSL_EXPORT int SSL_CTX_set_key_usage_check_enabled(SSL_CTX *ctx, int enabled); + // SSL_set_strict_cipher_list configures the cipher list for |ssl|, evaluating // |str| as a cipher string and returning error if |str| contains anything // meaningless. It returns one on success and zero on failure. -@@ -4583,6 +4586,9 @@ OPENSSL_EXPORT void SSL_CTX_set_grease_enabled(SSL_CTX *ctx, int enabled); +@@ -4583,6 +4589,12 @@ OPENSSL_EXPORT void SSL_CTX_set_grease_enabled(SSL_CTX *ctx, int enabled); // permute extensions. For now, this is only implemented for the ClientHello. OPENSSL_EXPORT void SSL_CTX_set_permute_extensions(SSL_CTX *ctx, int enabled); +// curl-impersonate +OPENSSL_EXPORT int SSL_CTX_set_extension_order(SSL_CTX *ctx, char *order); ++ ++// curl-impersonate ++OPENSSL_EXPORT int SSL_CTX_set_key_usage_check_enabled(SSL_CTX *ctx, int enabled); + // SSL_set_permute_extensions configures whether sockets on |ssl| should // permute extensions. For now, this is only implemented for the ClientHello. @@ -126,7 +132,7 @@ index b13400097..8b457b873 100644 if (!kExtensions[i].add_clienthello(hs, &extensions, &extensions, type)) { OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_ADDING_EXTENSION); diff --git a/ssl/handshake_client.cc b/ssl/handshake_client.cc -index 971ebd0b1..0005c6d79 100644 +index 971ebd0b1..effe5c920 100644 --- a/ssl/handshake_client.cc +++ b/ssl/handshake_client.cc @@ -215,14 +215,6 @@ static void ssl_get_client_disabled(const SSL_HANDSHAKE *hs, @@ -182,8 +188,18 @@ index 971ebd0b1..0005c6d79 100644 !ssl_encrypt_client_hello(hs, MakeConstSpan(ech_enc, ech_enc_len)) || !ssl_add_client_hello(hs)) { return ssl_hs_error; +@@ -1402,7 +1374,8 @@ static enum ssl_hs_wait_t do_send_client_key_exchange(SSL_HANDSHAKE *hs) { + ssl_key_usage_t intended_use = (alg_k & SSL_kRSA) + ? key_usage_encipherment + : key_usage_digital_signature; +- if (!ssl_cert_check_key_usage(&leaf_cbs, intended_use)) { ++ if (hs->config->key_usage_check_enabled && ++ !ssl_cert_check_key_usage(&leaf_cbs, intended_use)) { + if (hs->config->enforce_rsa_key_usage || + EVP_PKEY_id(hs->peer_pubkey.get()) != EVP_PKEY_RSA) { + return ssl_hs_error; diff --git a/ssl/internal.h b/ssl/internal.h -index c9facb699..eab61611e 100644 +index c9facb699..a32e9b4ba 100644 --- a/ssl/internal.h +++ b/ssl/internal.h @@ -574,9 +574,14 @@ BSSL_NAMESPACE_BEGIN @@ -202,32 +218,41 @@ index c9facb699..eab61611e 100644 // Bits for |algorithm_prf| (handshake digest). #define SSL_HANDSHAKE_MAC_DEFAULT 0x1 -@@ -2161,6 +2166,9 @@ bssl::UniquePtr tls13_create_session_with_ticket(SSL *ssl, +@@ -2161,6 +2166,12 @@ bssl::UniquePtr tls13_create_session_with_ticket(SSL *ssl, // for |hs|, if applicable. It returns true on success and false on error. bool ssl_setup_extension_permutation(SSL_HANDSHAKE *hs); +// curl-impersonate +bool ssl_set_extension_order(SSL_HANDSHAKE *hs); ++ ++// curl-impersonate ++bool ssl_set_key_usage_check_enabled(SSL_HANDSHAKE *hs); + // ssl_setup_key_shares computes client key shares and saves them in |hs|. It // returns true on success and false on failure. If |override_group_id| is zero, // it offers the default groups, including GREASE. If it is non-zero, it offers -@@ -3033,6 +3041,9 @@ struct SSL_CONFIG { +@@ -3033,6 +3044,12 @@ struct SSL_CONFIG { // crypto UniquePtr cipher_list; + // curl-impersonate + char *extension_order = nullptr; ++ ++ // curl-impersonate ++ int key_usage_check_enabled = 1; + // This is used to hold the local certificate used (i.e. the server // certificate for a server or the client certificate for a client). UniquePtr cert; -@@ -3490,6 +3501,9 @@ struct ssl_ctx_st { +@@ -3490,6 +3507,12 @@ struct ssl_ctx_st { bssl::UniquePtr cipher_list; + // curl-impersonate + char *extension_order = nullptr; ++ ++ // curl-impersonate ++ int key_usage_check_enabled = 1; + X509_STORE *cert_store = nullptr; LHASH_OF(SSL_SESSION) *sessions = nullptr; @@ -463,18 +488,19 @@ index fd8cef95d..3d2c8ff6d 100644 "Not all ciphers are included in the cipher order"); diff --git a/ssl/ssl_lib.cc b/ssl/ssl_lib.cc -index 58b68e675..15eb823b3 100644 +index 58b68e675..455ee4dd0 100644 --- a/ssl/ssl_lib.cc +++ b/ssl/ssl_lib.cc -@@ -657,6 +657,7 @@ SSL *SSL_new(SSL_CTX *ctx) { +@@ -657,6 +657,8 @@ SSL *SSL_new(SSL_CTX *ctx) { ssl->config->retain_only_sha256_of_client_certs = ctx->retain_only_sha256_of_client_certs; ssl->config->permute_extensions = ctx->permute_extensions; -+ ssl->config->extension_order = ctx->extension_order; ++ ssl->config->extension_order = ctx->extension_order; // curl-impersonate ++ ssl->config->key_usage_check_enabled = ctx->key_usage_check_enabled; // curl-impersonate ssl->config->aes_hw_override = ctx->aes_hw_override; ssl->config->aes_hw_override_value = ctx->aes_hw_override_value; ssl->config->tls13_cipher_policy = ctx->tls13_cipher_policy; -@@ -3015,6 +3016,12 @@ void SSL_CTX_set_permute_extensions(SSL_CTX *ctx, int enabled) { +@@ -3015,6 +3017,17 @@ void SSL_CTX_set_permute_extensions(SSL_CTX *ctx, int enabled) { ctx->permute_extensions = !!enabled; } @@ -483,6 +509,11 @@ index 58b68e675..15eb823b3 100644 + ctx->extension_order = order; + return 0; +} ++ ++int SSL_CTX_set_key_usage_check_enabled(SSL_CTX *ctx, int enabled) { ++ ctx->key_usage_check_enabled = enabled; ++ return 0; ++} + void SSL_set_permute_extensions(SSL *ssl, int enabled) { if (!ssl->config) { diff --git a/chrome/patches/curl-impersonate.patch b/chrome/patches/curl-impersonate.patch index 7b227e3e..e56bffdc 100644 --- a/chrome/patches/curl-impersonate.patch +++ b/chrome/patches/curl-impersonate.patch @@ -1,10 +1,10 @@ diff --git a/CMakeLists.txt b/CMakeLists.txt -index a54c2fff9..7d22d4e96 100644 +index 656aa7c74..594e9574a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt -@@ -619,6 +619,29 @@ if(CURL_ZSTD) - endif() - endif() +@@ -627,6 +627,29 @@ macro(openssl_check_symbol_exists SYMBOL FILES VARIABLE) + cmake_pop_check_state() + endmacro() +option(USE_ECH "Enable ECH support" OFF) +if(USE_ECH) @@ -29,21 +29,21 @@ index a54c2fff9..7d22d4e96 100644 + endif() +endif() + - # Check symbol in OpenSSL-like TLS backends. - macro(openssl_check_symbol_exists SYMBOL FILES VARIABLE) - cmake_push_check_state() + # Ensure that the OpenSSL fork actually supports QUIC. + macro(openssl_check_quic) + if(NOT DEFINED HAVE_SSL_CTX_SET_QUIC_METHOD) diff --git a/Makefile.am b/Makefile.am -index c8afcb505..234125083 100644 +index 658189e47..1ebc38b5a 100644 --- a/Makefile.am +++ b/Makefile.am -@@ -131,13 +131,13 @@ CLEANFILES = $(VC14_LIBVCXPROJ) \ - $(VC14_SRCVCXPROJ) $(VC14_10_LIBVCXPROJ) $(VC14_10_SRCVCXPROJ) \ +@@ -132,13 +132,13 @@ CLEANFILES = $(VC14_LIBVCXPROJ) $(VC14_SRCVCXPROJ) \ + $(VC14_20_LIBVCXPROJ) $(VC14_20_SRCVCXPROJ) \ $(VC14_30_LIBVCXPROJ) $(VC14_30_SRCVCXPROJ) -bin_SCRIPTS = curl-config +bin_SCRIPTS = curl-impersonate-chrome-config - SUBDIRS = lib src + SUBDIRS = lib docs src scripts DIST_SUBDIRS = $(SUBDIRS) tests packages scripts include docs pkgconfigdir = $(libdir)/pkgconfig @@ -53,7 +53,7 @@ index c8afcb505..234125083 100644 # List of files required to generate VC IDE .dsp, .vcproj and .vcxproj files include lib/Makefile.inc diff --git a/configure.ac b/configure.ac -index d9b396376..cd3b845f4 100644 +index 49371a755..a19c12b95 100644 --- a/configure.ac +++ b/configure.ac @@ -1422,7 +1422,8 @@ if test X"$OPT_BROTLI" != Xno; then @@ -61,8 +61,8 @@ index d9b396376..cd3b845f4 100644 dnl if given with a prefix, we set -L and -I based on that if test -n "$PREFIX_BROTLI"; then - LIB_BROTLI="-lbrotlidec" -+ # curl-impersonate: Use static libbrotli -+ LIB_BROTLI="-lbrotlidec-static -lbrotlicommon-static" ++ # curl-impersonate: Use static libbrotli, -static postfix dropped since brotli 1.1.0 ++ LIB_BROTLI="-lbrotlidec -lbrotlicommon" LD_BROTLI=-L${PREFIX_BROTLI}/lib$libsuff CPP_BROTLI=-I${PREFIX_BROTLI}/include DIR_BROTLI=${PREFIX_BROTLI}/lib$libsuff @@ -79,7 +79,7 @@ index d9b396376..cd3b845f4 100644 AC_CHECK_HEADERS(brotli/decode.h, curl_brotli_msg="enabled (libbrotlidec)" -@@ -4383,14 +4388,23 @@ if test "x$want_ech" != "xno"; then +@@ -4547,14 +4552,23 @@ if test "x$want_ech" != "xno"; then ECH_ENABLED=0 ECH_SUPPORT='' @@ -108,7 +108,7 @@ index d9b396376..cd3b845f4 100644 fi dnl now deal with whatever we found -@@ -4795,8 +4809,8 @@ AC_CONFIG_FILES([Makefile \ +@@ -4962,8 +4976,8 @@ AC_CONFIG_FILES([Makefile \ tests/http/clients/Makefile \ packages/Makefile \ packages/vms/Makefile \ @@ -146,52 +146,57 @@ index 54f92d931..ea5895e9b 100644 exit 1 diff --git a/export.sh b/export.sh new file mode 100755 -index 000000000..34b44cd2a +index 000000000..7bced6879 --- /dev/null +++ b/export.sh -@@ -0,0 +1,4 @@ +@@ -0,0 +1,9 @@ +#!/bin/bash + -+git df curl-8_5_0 > chrome.patch ++# TODO: use cmake to generate mingw makefile, see: ++# ++# 1. https://github.com/curl/curl/pull/13244/files ++# 2. https://everything.curl.dev/build/windows.html ++ ++git df curl-8_7_1 > chrome.patch +mv chrome.patch ../curl-impersonate/chrome/patches/curl-impersonate.patch diff --git a/include/curl/curl.h b/include/curl/curl.h -index cc24c0506..9cba4dd14 100644 +index b2377b789..c614266e5 100644 --- a/include/curl/curl.h +++ b/include/curl/curl.h -@@ -631,6 +631,7 @@ typedef enum { - CURLE_PROXY, /* 97 - proxy handshake error */ +@@ -632,6 +632,7 @@ typedef enum { CURLE_SSL_CLIENTCERT, /* 98 - client-side certificate required */ CURLE_UNRECOVERABLE_POLL, /* 99 - poll/select returned fatal error */ -+ CURLE_ECH_REQUIRED , /* 100 - ECH tried but failed */ + CURLE_TOO_LARGE, /* 100 - a value/data met its maximum */ ++ CURLE_ECH_REQUIRED, /* 101 - ECH tried but failed */ CURL_LAST /* never use! */ } CURLcode; -@@ -2201,6 +2202,77 @@ typedef enum { - /* set a specific client IP for HAProxy PROXY protocol header? */ - CURLOPT(CURLOPT_HAPROXY_CLIENT_IP, CURLOPTTYPE_STRINGPOINT, 323), +@@ -2206,6 +2207,79 @@ typedef enum { + /* millisecond version */ + CURLOPT(CURLOPT_SERVER_RESPONSE_TIMEOUT_MS, CURLOPTTYPE_LONG, 324), + /* curl-impersonate: A list of headers used by the impersonated browser. + * If given, merged with CURLOPT_HTTPHEADER. */ -+ CURLOPT(CURLOPT_HTTPBASEHEADER, CURLOPTTYPE_SLISTPOINT, 324), ++ CURLOPT(CURLOPT_HTTPBASEHEADER, CURLOPTTYPE_SLISTPOINT, 1000), + + /* curl-impersonate: A list of TLS signature hash algorithms. + * See https://datatracker.ietf.org/doc/html/rfc5246#section-7.4.1.4.1 */ -+ CURLOPT(CURLOPT_SSL_SIG_HASH_ALGS, CURLOPTTYPE_STRINGPOINT, 325), ++ CURLOPT(CURLOPT_SSL_SIG_HASH_ALGS, CURLOPTTYPE_STRINGPOINT, 1001), + + /* curl-impersonate: Whether to enable ALPS in TLS or not. + * See https://datatracker.ietf.org/doc/html/draft-vvv-tls-alps. + * Support for ALPS is minimal and is intended only for the TLS client + * hello to match. */ -+ CURLOPT(CURLOPT_SSL_ENABLE_ALPS, CURLOPTTYPE_LONG, 326), ++ CURLOPT(CURLOPT_SSL_ENABLE_ALPS, CURLOPTTYPE_LONG, 1002), + + /* curl-impersonate: Comma-separated list of certificate compression + * algorithms to use. These are published in the client hello. + * Supported algorithms are "zlib" and "brotli". + * See https://datatracker.ietf.org/doc/html/rfc8879 */ -+ CURLOPT(CURLOPT_SSL_CERT_COMPRESSION, CURLOPTTYPE_STRINGPOINT, 327), ++ CURLOPT(CURLOPT_SSL_CERT_COMPRESSION, CURLOPTTYPE_STRINGPOINT, 1003), + + /* Enable/disable TLS session ticket extension (RFC5077) */ -+ CURLOPT(CURLOPT_SSL_ENABLE_TICKET, CURLOPTTYPE_LONG, 328), ++ CURLOPT(CURLOPT_SSL_ENABLE_TICKET, CURLOPTTYPE_LONG, 1004), + + /* + * curl-impersonate: @@ -200,46 +205,48 @@ index cc24c0506..9cba4dd14 100644 + * ":method", ":authority", ":scheme", ":path" in the desired order of + * appearance in the HTTP/2 HEADERS frame. + */ -+ CURLOPT(CURLOPT_HTTP2_PSEUDO_HEADERS_ORDER, CURLOPTTYPE_STRINGPOINT, 329), ++ CURLOPT(CURLOPT_HTTP2_PSEUDO_HEADERS_ORDER, CURLOPTTYPE_STRINGPOINT, 1005), + + /* + * curl-impersonate: + * HTTP2 settings frame keys and values, format: 1:v;2:v;3:v + */ -+ CURLOPT(CURLOPT_HTTP2_SETTINGS, CURLOPTTYPE_STRINGPOINT, 330), ++ CURLOPT(CURLOPT_HTTP2_SETTINGS, CURLOPTTYPE_STRINGPOINT, 1006), + + /* + * curl-impersonate: Whether to enable Boringssl permute extensions + * See https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#SSL_set_permute_extensions. + */ -+ CURLOPT(CURLOPT_SSL_PERMUTE_EXTENSIONS, CURLOPTTYPE_LONG, 331), ++ CURLOPT(CURLOPT_SSL_PERMUTE_EXTENSIONS, CURLOPTTYPE_LONG, 1007), + + /* + * curl-impersonate: + * HTTP2 initial window update + */ -+ CURLOPT(CURLOPT_HTTP2_WINDOW_UPDATE, CURLOPTTYPE_LONG, 332), ++ CURLOPT(CURLOPT_HTTP2_WINDOW_UPDATE, CURLOPTTYPE_LONG, 1008), + + /* curl-impersonate: -+ * set ECH configuration, XXX, the official one is 324 ++ * set ECH configuration + */ -+ CURLOPT(CURLOPT_ECH, CURLOPTTYPE_STRINGPOINT, 333), ++ CURLOPT(CURLOPT_ECH, CURLOPTTYPE_STRINGPOINT, 1009), + + /* + * curl-impersonate: + * Set the initial streams settings for http2. + */ -+ CURLOPT(CURLOPT_HTTP2_STREAMS, CURLOPTTYPE_STRINGPOINT, 334), ++ CURLOPT(CURLOPT_HTTP2_STREAMS, CURLOPTTYPE_STRINGPOINT, 1010), + -+ /* curl-impersonate: -+ * enable tls grease -+ */ -+ CURLOPT(CURLOPT_TLS_GREASE, CURLOPTTYPE_LONG, 335), ++ /* curl-impersonate: enable tls grease */ ++ CURLOPT(CURLOPT_TLS_GREASE, CURLOPTTYPE_LONG, 1011), + -+ /* curl-impersonate: -+ * set tls extension order -+ */ -+ CURLOPT(CURLOPT_TLS_EXTENSION_ORDER, CURLOPTTYPE_STRINGPOINT, 336), ++ /* curl-impersonate: set tls extension order */ ++ CURLOPT(CURLOPT_TLS_EXTENSION_ORDER, CURLOPTTYPE_STRINGPOINT, 1012), ++ ++ /* curl-impersonate: Set stream exclusiveness, 0 or 1 */ ++ CURLOPT(CURLOPT_STREAM_EXCLUSIVE, CURLOPTTYPE_LONG, 1013), ++ ++ /* curl-impersonate: enable tls key usage check, defaults: on */ ++ CURLOPT(CURLOPT_TLS_KEY_USAGE_NO_CHECK, CURLOPTTYPE_LONG, 1014), + CURLOPT_LASTENTRY /* the last unused */ } CURLoption; @@ -359,10 +366,10 @@ index 1237c8e99..6b2961018 100644 libcurlu_la_CPPFLAGS = $(AM_CPPFLAGS) -DCURL_STATICLIB -DUNITTESTS libcurlu_la_LDFLAGS = $(AM_LDFLAGS) -static $(LIBCURL_LIBS) diff --git a/lib/Makefile.inc b/lib/Makefile.inc -index e568ef953..298b16050 100644 +index 400e2b1ac..ff3e479aa 100644 --- a/lib/Makefile.inc +++ b/lib/Makefile.inc -@@ -171,6 +171,7 @@ LIB_CFILES = \ +@@ -177,6 +177,7 @@ LIB_CFILES = \ idn.c \ if2ip.c \ imap.c \ @@ -370,11 +377,60 @@ index e568ef953..298b16050 100644 inet_ntop.c \ inet_pton.c \ krb5.c \ +diff --git a/lib/content_encoding.c b/lib/content_encoding.c +index c1abf24e8..8e926dd2e 100644 +--- a/lib/content_encoding.c ++++ b/lib/content_encoding.c +@@ -300,7 +300,7 @@ static CURLcode deflate_do_write(struct Curl_easy *data, + struct zlib_writer *zp = (struct zlib_writer *) writer; + z_stream *z = &zp->z; /* zlib state structure */ + +- if(!(type & CLIENTWRITE_BODY)) ++ if(!(type & CLIENTWRITE_BODY) || !nbytes) + return Curl_cwriter_write(data, writer->next, type, buf, nbytes); + + /* Set the compressed input when this function is called */ +@@ -457,7 +457,7 @@ static CURLcode gzip_do_write(struct Curl_easy *data, + struct zlib_writer *zp = (struct zlib_writer *) writer; + z_stream *z = &zp->z; /* zlib state structure */ + +- if(!(type & CLIENTWRITE_BODY)) ++ if(!(type & CLIENTWRITE_BODY) || !nbytes) + return Curl_cwriter_write(data, writer->next, type, buf, nbytes); + + if(zp->zlib_init == ZLIB_INIT_GZIP) { +@@ -669,7 +669,7 @@ static CURLcode brotli_do_write(struct Curl_easy *data, + CURLcode result = CURLE_OK; + BrotliDecoderResult r = BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT; + +- if(!(type & CLIENTWRITE_BODY)) ++ if(!(type & CLIENTWRITE_BODY) || !nbytes) + return Curl_cwriter_write(data, writer->next, type, buf, nbytes); + + if(!bp->br) +@@ -762,7 +762,7 @@ static CURLcode zstd_do_write(struct Curl_easy *data, + ZSTD_outBuffer out; + size_t errorCode; + +- if(!(type & CLIENTWRITE_BODY)) ++ if(!(type & CLIENTWRITE_BODY) || !nbytes) + return Curl_cwriter_write(data, writer->next, type, buf, nbytes); + + if(!zp->decomp) { +@@ -916,7 +916,7 @@ static CURLcode error_do_write(struct Curl_easy *data, + (void) buf; + (void) nbytes; + +- if(!(type & CLIENTWRITE_BODY)) ++ if(!(type & CLIENTWRITE_BODY) || !nbytes) + return Curl_cwriter_write(data, writer->next, type, buf, nbytes); + + failf(data, "Unrecognized content encoding type. " diff --git a/lib/curl_config.h.cmake b/lib/curl_config.h.cmake -index 339358ea3..a9cf400fb 100644 +index 0f4db6982..dfabbefca 100644 --- a/lib/curl_config.h.cmake +++ b/lib/curl_config.h.cmake -@@ -811,3 +811,6 @@ ${SIZEOF_TIME_T_CODE} +@@ -796,3 +796,6 @@ ${SIZEOF_TIME_T_CODE} /* Define to 1 to enable TLS-SRP support. */ #cmakedefine USE_TLS_SRP 1 @@ -433,10 +489,10 @@ index 3b536000a..d7135698f 100644 /** * Return the n-th header entry or NULL if it does not exist. diff --git a/lib/easy.c b/lib/easy.c -index 322d1a41b..805613e6f 100644 +index dc4870608..f0b42fe8b 100644 --- a/lib/easy.c +++ b/lib/easy.c -@@ -74,6 +74,8 @@ +@@ -75,6 +75,8 @@ #include "dynbuf.h" #include "altsvc.h" #include "hsts.h" @@ -445,7 +501,7 @@ index 322d1a41b..805613e6f 100644 #include "easy_lock.h" -@@ -341,6 +343,203 @@ CURLsslset curl_global_sslset(curl_sslbackend id, const char *name, +@@ -342,6 +344,211 @@ CURLsslset curl_global_sslset(curl_sslbackend id, const char *name, return rc; } @@ -454,7 +510,7 @@ index 322d1a41b..805613e6f 100644 + * curl-impersonate: + * Actually call curl_easy_setopt() with all the needed options + * */ -+CURLcode _do_impersonate(struct Curl_easy *data, ++static CURLcode _do_impersonate(struct Curl_easy *data, + const struct impersonate_opts *opts, + int default_headers) +{ @@ -464,7 +520,7 @@ index 322d1a41b..805613e6f 100644 + + if(opts->target == NULL) { + DEBUGF(fprintf(stderr, "Error: unknown impersonation target '%s'\n", -+ target)); ++ opts->target)); + return CURLE_BAD_FUNCTION_ARGUMENT; + } + @@ -590,6 +646,14 @@ index 322d1a41b..805613e6f 100644 + ret = curl_easy_setopt(data, CURLOPT_TLS_EXTENSION_ORDER, opts->tls_extension_order); + } + ++ if(opts->http2_stream_weight) { ++ ret = curl_easy_setopt(data, CURLOPT_STREAM_WEIGHT, opts->http2_stream_weight); ++ } ++ ++ if(opts->http2_stream_exclusive) { ++ ret = curl_easy_setopt(data, CURLOPT_STREAM_EXCLUSIVE, opts->http2_stream_exclusive); ++ } ++ + /* Always enable all supported compressions. */ + ret = curl_easy_setopt(data, CURLOPT_ACCEPT_ENCODING, ""); + if(ret) @@ -649,7 +713,7 @@ index 322d1a41b..805613e6f 100644 /* * curl_easy_init() is the external interface to alloc, setup and init an * easy handle that is returned. If anything goes wrong, NULL is returned. -@@ -349,6 +548,8 @@ struct Curl_easy *curl_easy_init(void) +@@ -350,6 +557,8 @@ struct Curl_easy *curl_easy_init(void) { CURLcode result; struct Curl_easy *data; @@ -658,7 +722,7 @@ index 322d1a41b..805613e6f 100644 /* Make sure we inited the global SSL stuff */ global_init_lock(); -@@ -371,6 +572,29 @@ struct Curl_easy *curl_easy_init(void) +@@ -372,6 +581,29 @@ struct Curl_easy *curl_easy_init(void) return NULL; } @@ -688,7 +752,7 @@ index 322d1a41b..805613e6f 100644 return data; } -@@ -945,6 +1169,13 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) +@@ -952,6 +1184,13 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) outcurl->state.referer_alloc = TRUE; } @@ -702,17 +766,17 @@ index 322d1a41b..805613e6f 100644 /* Reinitialize an SSL engine for the new handle * note: the engine name has already been copied by dupset */ if(outcurl->set.str[STRING_SSL_ENGINE]) { -@@ -1004,6 +1235,9 @@ fail: +@@ -1040,6 +1279,9 @@ fail: */ void curl_easy_reset(struct Curl_easy *data) { + char *env_target; + char *env_headers; + - Curl_free_request_state(data); + Curl_req_hard_reset(&data->req, data); /* zero out UserDefined data: */ -@@ -1028,6 +1262,23 @@ void curl_easy_reset(struct Curl_easy *data) +@@ -1064,6 +1306,23 @@ void curl_easy_reset(struct Curl_easy *data) #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_DIGEST_AUTH) Curl_http_auth_cleanup_digest(data); #endif @@ -737,7 +801,7 @@ index 322d1a41b..805613e6f 100644 /* diff --git a/lib/easyoptions.c b/lib/easyoptions.c -index e69c658b0..027dd6f93 100644 +index 9c4438a10..680fd7afe 100644 --- a/lib/easyoptions.c +++ b/lib/easyoptions.c @@ -86,6 +86,7 @@ struct curl_easyoption Curl_easyopts[] = { @@ -763,7 +827,7 @@ index e69c658b0..027dd6f93 100644 {"HTTPHEADER", CURLOPT_HTTPHEADER, CURLOT_SLIST, 0}, {"HTTPPOST", CURLOPT_HTTPPOST, CURLOT_OBJECT, 0}, {"HTTPPROXYTUNNEL", CURLOPT_HTTPPROXYTUNNEL, CURLOT_LONG, 0}, -@@ -305,18 +312,23 @@ struct curl_easyoption Curl_easyopts[] = { +@@ -307,22 +314,28 @@ struct curl_easyoption Curl_easyopts[] = { {"SSLKEYTYPE", CURLOPT_SSLKEYTYPE, CURLOT_STRING, 0}, {"SSLKEY_BLOB", CURLOPT_SSLKEY_BLOB, CURLOT_BLOB, 0}, {"SSLVERSION", CURLOPT_SSLVERSION, CURLOT_VALUES, 0}, @@ -787,28 +851,34 @@ index e69c658b0..027dd6f93 100644 {"STDERR", CURLOPT_STDERR, CURLOT_OBJECT, 0}, {"STREAM_DEPENDS", CURLOPT_STREAM_DEPENDS, CURLOT_OBJECT, 0}, {"STREAM_DEPENDS_E", CURLOPT_STREAM_DEPENDS_E, CURLOT_OBJECT, 0}, -@@ -340,6 +352,8 @@ struct curl_easyoption Curl_easyopts[] = { + {"STREAM_WEIGHT", CURLOPT_STREAM_WEIGHT, CURLOT_LONG, 0}, ++ {"STREAM_EXCLUSIVE", CURLOPT_STREAM_EXCLUSIVE, CURLOT_LONG, 0}, + {"SUPPRESS_CONNECT_HEADERS", CURLOPT_SUPPRESS_CONNECT_HEADERS, + CURLOT_LONG, 0}, + {"TCP_FASTOPEN", CURLOPT_TCP_FASTOPEN, CURLOT_LONG, 0}, +@@ -342,6 +355,9 @@ struct curl_easyoption Curl_easyopts[] = { {"TLSAUTH_PASSWORD", CURLOPT_TLSAUTH_PASSWORD, CURLOT_STRING, 0}, {"TLSAUTH_TYPE", CURLOPT_TLSAUTH_TYPE, CURLOT_STRING, 0}, {"TLSAUTH_USERNAME", CURLOPT_TLSAUTH_USERNAME, CURLOT_STRING, 0}, -+ {"TLS_GREASE", CURLOPT_TLS_GREASE, CURLOT_LONG, 0}, + {"TLS_EXTENSION_ORDER", CURLOPT_TLS_EXTENSION_ORDER, CURLOT_STRING, 0}, ++ {"TLS_GREASE", CURLOPT_TLS_GREASE, CURLOT_LONG, 0}, ++ {"TLS_KEY_USAGE_NO_CHECK", CURLOPT_TLS_KEY_USAGE_NO_CHECK, CURLOT_LONG, 0}, {"TRAILERDATA", CURLOPT_TRAILERDATA, CURLOT_CBPTR, 0}, {"TRAILERFUNCTION", CURLOPT_TRAILERFUNCTION, CURLOT_FUNCTION, 0}, {"TRANSFERTEXT", CURLOPT_TRANSFERTEXT, CURLOT_LONG, 0}, -@@ -373,6 +387,6 @@ struct curl_easyoption Curl_easyopts[] = { +@@ -375,6 +391,6 @@ struct curl_easyoption Curl_easyopts[] = { */ int Curl_easyopts_check(void) { -- return ((CURLOPT_LASTENTRY%10000) != (323 + 1)); -+ return ((CURLOPT_LASTENTRY%10000) != (334 + 1)); +- return ((CURLOPT_LASTENTRY%10000) != (324 + 1)); ++ return ((CURLOPT_LASTENTRY%10000) != (1013 + 1)); } #endif diff --git a/lib/http.c b/lib/http.c -index be6d442e8..ca537314a 100644 +index 92c04e69c..84ece2a16 100644 --- a/lib/http.c +++ b/lib/http.c -@@ -90,6 +90,7 @@ +@@ -91,6 +91,7 @@ #include "ws.h" #include "c-hyper.h" #include "curl_ctype.h" @@ -816,7 +886,7 @@ index be6d442e8..ca537314a 100644 /* The last 3 #include files should be in this order */ #include "curl_printf.h" -@@ -1937,6 +1938,15 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data, +@@ -1451,6 +1452,15 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data, int numlists = 1; /* by default */ int i; @@ -832,7 +902,7 @@ index be6d442e8..ca537314a 100644 #ifndef CURL_DISABLE_PROXY enum proxy_use proxy; -@@ -1948,10 +1958,10 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data, +@@ -1462,10 +1472,10 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data, switch(proxy) { case HEADER_SERVER: @@ -845,7 +915,7 @@ index be6d442e8..ca537314a 100644 if(data->set.sep_headers) { h[1] = data->set.proxyheaders; numlists++; -@@ -1961,12 +1971,12 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data, +@@ -1475,12 +1485,12 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data, if(data->set.sep_headers) h[0] = data->set.proxyheaders; else @@ -860,7 +930,7 @@ index be6d442e8..ca537314a 100644 #endif /* loop through one or two lists */ -@@ -2202,6 +2212,108 @@ void Curl_http_method(struct Curl_easy *data, struct connectdata *conn, +@@ -1717,6 +1727,108 @@ void Curl_http_method(struct Curl_easy *data, struct connectdata *conn, *reqp = httpreq; } @@ -969,9 +1039,9 @@ index be6d442e8..ca537314a 100644 CURLcode Curl_http_useragent(struct Curl_easy *data) { /* The User-Agent string might have been allocated in url.c already, because -@@ -3210,6 +3322,11 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) - http = data->req.p.http; - DEBUGASSERT(http); +@@ -2558,6 +2670,11 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) + if(result) + goto fail; + /* curl-impersonate: Add HTTP headers to impersonate real browsers. */ + result = Curl_http_merge_headers(data); @@ -980,8 +1050,8 @@ index be6d442e8..ca537314a 100644 + result = Curl_http_host(data, conn); if(result) - return result; -@@ -4847,12 +4964,41 @@ static bool h2_non_field(const char *name, size_t namelen) + goto fail; +@@ -4269,12 +4386,41 @@ static bool h2_non_field(const char *name, size_t namelen) return FALSE; } @@ -1023,7 +1093,7 @@ index be6d442e8..ca537314a 100644 CURLcode result; DEBUGASSERT(req); -@@ -4886,25 +5032,56 @@ CURLcode Curl_http_req_to_h2(struct dynhds *h2_headers, +@@ -4308,25 +4454,56 @@ CURLcode Curl_http_req_to_h2(struct dynhds *h2_headers, Curl_dynhds_reset(h2_headers); Curl_dynhds_set_opts(h2_headers, DYNHDS_OPT_LOWERCASE); @@ -1093,7 +1163,7 @@ index be6d442e8..ca537314a 100644 } diff --git a/lib/http2.c b/lib/http2.c -index 973848484..36654499d 100644 +index 99d7f3b0e..da160907e 100644 --- a/lib/http2.c +++ b/lib/http2.c @@ -51,6 +51,7 @@ @@ -1286,7 +1356,7 @@ index 973848484..36654499d 100644 static CURLcode h2_progress_egress(struct Curl_cfilter *cf, struct Curl_easy *data); -@@ -504,8 +635,22 @@ static CURLcode cf_h2_ctx_init(struct Curl_cfilter *cf, +@@ -491,8 +622,22 @@ static CURLcode cf_h2_ctx_init(struct Curl_cfilter *cf, } } @@ -1311,7 +1381,7 @@ index 973848484..36654499d 100644 if(rc) { failf(data, "nghttp2_session_set_local_window_size() failed: %s(%d)", nghttp2_strerror(rc), rc); -@@ -513,6 +658,16 @@ static CURLcode cf_h2_ctx_init(struct Curl_cfilter *cf, +@@ -500,6 +645,16 @@ static CURLcode cf_h2_ctx_init(struct Curl_cfilter *cf, goto out; } @@ -1328,7 +1398,7 @@ index 973848484..36654499d 100644 /* all set, traffic will be send on connect */ result = CURLE_OK; CURL_TRC_CF(data, cf, "[0] created h2 session%s", -@@ -1747,11 +1902,19 @@ out: +@@ -1716,11 +1871,19 @@ out: return rv; } @@ -1337,7 +1407,8 @@ index 973848484..36654499d 100644 + * instead of NGINX default stream weight. + */ +#define CHROME_DEFAULT_STREAM_WEIGHT (256) -+#define FIREFOX_DEFAULT_STREAM_WEIGHT (42) ++#define SAFARI_DEFAULT_STREAM_WEIGHT (255) ++#define FIREFOX_DEFAULT_STREAM_WEIGHT (42) + static int sweight_wanted(const struct Curl_easy *data) { @@ -1345,19 +1416,10 @@ index 973848484..36654499d 100644 return data->set.priority.weight? - data->set.priority.weight : NGHTTP2_DEFAULT_WEIGHT; + data->set.priority.weight : CHROME_DEFAULT_STREAM_WEIGHT; -+ // data->set.priority.weight : FIREFOX_DEFAULT_STREAM_WEIGHT; } static int sweight_in_effect(const struct Curl_easy *data) -@@ -1759,6 +1922,7 @@ static int sweight_in_effect(const struct Curl_easy *data) - /* 0 weight is not set by user and we take the nghttp2 default one */ - return data->state.priority.weight? - data->state.priority.weight : NGHTTP2_DEFAULT_WEIGHT; -+ // data->state.priority.weight : FIREFOX_DEFAULT_STREAM_WEIGHT; - } - - /* -@@ -1767,15 +1931,24 @@ static int sweight_in_effect(const struct Curl_easy *data) +@@ -1736,12 +1899,23 @@ static int sweight_in_effect(const struct Curl_easy *data) * struct. */ @@ -1371,20 +1433,18 @@ index 973848484..36654499d 100644 nghttp2_priority_spec *pri_spec) { struct Curl_data_priority *prio = &data->set.priority; - struct stream_ctx *depstream = H2_STREAM_CTX(prio->parent); + struct h2_stream_ctx *depstream = H2_STREAM_CTX(prio->parent); int32_t depstream_id = depstream? depstream->id:0; + // int32_t depstream_id = depstream? depstream->id:FIREFOX_DEFAULT_STREAM_DEP; -+ /* curl-impersonate: Set stream exclusive flag to true. */ -+ int exclusive = 1; ++ ++ /* curl-impersonate: Set stream exclusive flag based on user option. ++ * Use data->set, not data->state. ++ */ nghttp2_priority_spec_init(pri_spec, depstream_id, sweight_wanted(data), -- data->set.priority.exclusive); -+ exclusive); - data->state.priority = *prio; - } - -@@ -1792,20 +1965,24 @@ static CURLcode h2_progress_egress(struct Curl_cfilter *cf, - struct stream_ctx *stream = H2_STREAM_CTX(data); + data->set.priority.exclusive); +@@ -1761,20 +1935,24 @@ static CURLcode h2_progress_egress(struct Curl_cfilter *cf, + struct h2_stream_ctx *stream = H2_STREAM_CTX(data); int rv = 0; + /* curl-impersonate: Check if stream exclusive flag is true. */ @@ -1432,10 +1492,10 @@ index 80e183480..8ee390b7e 100644 * Store nghttp2 version info in this buffer. diff --git a/lib/impersonate.c b/lib/impersonate.c new file mode 100644 -index 000000000..ef2023033 +index 000000000..b18b3a7b5 --- /dev/null +++ b/lib/impersonate.c -@@ -0,0 +1,970 @@ +@@ -0,0 +1,1007 @@ +#include "curl_setup.h" + +#include @@ -1484,6 +1544,8 @@ index 000000000..ef2023033 + }, + .http2_settings = "1:65536;3:1000;4:6291456;6:262144", + .http2_window_update = 15663105, ++ .http2_stream_weight = 256, ++ .http2_stream_exclusive = 1, + .tls_extension_order = NULL, + .tls_grease = true + }, @@ -1528,6 +1590,8 @@ index 000000000..ef2023033 + }, + .http2_settings = "1:65536;3:1000;4:6291456;6:262144", + .http2_window_update = 15663105, ++ .http2_stream_weight = 256, ++ .http2_stream_exclusive = 1, + .tls_extension_order = NULL, + .tls_grease = true + }, @@ -1572,6 +1636,8 @@ index 000000000..ef2023033 + }, + .http2_settings = "1:65536;3:1000;4:6291456;6:262144", + .http2_window_update = 15663105, ++ .http2_stream_weight = 256, ++ .http2_stream_exclusive = 1, + .tls_extension_order = NULL, + .tls_grease = true + }, @@ -1616,6 +1682,8 @@ index 000000000..ef2023033 + }, + .http2_settings = "1:65536;3:1000;4:6291456;6:262144", + .http2_window_update = 15663105, ++ .http2_stream_weight = 256, ++ .http2_stream_exclusive = 1, + .tls_extension_order = NULL, + .tls_grease = true + }, @@ -1660,6 +1728,8 @@ index 000000000..ef2023033 + }, + .http2_settings = "1:65536;2:0;3:1000;4:6291456;6:262144", + .http2_window_update = 15663105, ++ .http2_stream_weight = 256, ++ .http2_stream_exclusive = 1, + .tls_extension_order = NULL, + .tls_grease = true + }, @@ -1705,6 +1775,8 @@ index 000000000..ef2023033 + }, + .http2_settings = "1:65536;2:0;3:1000;4:6291456;6:262144", + .http2_window_update = 15663105, ++ .http2_stream_weight = 256, ++ .http2_stream_exclusive = 1, + .tls_extension_order = NULL, + .tls_grease = true + }, @@ -1750,6 +1822,8 @@ index 000000000..ef2023033 + }, + .http2_settings = "1:65536;2:0;3:1000;4:6291456;6:262144", + .http2_window_update = 15663105, ++ .http2_stream_weight = 256, ++ .http2_stream_exclusive = 1, + .tls_extension_order = NULL, + .tls_grease = true + }, @@ -1795,6 +1869,8 @@ index 000000000..ef2023033 + }, + .http2_settings = "1:65536;2:0;4:6291456;6:262144", + .http2_window_update = 15663105, ++ .http2_stream_weight = 256, ++ .http2_stream_exclusive = 1, + .ech = "GREASE", + .tls_extension_order = NULL, + .tls_grease = true @@ -1841,6 +1917,8 @@ index 000000000..ef2023033 + }, + .http2_settings = "1:65536;2:0;4:6291456;6:262144", + .http2_window_update = 15663105, ++ .http2_stream_weight = 256, ++ .http2_stream_exclusive = 1, + .ech = "GREASE", + .tls_extension_order = NULL, + .tls_grease = true @@ -1887,6 +1965,8 @@ index 000000000..ef2023033 + }, + .http2_settings = "1:65536;2:0;4:6291456;6:262144", + .http2_window_update = 15663105, ++ .http2_stream_weight = 256, ++ .http2_stream_exclusive = 1, + .ech = "GREASE", + .tls_extension_order = NULL, + .tls_grease = true @@ -1935,6 +2015,8 @@ index 000000000..ef2023033 + }, + .http2_settings = "1:65536;2:0;4:6291456;6:262144", + .http2_window_update = 15663105, ++ .http2_stream_weight = 256, ++ .http2_stream_exclusive = 1, + .ech = "GREASE", + .tls_extension_order = NULL, + .tls_grease = true @@ -1980,6 +2062,8 @@ index 000000000..ef2023033 + }, + .http2_settings = "1:65536;3:1000;4:6291456;6:262144", + .http2_window_update = 15663105, ++ .http2_stream_weight = 256, ++ .http2_stream_exclusive = 1, + .tls_extension_order = NULL, + .tls_grease = true + }, @@ -2024,6 +2108,8 @@ index 000000000..ef2023033 + }, + .http2_settings = "1:65536;3:1000;4:6291456;6:262144", + .http2_window_update = 15663105, ++ .http2_stream_weight = 256, ++ .http2_stream_exclusive = 1, + .tls_extension_order = NULL, + .tls_grease = true + }, @@ -2068,6 +2154,8 @@ index 000000000..ef2023033 + }, + .http2_settings = "1:65536;3:1000;4:6291456;6:262144", + .http2_window_update = 15663105, ++ .http2_stream_weight = 256, ++ .http2_stream_exclusive = 1, + .tls_extension_order = NULL, + .tls_grease = true + }, @@ -2128,6 +2216,8 @@ index 000000000..ef2023033 + .http2_settings = "4:4194304;3:100", + .http2_window_update = 10485760, + .http2_pseudo_headers_order = "mspa", ++ .http2_stream_weight = 255, ++ .http2_stream_exclusive = 0, + .tls_extension_order = NULL, + .tls_grease = true + }, @@ -2183,6 +2273,8 @@ index 000000000..ef2023033 + .http2_settings = "4:4194304;3:100", + .http2_window_update = 10485760, + .http2_pseudo_headers_order = "mspa", ++ .http2_stream_weight = 255, ++ .http2_stream_exclusive = 0, + .tls_extension_order = NULL, + .tls_grease = true + }, @@ -2241,6 +2333,8 @@ index 000000000..ef2023033 + .http2_settings = "2:0;4:2097152;3:100", + .http2_window_update = 10485760, + .http2_pseudo_headers_order = "mspa", ++ .http2_stream_weight = 255, ++ .http2_stream_exclusive = 0, + .tls_extension_order = NULL, + .tls_grease = true + }, @@ -2299,6 +2393,8 @@ index 000000000..ef2023033 + .http2_settings = "2:0;4:4194304;3:100", + .http2_window_update = 10485760, + .http2_pseudo_headers_order = "mspa", ++ .http2_stream_weight = 255, ++ .http2_stream_exclusive = 0, + .tls_extension_order = NULL, + .tls_grease = true + }, @@ -2357,6 +2453,7 @@ index 000000000..ef2023033 + .http2_settings = "2:0;4:4194304;3:100", + .http2_window_update = 10485760, + .http2_pseudo_headers_order = "mspa", ++ .http2_stream_weight = 255, + .tls_extension_order = NULL, + .tls_grease = true + }, @@ -2408,10 +2505,10 @@ index 000000000..ef2023033 +}; diff --git a/lib/impersonate.h b/lib/impersonate.h new file mode 100644 -index 000000000..a9e1e4b45 +index 000000000..988a7f86a --- /dev/null +++ b/lib/impersonate.h -@@ -0,0 +1,50 @@ +@@ -0,0 +1,52 @@ +#ifndef HEADER_CURL_IMPERSONATE_H +#define HEADER_CURL_IMPERSONATE_H + @@ -2451,6 +2548,8 @@ index 000000000..a9e1e4b45 + const char *ech; + const char *tls_extension_order; + bool tls_grease; ++ int http2_stream_weight; ++ int http2_stream_exclusive; + /* Other TLS options will come here in the future once they are + * configurable through curl_easy_setopt() */ +}; @@ -2463,10 +2562,10 @@ index 000000000..a9e1e4b45 + +#endif /* HEADER_CURL_IMPERSONATE_H */ diff --git a/lib/multi.c b/lib/multi.c -index 5456113be..85841f769 100644 +index ed9cac796..6ca666e4a 100644 --- a/lib/multi.c +++ b/lib/multi.c -@@ -396,7 +396,8 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */ +@@ -401,7 +401,8 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */ Curl_llist_init(&multi->msgsent, NULL); multi->multiplexing = TRUE; @@ -2477,7 +2576,7 @@ index 5456113be..85841f769 100644 #ifdef USE_WINSOCK multi->wsa_event = WSACreateEvent(); diff --git a/lib/setopt.c b/lib/setopt.c -index a08140cce..05468ff49 100644 +index 8a5a5d7c3..3a78d3ac8 100644 --- a/lib/setopt.c +++ b/lib/setopt.c @@ -51,6 +51,7 @@ @@ -2485,10 +2584,10 @@ index a08140cce..05468ff49 100644 #include "hsts.h" #include "tftp.h" +#include "slist.h" - + #include "strdup.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" -@@ -710,6 +711,23 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) +@@ -717,6 +718,23 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) va_arg(param, char *)); break; @@ -2512,7 +2611,7 @@ index a08140cce..05468ff49 100644 #ifndef CURL_DISABLE_PROXY case CURLOPT_PROXYHEADER: /* -@@ -2394,6 +2412,27 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) +@@ -2398,6 +2416,27 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) result = Curl_setstropt(&data->set.str[STRING_SSL_EC_CURVES], va_arg(param, char *)); break; @@ -2540,7 +2639,7 @@ index a08140cce..05468ff49 100644 #endif case CURLOPT_IPRESOLVE: arg = va_arg(param, long); -@@ -2936,6 +2975,42 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) +@@ -2936,6 +2975,45 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) case CURLOPT_SSL_ENABLE_ALPN: data->set.ssl_enable_alpn = (0 != va_arg(param, long)); break; @@ -2560,6 +2659,9 @@ index a08140cce..05468ff49 100644 + result = Curl_setstropt(&data->set.str[STRING_TLS_EXTENSION_ORDER], + va_arg(param, char *)); + break; ++ case CURLOPT_TLS_KEY_USAGE_NO_CHECK: ++ data->set.tls_key_usage_no_check = (0 != va_arg(param, long)) ? TRUE : FALSE; ++ break; +#ifdef USE_HTTP2 + case CURLOPT_HTTP2_PSEUDO_HEADERS_ORDER: + result = Curl_setstropt(&data->set.str[STRING_HTTP2_PSEUDO_HEADERS_ORDER], @@ -2583,7 +2685,22 @@ index a08140cce..05468ff49 100644 #ifdef USE_UNIX_SOCKETS case CURLOPT_UNIX_SOCKET_PATH: data->set.abstract_unix_socket = FALSE; -@@ -3128,6 +3203,31 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) +@@ -2963,6 +3041,14 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) + break; + #else + return CURLE_NOT_BUILT_IN; ++#endif ++ case CURLOPT_STREAM_EXCLUSIVE: ++#if defined(USE_HTTP2) || defined(USE_HTTP3) ++ arg = va_arg(param, long); ++ data->set.priority.exclusive = (int)arg; ++ break; ++#else ++ return CURLE_NOT_BUILT_IN; + #endif + case CURLOPT_STREAM_DEPENDS: + case CURLOPT_STREAM_DEPENDS_E: +@@ -3132,6 +3218,31 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) data->set.ws_raw_mode = raw; break; } @@ -2616,12 +2733,12 @@ index a08140cce..05468ff49 100644 case CURLOPT_QUICK_EXIT: data->set.quick_exit = (0 != va_arg(param, long)) ? 1L:0L; diff --git a/lib/strerror.c b/lib/strerror.c -index 0d5f9276f..232116383 100644 +index a900e78d1..e7d54905a 100644 --- a/lib/strerror.c +++ b/lib/strerror.c -@@ -319,6 +319,11 @@ curl_easy_strerror(CURLcode error) - case CURLE_UNRECOVERABLE_POLL: - return "Unrecoverable error in select/poll"; +@@ -322,6 +322,11 @@ curl_easy_strerror(CURLcode error) + case CURLE_TOO_LARGE: + return "A value or data field grew larger than allowed"; +#ifdef USE_ECH + case CURLE_ECH_REQUIRED: @@ -2632,10 +2749,10 @@ index 0d5f9276f..232116383 100644 case CURLE_OBSOLETE20: case CURLE_OBSOLETE24: diff --git a/lib/transfer.c b/lib/transfer.c -index 96f1fde75..4a57497c7 100644 +index e31d1d6db..66e106901 100644 --- a/lib/transfer.c +++ b/lib/transfer.c -@@ -104,7 +104,15 @@ char *Curl_checkheaders(const struct Curl_easy *data, +@@ -105,7 +105,15 @@ char *Curl_checkheaders(const struct Curl_easy *data, DEBUGASSERT(thislen); DEBUGASSERT(thisheader[thislen-1] != ':'); @@ -2653,10 +2770,10 @@ index 96f1fde75..4a57497c7 100644 Curl_headersep(head->data[thislen]) ) return head->data; diff --git a/lib/url.c b/lib/url.c -index b81785fe2..699e8037a 100644 +index 224b9f3e2..db07bfa40 100644 --- a/lib/url.c +++ b/lib/url.c -@@ -322,6 +322,11 @@ CURLcode Curl_close(struct Curl_easy **datap) +@@ -320,6 +320,20 @@ CURLcode Curl_close(struct Curl_easy **datap) Curl_safefree(data->state.aptr.proxyuser); Curl_safefree(data->state.aptr.proxypasswd); @@ -2665,18 +2782,28 @@ index b81785fe2..699e8037a 100644 + /* curl-impersonate: Free the dynamic list of headers. */ + curl_slist_free_all(data->state.merged_headers); + - #ifndef CURL_DISABLE_DOH - if(data->req.doh) { - Curl_dyn_free(&data->req.doh->probe[0].serverdoh); -@@ -468,6 +473,7 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data) ++#ifndef CURL_DISABLE_DOH ++ if(data->req.doh) { ++ Curl_dyn_free(&data->req.doh->probe[0].serverdoh); ++ Curl_dyn_free(&data->req.doh->probe[1].serverdoh); ++ curl_slist_free_all(data->req.doh->headers); ++ Curl_safefree(data->req.doh); ++ } ++#endif ++ + #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_FORM_API) + Curl_mime_cleanpart(data->state.formp); + Curl_safefree(data->state.formp); +@@ -458,6 +472,8 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data) set->tcp_fastopen = FALSE; set->tcp_nodelay = TRUE; set->ssl_enable_alpn = TRUE; + set->ssl_enable_ticket = TRUE; ++ set->tls_grease = TRUE; set->expect_100_timeout = 1000L; /* Wait for a second by default. */ set->sep_headers = TRUE; /* separated header lists by default */ set->buffer_size = READBUFFER_SIZE; -@@ -3672,6 +3678,11 @@ static CURLcode create_conn(struct Curl_easy *data, +@@ -3664,6 +3680,11 @@ static CURLcode create_conn(struct Curl_easy *data, (default) */ if(data->set.ssl_enable_alpn) conn->bits.tls_enable_alpn = TRUE; @@ -2689,7 +2816,7 @@ index b81785fe2..699e8037a 100644 if(waitpipe) diff --git a/lib/urldata.h b/lib/urldata.h -index ff661482e..29b9d37fa 100644 +index ce28f25bb..1abb66c38 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -53,6 +53,15 @@ @@ -2705,10 +2832,10 @@ index ff661482e..29b9d37fa 100644 +# define CURLECH_CLA_CFG 4 +#endif + + struct curl_trc_featt; + #ifdef USE_WEBSOCKETS - /* CURLPROTO_GOPHERS (29) is the highest publicly used protocol bit number, - * the rest are internal information. If we use higher bits we only do this on -@@ -290,6 +299,8 @@ struct ssl_primary_config { +@@ -298,6 +307,8 @@ struct ssl_primary_config { char *password; /* TLS password (for, e.g., SRP) */ #endif char *curves; /* list of curves to use */ @@ -2717,17 +2844,26 @@ index ff661482e..29b9d37fa 100644 unsigned char ssl_options; /* the CURLOPT_SSL_OPTIONS bitmask */ unsigned int version_max; /* max supported version the client wants to use */ unsigned char version; /* what version the client wants to use */ -@@ -541,6 +552,9 @@ struct ConnectBits { +@@ -305,6 +316,7 @@ struct ssl_primary_config { + BIT(verifyhost); /* set TRUE if CN/SAN must match hostname */ + BIT(verifystatus); /* set TRUE if certificate status must be checked */ + BIT(sessionid); /* cache session IDs or not */ ++ // BIT(grease); /* grease enabled? */ + }; + + struct ssl_config_data { +@@ -545,6 +557,10 @@ struct ConnectBits { BIT(multiplex); /* connection is multiplexed */ BIT(tcp_fastopen); /* use TCP Fast Open */ BIT(tls_enable_alpn); /* TLS ALPN extension? */ + BIT(tls_enable_alps); /* TLS ALPS extension? */ + BIT(tls_enable_ticket); /* TLS session ticket extension? */ + BIT(tls_permute_extensions); /* TLS extension permutations */ ++ BIT(tls_grease); /* TLS grease? */ #ifndef CURL_DISABLE_DOH BIT(doh); #endif -@@ -1452,6 +1466,19 @@ struct UrlState { +@@ -1320,6 +1336,19 @@ struct UrlState { CURLcode hresult; /* used to pass return codes back from hyper callbacks */ #endif @@ -2744,10 +2880,10 @@ index ff661482e..29b9d37fa 100644 + */ + struct curl_slist *merged_headers; + - /* Dynamically allocated strings, MUST be freed before this struct is - killed. */ - struct dynamically_allocated_data { -@@ -1628,6 +1655,14 @@ enum dupstring { + #ifndef CURL_DISABLE_VERBOSE_STRINGS + struct curl_trc_feat *feat; /* opt. trace feature transfer is part of */ + #endif +@@ -1496,6 +1525,14 @@ enum dupstring { STRING_SSL_EC_CURVES, STRING_AWS_SIGV4, /* Parameters for V4 signature */ STRING_HAPROXY_CLIENT_IP, /* CURLOPT_HAPROXY_CLIENT_IP */ @@ -2762,17 +2898,19 @@ index ff661482e..29b9d37fa 100644 /* -- end of null-terminated strings -- */ -@@ -1921,6 +1956,9 @@ struct UserDefined { +@@ -1791,6 +1828,11 @@ struct UserDefined { BIT(tcp_keepalive); /* use TCP keepalives */ BIT(tcp_fastopen); /* use TCP Fast Open */ BIT(ssl_enable_alpn);/* TLS ALPN extension? */ + BIT(ssl_enable_alps);/* TLS ALPS extension? */ + BIT(ssl_enable_ticket); /* TLS session ticket extension */ + BIT(ssl_permute_extensions); /* TLS Permute extensions */ ++ BIT(tls_grease); /* TLS grease? */ ++ BIT(tls_key_usage_no_check); /* TLS key_usage_check? */ BIT(path_as_is); /* allow dotdots? */ BIT(pipewait); /* wait for multiplex status before starting a new connection */ -@@ -1941,6 +1979,11 @@ struct UserDefined { +@@ -1811,6 +1853,10 @@ struct UserDefined { #ifdef USE_WEBSOCKETS BIT(ws_raw_mode); #endif @@ -2780,12 +2918,11 @@ index ff661482e..29b9d37fa 100644 + int tls_ech; /* TLS ECH configuration */ +#endif + int http2_window_update; -+ BIT(tls_grease); }; - struct Names { + #ifndef CURL_DISABLE_MIME diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c -index 8c8f43e83..030832aeb 100644 +index a3953f6c3..bddf3edce 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -79,9 +79,24 @@ @@ -2927,7 +3064,7 @@ index 8c8f43e83..030832aeb 100644 #if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) typedef uint32_t sslerr_t; #else -@@ -2601,6 +2723,151 @@ static const char *tls_rt_type(int type) +@@ -2644,6 +2766,151 @@ static const char *tls_rt_type(int type) } } @@ -3079,7 +3216,7 @@ index 8c8f43e83..030832aeb 100644 /* * Our callback from the SSL/TLS layers. */ -@@ -3571,7 +3838,14 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, +@@ -3616,7 +3883,14 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, ctx_options = SSL_OP_ALL; #ifdef SSL_OP_NO_TICKET @@ -3095,7 +3232,7 @@ index 8c8f43e83..030832aeb 100644 #endif #ifdef SSL_OP_NO_COMPRESSION -@@ -3638,6 +3912,18 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, +@@ -3683,6 +3957,18 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, } #endif @@ -3114,7 +3251,7 @@ index 8c8f43e83..030832aeb 100644 if(ssl_cert || ssl_cert_blob || ssl_cert_type) { if(!result && !cert_stuff(data, backend->ctx, -@@ -3691,6 +3977,35 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, +@@ -3736,6 +4022,35 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, } #endif @@ -3150,7 +3287,7 @@ index 8c8f43e83..030832aeb 100644 #ifdef USE_OPENSSL_SRP if(ssl_config->primary.username && Curl_auth_allowed_to_host(data)) { char * const ssl_username = ssl_config->primary.username; -@@ -3716,6 +4031,38 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, +@@ -3761,6 +4076,44 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, } #endif @@ -3173,12 +3310,18 @@ index 8c8f43e83..030832aeb 100644 + SSL_CTX_set_permute_extensions(backend->ctx, 1); + } + -+ /* curl-impersonate: Set TLS extensions order. -+ */ ++ /* curl-impersonate: Set TLS extensions order. */ + if(data->set.str[STRING_TLS_EXTENSION_ORDER]) { + SSL_CTX_set_extension_order(backend->ctx, data->set.str[STRING_TLS_EXTENSION_ORDER]); + } + ++ // curl-impersonate: Set key usage check ++ if(data->set.tls_key_usage_no_check) { ++ SSL_CTX_set_key_usage_check_enabled(backend->ctx, 0); ++ }else{ ++ SSL_CTX_set_key_usage_check_enabled(backend->ctx, 1); ++ } ++ + if(conn_config->cert_compression && + add_cert_compression(data, + backend->ctx, @@ -3189,7 +3332,7 @@ index 8c8f43e83..030832aeb 100644 /* OpenSSL always tries to verify the peer, this only says whether it should * fail to connect if the verification fails, or if it should continue * anyway. In the latter case the result of the verification is checked with -@@ -3771,6 +4118,24 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, +@@ -3816,6 +4169,24 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, SSL_set_app_data(backend->handle, cf); @@ -3214,7 +3357,7 @@ index 8c8f43e83..030832aeb 100644 #if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ !defined(OPENSSL_NO_OCSP) if(conn_config->verifystatus) -@@ -3794,6 +4159,21 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, +@@ -3839,6 +4210,21 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, } #endif @@ -3236,7 +3379,7 @@ index 8c8f43e83..030832aeb 100644 SSL_set_app_data(backend->handle, cf); connssl->reused_session = FALSE; -@@ -4005,6 +4385,60 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf, +@@ -4050,6 +4436,60 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf, negotiated_group_name? negotiated_group_name : "[blank]", OBJ_nid2sn(psigtype_nid)); @@ -3298,7 +3441,7 @@ index 8c8f43e83..030832aeb 100644 /* Sets data and len to negotiated protocol, len is 0 if no protocol was * negotiated diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c -index 34eda3e5a..eda3f6d58 100644 +index d13a3cb1b..5ec3db492 100644 --- a/lib/vtls/vtls.c +++ b/lib/vtls/vtls.c @@ -139,6 +139,9 @@ static const struct alpn_spec ALPN_SPEC_H11 = { @@ -3383,7 +3526,7 @@ index 34eda3e5a..eda3f6d58 100644 ctx->backend = calloc(1, Curl_ssl->sizeof_ssl_backend_data); if(!ctx->backend) { free(ctx); -@@ -1883,8 +1907,11 @@ static CURLcode cf_ssl_create(struct Curl_cfilter **pcf, +@@ -1885,8 +1909,11 @@ static CURLcode cf_ssl_create(struct Curl_cfilter **pcf, DEBUGASSERT(data->conn); @@ -3397,7 +3540,7 @@ index 34eda3e5a..eda3f6d58 100644 if(!ctx) { result = CURLE_OUT_OF_MEMORY; goto out; -@@ -1934,6 +1961,7 @@ static CURLcode cf_ssl_proxy_create(struct Curl_cfilter **pcf, +@@ -1936,6 +1963,7 @@ static CURLcode cf_ssl_proxy_create(struct Curl_cfilter **pcf, struct ssl_connect_data *ctx; CURLcode result; bool use_alpn = conn->bits.tls_enable_alpn; @@ -3405,7 +3548,7 @@ index 34eda3e5a..eda3f6d58 100644 int httpwant = CURL_HTTP_VERSION_1_1; #ifdef USE_HTTP2 -@@ -1943,7 +1971,8 @@ static CURLcode cf_ssl_proxy_create(struct Curl_cfilter **pcf, +@@ -1945,7 +1973,8 @@ static CURLcode cf_ssl_proxy_create(struct Curl_cfilter **pcf, } #endif @@ -3416,7 +3559,7 @@ index 34eda3e5a..eda3f6d58 100644 result = CURLE_OUT_OF_MEMORY; goto out; diff --git a/lib/vtls/vtls.h b/lib/vtls/vtls.h -index f1856bd33..fe9f5c266 100644 +index 744bbf8fd..3bd42ee9d 100644 --- a/lib/vtls/vtls.h +++ b/lib/vtls/vtls.h @@ -44,6 +44,8 @@ struct Curl_ssl_session; @@ -3429,7 +3572,7 @@ index f1856bd33..fe9f5c266 100644 ALPN_ACCEPTED "%s" #define VTLS_INFOF_ALPN_ACCEPTED_LEN_1STR \ diff --git a/lib/vtls/vtls_int.h b/lib/vtls/vtls_int.h -index af7ae552e..f22147e22 100644 +index 0361fa95a..417e6a689 100644 --- a/lib/vtls/vtls_int.h +++ b/lib/vtls/vtls_int.h @@ -70,6 +70,7 @@ struct ssl_connect_data { @@ -3465,10 +3608,10 @@ index 9db6b0f89..14c2f23e0 100644 Libs.private: @LIBCURL_LIBS@ Cflags: -I${includedir} @CPPFLAG_CURL_STATICLIB@ diff --git a/m4/curl-compilers.m4 b/m4/curl-compilers.m4 -index 35ba19866..3bab99f62 100644 +index 9a4547709..42bc87373 100644 --- a/m4/curl-compilers.m4 +++ b/m4/curl-compilers.m4 -@@ -382,42 +382,55 @@ AC_DEFUN([CURL_CONVERT_INCLUDE_TO_ISYSTEM], [ +@@ -381,42 +381,55 @@ AC_DEFUN([CURL_CONVERT_INCLUDE_TO_ISYSTEM], [ AC_REQUIRE([CURL_SHFUNC_SQUEEZE])dnl AC_REQUIRE([CURL_CHECK_COMPILER])dnl AC_MSG_CHECKING([convert -I options to -isystem]) @@ -3560,10 +3703,10 @@ index 35ba19866..3bab99f62 100644 diff --git a/scripts/singleuse.pl b/scripts/singleuse.pl -index b8a57f8d8..63c0e7a55 100755 +index 064990226..172bdc2d0 100755 --- a/scripts/singleuse.pl +++ b/scripts/singleuse.pl -@@ -51,6 +51,7 @@ my %api = ( +@@ -56,6 +56,7 @@ my %api = ( 'curl_easy_escape' => 'API', 'curl_easy_getinfo' => 'API', 'curl_easy_init' => 'API', @@ -3572,7 +3715,7 @@ index b8a57f8d8..63c0e7a55 100755 'curl_easy_perform' => 'API', 'curl_easy_recv' => 'API', diff --git a/src/Makefile.am b/src/Makefile.am -index dced53e0f..dee8a2fc3 100644 +index fcc9cfdf9..18766b7dc 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -43,7 +43,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/include \ @@ -3582,9 +3725,9 @@ index dced53e0f..dee8a2fc3 100644 -bin_PROGRAMS = curl +bin_PROGRAMS = curl-impersonate-chrome + if BUILD_DOCS SUBDIRS = ../docs - -@@ -55,9 +55,9 @@ AM_CPPFLAGS += -DBUILDING_CURL +@@ -57,9 +57,9 @@ AM_CPPFLAGS += -DBUILDING_CURL include Makefile.inc # CURL_FILES comes from Makefile.inc @@ -3596,7 +3739,7 @@ index dced53e0f..dee8a2fc3 100644 $(CURL_RCFILES): tool_version.h endif -@@ -70,9 +70,9 @@ CFLAGS += @CURL_CFLAG_EXTRAS@ +@@ -72,9 +72,9 @@ CFLAGS += @CURL_CFLAG_EXTRAS@ LIBS = $(BLANK_AT_MAKETIME) if USE_EXPLICIT_LIB_DEPS @@ -3609,26 +3752,25 @@ index dced53e0f..dee8a2fc3 100644 # if unit tests are enabled, build a static library to link them with diff --git a/src/tool_cfgable.c b/src/tool_cfgable.c -index 906e23e14..5c6613a93 100644 +index 3259bc7a5..e46fd7539 100644 --- a/src/tool_cfgable.c +++ b/src/tool_cfgable.c -@@ -95,6 +95,15 @@ static void free_config_fields(struct OperationConfig *config) +@@ -96,6 +96,14 @@ static void free_config_fields(struct OperationConfig *config) Curl_safefree(config->proto_str); Curl_safefree(config->proto_redir_str); -+ // Impersonate ++ // curl-impersonate + Curl_safefree(config->ssl_sig_hash_algs); + Curl_safefree(config->ssl_cert_compression); + Curl_safefree(config->http2_pseudo_headers_order); + Curl_safefree(config->http2_settings); + Curl_safefree(config->http2_streams); + Curl_safefree(config->tls_extension_order); -+ // End Impersonate -+ ++ urlnode = config->url_list; while(urlnode) { struct getout *next = urlnode->next; -@@ -175,6 +184,14 @@ static void free_config_fields(struct OperationConfig *config) +@@ -176,6 +184,14 @@ static void free_config_fields(struct OperationConfig *config) Curl_safefree(config->aws_sigv4); Curl_safefree(config->proto_str); Curl_safefree(config->proto_redir_str); @@ -3644,10 +3786,10 @@ index 906e23e14..5c6613a93 100644 void config_free(struct OperationConfig *config) diff --git a/src/tool_cfgable.h b/src/tool_cfgable.h -index 57e8fce52..b5d7019b1 100644 +index dfa74d81f..349a46af6 100644 --- a/src/tool_cfgable.h +++ b/src/tool_cfgable.h -@@ -161,8 +161,16 @@ struct OperationConfig { +@@ -161,8 +161,18 @@ struct OperationConfig { bool crlf; char *customrequest; char *ssl_ec_curves; @@ -3658,13 +3800,15 @@ index 57e8fce52..b5d7019b1 100644 + char *http2_pseudo_headers_order; + char *http2_settings; + long http2_window_update; ++ long http2_stream_weight; ++ long http2_stream_exclusive; + char *http2_streams; + bool tls_grease; + char *tls_extension_order; long httpversion; bool http09_allowed; bool nobuffer; -@@ -192,6 +200,7 @@ struct OperationConfig { +@@ -192,6 +202,7 @@ struct OperationConfig { struct curl_slist *prequote; long ssl_version; long ssl_version_max; @@ -3672,7 +3816,7 @@ index 57e8fce52..b5d7019b1 100644 long proxy_ssl_version; long ip_version; long create_file_mode; /* CURLOPT_NEW_FILE_PERMS */ -@@ -268,6 +277,8 @@ struct OperationConfig { +@@ -268,6 +279,8 @@ struct OperationConfig { bool proxy_ssl_auto_client_cert; /* proxy version of ssl_auto_client_cert */ char *oauth_bearer; /* OAuth 2.0 bearer token */ bool noalpn; /* enable/disable TLS ALPN extension */ @@ -3681,7 +3825,7 @@ index 57e8fce52..b5d7019b1 100644 char *unix_socket_path; /* path to Unix domain socket */ bool abstract_unix_socket; /* path to an abstract Unix domain socket */ bool falsestart; -@@ -298,6 +309,11 @@ struct OperationConfig { +@@ -298,6 +311,11 @@ struct OperationConfig { struct State state; /* for create_transfer() */ bool rm_partial; /* on error, remove partially written output files */ @@ -3694,116 +3838,239 @@ index 57e8fce52..b5d7019b1 100644 struct GlobalConfig { diff --git a/src/tool_getparam.c b/src/tool_getparam.c -index 5fa1ace10..80277bbd9 100644 +index c6a9c9358..2234eb78d 100644 --- a/src/tool_getparam.c +++ b/src/tool_getparam.c -@@ -296,6 +296,20 @@ static const struct LongShort aliases[]= { - {"EC", "etag-save", ARG_FILENAME}, - {"ED", "etag-compare", ARG_FILENAME}, - {"EE", "curves", ARG_STRING}, -+ {"ET", "signature-hashes", ARG_STRING}, -+ {"EU", "alps", ARG_BOOL}, -+ {"EI", "cert-compression", ARG_STRING}, -+ {"EJ", "tls-session-ticket", ARG_BOOL}, -+ {"EK", "http2-pseudo-headers-order", ARG_STRING}, -+ {"EL", "http2-settings", ARG_STRING}, -+ {"EM", "tls-permute-extensions", ARG_BOOL}, -+ {"EN", "http2-window-update", ARG_STRING}, +@@ -77,6 +77,7 @@ static ParameterError getstr(char **str, const char *val, bool allowblank) + typedef enum { + C_ABSTRACT_UNIX_SOCKET, + C_ALPN, ++ C_ALPS, + C_ALT_SVC, + C_ANYAUTH, + C_APPEND, +@@ -87,6 +88,7 @@ typedef enum { + C_CACERT, + C_CAPATH, + C_CERT, ++ C_CERT_COMPRESSION, + C_CERT_STATUS, + C_CERT_TYPE, + C_CIPHERS, +@@ -123,6 +125,7 @@ typedef enum { + C_DOH_INSECURE, + C_DOH_URL, + C_DUMP_HEADER, ++ C_ECH, + C_EGD_FILE, + C_ENGINE, + C_EPRT, +@@ -166,6 +169,12 @@ typedef enum { + C_HTTP1_1, + C_HTTP2, + C_HTTP2_PRIOR_KNOWLEDGE, ++ C_HTTP2_PSEUDO_HEADERS_ORDER, ++ C_HTTP2_SETTINGS, ++ C_HTTP2_WINDOW_UPDATE, ++ C_HTTP2_STREAM_EXCLUSIVE, ++ C_HTTP2_STREAM_WEIGHT, ++ C_HTTP2_STREAMS, + C_HTTP3, + C_HTTP3_ONLY, + C_IGNORE_CONTENT_LENGTH, +@@ -283,6 +292,7 @@ typedef enum { + C_SESSIONID, + C_SHOW_ERROR, + C_SILENT, ++ C_SIGNATURE_HASHES, + C_SOCKS4, + C_SOCKS4A, + C_SOCKS5, +@@ -312,6 +322,10 @@ typedef enum { + C_TFTP_NO_OPTIONS, + C_TIME_COND, + C_TLS_MAX, ++ C_TLS_SESSION_TICKET, ++ C_TLS_EXTENSION_ORDER, ++ C_TLS_PERMUTE_EXTENSIONS, ++ C_TLS_GREASE, + C_TLS13_CIPHERS, + C_TLSAUTHTYPE, + C_TLSPASSWORD, +@@ -358,6 +372,7 @@ struct LongShort { + static const struct LongShort aliases[]= { + {"abstract-unix-socket", ARG_FILE, ' ', C_ABSTRACT_UNIX_SOCKET}, + {"alpn", ARG_BOOL, ' ', C_ALPN}, ++ {"alps", ARG_BOOL, ' ', C_ALPS}, // curl-impersonate + {"alt-svc", ARG_STRG, ' ', C_ALT_SVC}, + {"anyauth", ARG_BOOL, ' ', C_ANYAUTH}, + {"append", ARG_BOOL, 'a', C_APPEND}, +@@ -368,6 +383,7 @@ static const struct LongShort aliases[]= { + {"cacert", ARG_FILE, ' ', C_CACERT}, + {"capath", ARG_FILE, ' ', C_CAPATH}, + {"cert", ARG_FILE, 'E', C_CERT}, ++ {"cert-compression", ARG_STRG, ' ', C_CERT_COMPRESSION}, // curl-impersonate + {"cert-status", ARG_BOOL, ' ', C_CERT_STATUS}, + {"cert-type", ARG_STRG, ' ', C_CERT_TYPE}, + {"ciphers", ARG_STRG, ' ', C_CIPHERS}, +@@ -404,6 +420,9 @@ static const struct LongShort aliases[]= { + {"doh-insecure", ARG_BOOL, ' ', C_DOH_INSECURE}, + {"doh-url" , ARG_STRG, ' ', C_DOH_URL}, + {"dump-header", ARG_FILE, 'D', C_DUMP_HEADER}, +#ifdef USE_ECH -+ {"ER", "ech", ARG_STRING}, ++ {"ech", ARG_STRG, ' ', C_ECH}, // curl-impersonate +#endif -+ {"EV", "http2-streams", ARG_STRING}, -+ {"EW", "tls-extension-order", ARG_STRING}, -+ {"EX", "tls-grease", ARG_BOOL}, - {"f", "fail", ARG_BOOL}, - {"fa", "fail-early", ARG_BOOL}, - {"fb", "styled-output", ARG_BOOL}, -@@ -2124,6 +2138,78 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ - GetStr(&config->ssl_ec_curves, nextarg); - break; - -+ case 'T': -+ /* --signature-hashes */ -+ GetStr(&config->ssl_sig_hash_algs, nextarg); -+ break; -+ -+ case 'U': -+ /* --alps */ -+ config->alps = toggle; -+ break; -+ -+ case 'I': -+ /* --cert-compression */ -+ GetStr(&config->ssl_cert_compression, nextarg); -+ break; -+ -+ case 'J': -+ /* --tls-session-ticket */ -+ config->noticket = (!toggle)?TRUE:FALSE; -+ break; -+ -+ case 'K': -+ /* --http2-pseudo-headers-order */ -+ GetStr(&config->http2_pseudo_headers_order, nextarg); -+ break; -+ -+ case 'L': -+ /* --http2-settings */ -+ GetStr(&config->http2_settings, nextarg); -+ break; -+ -+ case 'M': -+ /* --tls-permute-extensions */ -+ config->ssl_permute_extensions = toggle; -+ break; -+ -+ case 'N': -+ /* --http2-window-update */ -+ err = str2num(&config->http2_window_update, nextarg); -+ if(err) -+ return err; -+ if(config->http2_window_update < -1) -+ return PARAM_BAD_NUMERIC; -+ break; -+ -+ case 'V': -+ /* --http2-streams */ -+ GetStr(&config->http2_streams, nextarg); -+ break; -+ -+ case 'W': -+ /* --tls-extension-order */ -+ GetStr(&config->tls_extension_order, nextarg); -+ // printf("setting is %s\n", config->tls_extension_order); -+ break; -+ -+ case 'X': -+ /* --tls-grease */ -+ config->tls_grease = toggle; -+ break; -+ + {"egd-file", ARG_STRG, ' ', C_EGD_FILE}, + {"engine", ARG_STRG, ' ', C_ENGINE}, + {"eprt", ARG_BOOL, ' ', C_EPRT}, +@@ -447,6 +466,12 @@ static const struct LongShort aliases[]= { + {"http1.1", ARG_NONE, ' ', C_HTTP1_1}, + {"http2", ARG_NONE, ' ', C_HTTP2}, + {"http2-prior-knowledge", ARG_NONE, ' ', C_HTTP2_PRIOR_KNOWLEDGE}, ++ {"http2-pseudo-headers-order", ARG_STRG, ' ', C_HTTP2_PSEUDO_HEADERS_ORDER}, // curl-impersonate ++ {"http2-settings", ARG_STRG, ' ', C_HTTP2_SETTINGS}, // curl-impersonate ++ {"http2-stream-exclusive", ARG_STRG, ' ', C_HTTP2_STREAM_EXCLUSIVE}, // curl-impersonate ++ {"http2-stream-weight", ARG_STRG, ' ', C_HTTP2_STREAM_WEIGHT}, // curl-impersonate ++ {"http2-streams", ARG_STRG, ' ', C_HTTP2_STREAMS}, // curl-impersonate ++ {"http2-window-update", ARG_STRG, ' ', C_HTTP2_WINDOW_UPDATE}, // curl-impersonate + {"http3", ARG_NONE, ' ', C_HTTP3}, + {"http3-only", ARG_NONE, ' ', C_HTTP3_ONLY}, + {"ignore-content-length", ARG_BOOL, ' ', C_IGNORE_CONTENT_LENGTH}, +@@ -563,6 +588,7 @@ static const struct LongShort aliases[]= { + {"service-name", ARG_STRG, ' ', C_SERVICE_NAME}, + {"sessionid", ARG_BOOL, ' ', C_SESSIONID}, + {"show-error", ARG_BOOL, 'S', C_SHOW_ERROR}, ++ {"signature-hashes", ARG_STRG, ' ', C_SIGNATURE_HASHES}, // curl-impersonate + {"silent", ARG_BOOL, 's', C_SILENT}, + {"socks4", ARG_STRG, ' ', C_SOCKS4}, + {"socks4a", ARG_STRG, ' ', C_SOCKS4A}, +@@ -592,7 +618,11 @@ static const struct LongShort aliases[]= { + {"tftp-blksize", ARG_STRG, ' ', C_TFTP_BLKSIZE}, + {"tftp-no-options", ARG_BOOL, ' ', C_TFTP_NO_OPTIONS}, + {"time-cond", ARG_STRG, 'z', C_TIME_COND}, ++ {"tls-extension-order", ARG_STRG, ' ', C_TLS_EXTENSION_ORDER}, // curl-impersonate ++ {"tls-grease", ARG_BOOL, ' ', C_TLS_GREASE}, // curl-impersonate + {"tls-max", ARG_STRG, ' ', C_TLS_MAX}, ++ {"tls-permute-extensions", ARG_BOOL, ' ', C_TLS_PERMUTE_EXTENSIONS}, // curl-impersonate ++ {"tls-session-ticket", ARG_BOOL, ' ', C_TLS_SESSION_TICKET}, // curl-impersonate + {"tls13-ciphers", ARG_STRG, ' ', C_TLS13_CIPHERS}, + {"tlsauthtype", ARG_STRG, ' ', C_TLSAUTHTYPE}, + {"tlspassword", ARG_STRG, ' ', C_TLSPASSWORD}, +@@ -1434,6 +1464,9 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ + case C_ALPN: /* --alpn */ + config->noalpn = (!toggle)?TRUE:FALSE; + break; ++ case C_ALPS: /* --alps curl-impersonate */ ++ config->alps = toggle; ++ break; + case C_LIMIT_RATE: /* --limit-rate */ + err = GetSizeParameter(global, nextarg, "rate", &value); + if(!err) { +@@ -1865,6 +1898,18 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ + case C_TLS_MAX: /* --tls-max */ + err = str2tls_max(&config->ssl_version_max, nextarg); + break; ++ case C_TLS_SESSION_TICKET: /* --tls-session-ticket curl-impersonate */ ++ config->noticket = (!toggle)?TRUE:FALSE; ++ break; ++ case C_TLS_PERMUTE_EXTENSIONS: /* --tls-permute-extensions curl-impersonate */ ++ config->ssl_permute_extensions = toggle; ++ break; ++ case C_TLS_EXTENSION_ORDER: /* --tls-extension-order curl-impersonate */ ++ err = getstr(&config->tls_extension_order, nextarg, ALLOW_BLANK); ++ break; ++ case C_TLS_GREASE: /* --tls-grease curl-impersonate */ ++ config->tls_grease = toggle; ++ break; + case C_SUPPRESS_CONNECT_HEADERS: /* --suppress-connect-headers */ + config->suppress_connect_headers = toggle; + break; +@@ -1914,6 +1959,39 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ + return PARAM_LIBCURL_DOESNT_SUPPORT; + sethttpver(global, config, CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE); + break; ++ case C_HTTP2_PSEUDO_HEADERS_ORDER: /* --http2-pseudo-headers-order curl-impersonate */ ++ if(!feature_http2) ++ return PARAM_LIBCURL_DOESNT_SUPPORT; ++ err = getstr(&config->http2_pseudo_headers_order, nextarg, ALLOW_BLANK); ++ break; ++ case C_HTTP2_SETTINGS: /* --http2-settings curl-impersonate */ ++ if(!feature_http2) ++ return PARAM_LIBCURL_DOESNT_SUPPORT; ++ err = getstr(&config->http2_settings, nextarg, ALLOW_BLANK); ++ break; ++ case C_HTTP2_STREAM_EXCLUSIVE: ++ if(!feature_http2) ++ return PARAM_LIBCURL_DOESNT_SUPPORT; ++ err = str2num(&config->http2_stream_exclusive, nextarg); ++ if(config->http2_stream_exclusive < 0) return PARAM_BAD_NUMERIC; ++ break; ++ case C_HTTP2_STREAM_WEIGHT: ++ if(!feature_http2) ++ return PARAM_LIBCURL_DOESNT_SUPPORT; ++ err = str2num(&config->http2_stream_weight, nextarg); ++ if(config->http2_stream_weight < 0) return PARAM_BAD_NUMERIC; ++ break; ++ case C_HTTP2_WINDOW_UPDATE: /* --http2-window-update curl-impersonate */ ++ if(!feature_http2) ++ return PARAM_LIBCURL_DOESNT_SUPPORT; ++ err = str2num(&config->http2_window_update, nextarg); ++ if(config->http2_window_update < -1) return PARAM_BAD_NUMERIC; ++ break; ++ case C_HTTP2_STREAMS: /* --http2-streams curl-impersonate */ ++ if(!feature_http2) ++ return PARAM_LIBCURL_DOESNT_SUPPORT; ++ err = getstr(&config->http2_streams, nextarg, ALLOW_BLANK); ++ break; + case C_HTTP3: /* --http3: */ + /* Try HTTP/3, allow fallback */ + if(!feature_http3) +@@ -2033,6 +2111,18 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ + case C_DUMP_HEADER: /* --dump-header */ + err = getstr(&config->headerfile, nextarg, DENY_BLANK); + break; +#ifdef USE_ECH -+ case 'R': -+ if(strlen(nextarg) != 6 || !strncasecompare("GREASE", nextarg, 6)) { -+ warnf(global, "Only GREASE is supported for --ech."); -+ return PARAM_BAD_USE; /* */ -+ } -+ else { -+ /* Simple case: just a string, with a keyword */ -+ GetStr(&config->ech, nextarg); -+ } -+ break; ++ case C_ECH: /* --ech curl-impersonate */ ++ if(strlen(nextarg) != 6 || !strncasecompare("GREASE", nextarg, 6)) { ++ warnf(global, "Only GREASE is supported for --ech."); ++ return PARAM_BAD_USE; /* */ ++ } ++ else { ++ /* Simple case: just a string, with a keyword */ ++ getstr(&config->ech, nextarg, ALLOW_BLANK); ++ } ++ break; +#endif - default: /* unknown flag */ - err = PARAM_OPTION_UNKNOWN; - break; + case C_REFERER: { /* --referer */ + char *ptr = strstr(nextarg, ";auto"); + if(ptr) { +@@ -2051,6 +2141,9 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ + cleanarg(clearthis); + GetFileAndPassword(nextarg, &config->cert, &config->key_passwd); + break; ++ case C_CERT_COMPRESSION: /* --cert-compression curl-impersonate */ ++ err = getstr(&config->ssl_cert_compression, nextarg, ALLOW_BLANK); ++ break; + case C_CACERT: /* --cacert */ + err = getstr(&config->cacert, nextarg, DENY_BLANK); + break; +@@ -2555,6 +2648,9 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ + case C_SILENT: /* --silent */ + global->silent = toggle; + break; ++ case C_SIGNATURE_HASHES: /* --signature-hashes */ ++ err = getstr(&config->ssl_sig_hash_algs, nextarg, ALLOW_BLANK); ++ break; + case C_SHOW_ERROR: /* --show-error */ + global->showerror = toggle; + break; diff --git a/src/tool_listhelp.c b/src/tool_listhelp.c -index 4e7a6dd63..8093b7f8e 100644 +index 5d9364405..f346f8e0c 100644 --- a/src/tool_listhelp.c +++ b/src/tool_listhelp.c @@ -111,6 +111,27 @@ const struct helptxt helptext[] = { - {" --curves ", - "(EC) TLS key exchange algorithm(s) to request", + {" --curves ", + "(EC) TLS key exchange algorithms to request", CURLHELP_TLS}, + {" --signature-hashes ", + "TLS signature hash algorithm(s) to use", @@ -3852,10 +4119,10 @@ index 4e7a6dd63..8093b7f8e 100644 "Disable buffering of the output stream", CURLHELP_CURL}, diff --git a/src/tool_operate.c b/src/tool_operate.c -index c805b7732..4f948b09c 100644 +index 7e2c1eefe..24b74d180 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c -@@ -1522,6 +1522,26 @@ static CURLcode single_transfer(struct GlobalConfig *global, +@@ -1510,6 +1510,36 @@ static CURLcode single_transfer(struct GlobalConfig *global, return result; } @@ -3874,6 +4141,16 @@ index c805b7732..4f948b09c 100644 + CURLOPT_HTTP2_WINDOW_UPDATE, + config->http2_window_update); + ++ if(config->http2_stream_exclusive) ++ my_setopt(curl, ++ CURLOPT_STREAM_EXCLUSIVE, ++ config->http2_stream_exclusive); ++ ++ if(config->http2_stream_weight) ++ my_setopt(curl, ++ CURLOPT_STREAM_WEIGHT, ++ config->http2_stream_weight); ++ + if(config->http2_streams) + my_setopt_str(curl, + CURLOPT_HTTP2_STREAMS, @@ -3882,7 +4159,7 @@ index c805b7732..4f948b09c 100644 } /* (proto_http) */ if(proto_ftp) -@@ -1610,6 +1630,14 @@ static CURLcode single_transfer(struct GlobalConfig *global, +@@ -1598,6 +1628,14 @@ static CURLcode single_transfer(struct GlobalConfig *global, if(config->ssl_ec_curves) my_setopt_str(curl, CURLOPT_SSL_EC_CURVES, config->ssl_ec_curves); @@ -3897,7 +4174,7 @@ index c805b7732..4f948b09c 100644 if(config->writeout) my_setopt_str(curl, CURLOPT_CERTINFO, 1L); -@@ -1942,6 +1970,19 @@ static CURLcode single_transfer(struct GlobalConfig *global, +@@ -1930,6 +1968,19 @@ static CURLcode single_transfer(struct GlobalConfig *global, my_setopt_str(curl, CURLOPT_PROXY_TLS13_CIPHERS, config->proxy_cipher13_list); @@ -3917,7 +4194,7 @@ index c805b7732..4f948b09c 100644 /* new in libcurl 7.9.2: */ if(config->disable_epsv) /* disable it */ -@@ -2151,6 +2192,14 @@ static CURLcode single_transfer(struct GlobalConfig *global, +@@ -2139,6 +2190,14 @@ static CURLcode single_transfer(struct GlobalConfig *global, my_setopt(curl, CURLOPT_SSL_ENABLE_ALPN, 0L); } @@ -3932,7 +4209,7 @@ index c805b7732..4f948b09c 100644 /* new in 7.40.0, abstract support added in 7.53.0 */ if(config->unix_socket_path) { if(config->abstract_unix_socket) { -@@ -2199,6 +2248,16 @@ static CURLcode single_transfer(struct GlobalConfig *global, +@@ -2187,6 +2246,16 @@ static CURLcode single_transfer(struct GlobalConfig *global, if(config->hsts) my_setopt_str(curl, CURLOPT_HSTS, config->hsts); @@ -3950,10 +4227,10 @@ index c805b7732..4f948b09c 100644 per->retry_sleep_default = (config->retry_delay) ? config->retry_delay*1000L : RETRY_SLEEP_DEFAULT; /* ms */ diff --git a/src/tool_setopt.c b/src/tool_setopt.c -index de3b78fab..e034c9848 100644 +index 656adbda8..638d427e2 100644 --- a/src/tool_setopt.c +++ b/src/tool_setopt.c -@@ -153,6 +153,8 @@ static const struct NameValue setopt_nv_CURLNONZERODEFAULTS[] = { +@@ -163,6 +163,8 @@ static const struct NameValue setopt_nv_CURLNONZERODEFAULTS[] = { NV1(CURLOPT_SSL_VERIFYHOST, 1), NV1(CURLOPT_SSL_ENABLE_NPN, 1), NV1(CURLOPT_SSL_ENABLE_ALPN, 1), @@ -3962,3 +4239,100 @@ index de3b78fab..e034c9848 100644 NV1(CURLOPT_TCP_NODELAY, 1), NV1(CURLOPT_PROXY_SSL_VERIFYPEER, 1), NV1(CURLOPT_PROXY_SSL_VERIFYHOST, 1), +diff --git a/tests/http/test_02_download.py b/tests/http/test_02_download.py +index 4db9c9d36..395fc862f 100644 +--- a/tests/http/test_02_download.py ++++ b/tests/http/test_02_download.py +@@ -394,6 +394,19 @@ class TestDownload: + r = client.run(args=[url]) + r.check_exit_code(0) + ++ @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) ++ def test_02_28_get_compressed(self, env: Env, httpd, nghttpx, repeat, proto): ++ if proto == 'h3' and not env.have_h3(): ++ pytest.skip("h3 not supported") ++ count = 1 ++ urln = f'https://{env.authority_for(env.domain1brotli, proto)}/data-100k?[0-{count-1}]' ++ curl = CurlClient(env=env) ++ r = curl.http_download(urls=[urln], alpn_proto=proto, extra_args=[ ++ '--compressed' ++ ]) ++ r.check_exit_code(code=0) ++ r.check_response(count=count, http_status=200) ++ + def check_downloads(self, client, srcfile: str, count: int, + complete: bool = True): + for i in range(count): +diff --git a/tests/http/testenv/env.py b/tests/http/testenv/env.py +index a207059dc..13c5d6bd4 100644 +--- a/tests/http/testenv/env.py ++++ b/tests/http/testenv/env.py +@@ -129,10 +129,11 @@ class EnvConfig: + self.htdocs_dir = os.path.join(self.gen_dir, 'htdocs') + self.tld = 'http.curl.se' + self.domain1 = f"one.{self.tld}" ++ self.domain1brotli = f"brotli.one.{self.tld}" + self.domain2 = f"two.{self.tld}" + self.proxy_domain = f"proxy.{self.tld}" + self.cert_specs = [ +- CertificateSpec(domains=[self.domain1, 'localhost'], key_type='rsa2048'), ++ CertificateSpec(domains=[self.domain1, self.domain1brotli, 'localhost'], key_type='rsa2048'), + CertificateSpec(domains=[self.domain2], key_type='rsa2048'), + CertificateSpec(domains=[self.proxy_domain, '127.0.0.1'], key_type='rsa2048'), + CertificateSpec(name="clientsX", sub_specs=[ +@@ -376,6 +377,10 @@ class Env: + def domain1(self) -> str: + return self.CONFIG.domain1 + ++ @property ++ def domain1brotli(self) -> str: ++ return self.CONFIG.domain1brotli ++ + @property + def domain2(self) -> str: + return self.CONFIG.domain2 +diff --git a/tests/http/testenv/httpd.py b/tests/http/testenv/httpd.py +index c04c22699..b8615875a 100644 +--- a/tests/http/testenv/httpd.py ++++ b/tests/http/testenv/httpd.py +@@ -50,6 +50,7 @@ class Httpd: + 'alias', 'env', 'filter', 'headers', 'mime', 'setenvif', + 'socache_shmcb', + 'rewrite', 'http2', 'ssl', 'proxy', 'proxy_http', 'proxy_connect', ++ 'brotli', + 'mpm_event', + ] + COMMON_MODULES_DIRS = [ +@@ -203,6 +204,7 @@ class Httpd: + + def _write_config(self): + domain1 = self.env.domain1 ++ domain1brotli = self.env.domain1brotli + creds1 = self.env.get_credentials(domain1) + domain2 = self.env.domain2 + creds2 = self.env.get_credentials(domain2) +@@ -285,6 +287,24 @@ class Httpd: + f'', + f'', + ]) ++ # Alternate to domain1 with BROTLI compression ++ conf.extend([ # https host for domain1, h1 + h2 ++ f'', ++ f' ServerName {domain1brotli}', ++ f' Protocols h2 http/1.1', ++ f' SSLEngine on', ++ f' SSLCertificateFile {creds1.cert_file}', ++ f' SSLCertificateKeyFile {creds1.pkey_file}', ++ f' DocumentRoot "{self._docs_dir}"', ++ f' SetOutputFilter BROTLI_COMPRESS', ++ ]) ++ conf.extend(self._curltest_conf(domain1)) ++ if domain1 in self._extra_configs: ++ conf.extend(self._extra_configs[domain1]) ++ conf.extend([ ++ f'', ++ f'', ++ ]) + conf.extend([ # https host for domain2, no h2 + f'', + f' ServerName {domain2}', diff --git a/configure.ac b/configure.ac index e1b79b28..f55f66e5 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT([curl-impersonate], [0.7.0], [lwt@lwthiker.com]) +AC_INIT([curl-impersonate], [0.7.0], [lwt@lwthiker.com, kong@yifei.me]) AC_CANONICAL_BUILD AC_CANONICAL_HOST diff --git a/docker/alpine.dockerfile b/docker/alpine.dockerfile index ba33647a..c3b17126 100644 --- a/docker/alpine.dockerfile +++ b/docker/alpine.dockerfile @@ -22,7 +22,7 @@ RUN apk add autoconf automake pkgconfig libtool RUN apk add g++ go unzip # Download and compile libbrotli -ARG BROTLI_VERSION=1.0.9 +ARG BROTLI_VERSION=1.1.0 RUN curl -L https://github.com/google/brotli/archive/refs/tags/v${BROTLI_VERSION}.tar.gz -o brotli-${BROTLI_VERSION}.tar.gz && \ tar xf brotli-${BROTLI_VERSION}.tar.gz RUN cd brotli-${BROTLI_VERSION} && \ @@ -55,8 +55,8 @@ RUN mkdir boringssl/build/lib && \ ln -s ../ssl/libssl.a boringssl/build/lib/libssl.a && \ cp -R boringssl/include boringssl/build -ARG NGHTTP2_VERSION=nghttp2-1.56.0 -ARG NGHTTP2_URL=https://github.com/nghttp2/nghttp2/releases/download/v1.56.0/nghttp2-1.56.0.tar.bz2 +ARG NGHTTP2_VERSION=nghttp2-1.61.0 +ARG NGHTTP2_URL=https://github.com/nghttp2/nghttp2/releases/download/v1.61.0/nghttp2-1.61.0.tar.bz2 # Download nghttp2 for HTTP/2.0 support. RUN curl -o ${NGHTTP2_VERSION}.tar.bz2 -L ${NGHTTP2_URL} @@ -68,7 +68,7 @@ RUN cd ${NGHTTP2_VERSION} && \ make && make install # Download curl. -ARG CURL_VERSION=curl-8.5.0 +ARG CURL_VERSION=curl-8.7.1 RUN curl -o ${CURL_VERSION}.tar.xz https://curl.se/download/${CURL_VERSION}.tar.xz RUN tar xf ${CURL_VERSION}.tar.xz diff --git a/docker/debian.dockerfile b/docker/debian.dockerfile index 6feab202..260ed308 100644 --- a/docker/debian.dockerfile +++ b/docker/debian.dockerfile @@ -28,7 +28,7 @@ RUN apt-get install -y xz-utils RUN apt-get install -y g++ golang-go unzip # Download and compile libbrotli -ARG BROTLI_VERSION=1.0.9 +ARG BROTLI_VERSION=1.1.0 RUN curl -L https://github.com/google/brotli/archive/refs/tags/v${BROTLI_VERSION}.tar.gz -o brotli-${BROTLI_VERSION}.tar.gz && \ tar xf brotli-${BROTLI_VERSION}.tar.gz RUN cd brotli-${BROTLI_VERSION} && \ @@ -61,8 +61,8 @@ RUN mkdir boringssl/build/lib && \ ln -s ../ssl/libssl.a boringssl/build/lib/libssl.a && \ cp -R boringssl/include boringssl/build -ARG NGHTTP2_VERSION=nghttp2-1.56.0 -ARG NGHTTP2_URL=https://github.com/nghttp2/nghttp2/releases/download/v1.56.0/nghttp2-1.56.0.tar.bz2 +ARG NGHTTP2_VERSION=nghttp2-1.61.0 +ARG NGHTTP2_URL=https://github.com/nghttp2/nghttp2/releases/download/v1.61.0/nghttp2-1.61.0.tar.bz2 # Download nghttp2 for HTTP/2.0 support. RUN curl -o ${NGHTTP2_VERSION}.tar.bz2 -L ${NGHTTP2_URL} @@ -74,7 +74,7 @@ RUN cd ${NGHTTP2_VERSION} && \ make && make install # Download curl. -ARG CURL_VERSION=curl-8.5.0 +ARG CURL_VERSION=curl-8.7.1 RUN curl -o ${CURL_VERSION}.tar.xz https://curl.se/download/${CURL_VERSION}.tar.xz RUN tar xf ${CURL_VERSION}.tar.xz diff --git a/docker/dockerfile.mustache b/docker/dockerfile.mustache index d8eae9af..f9ea67c3 100644 --- a/docker/dockerfile.mustache +++ b/docker/dockerfile.mustache @@ -53,7 +53,7 @@ RUN apk add g++ go unzip {{/alpine}} # Download and compile libbrotli -ARG BROTLI_VERSION=1.0.9 +ARG BROTLI_VERSION=1.1.0 RUN curl -L https://github.com/google/brotli/archive/refs/tags/v${BROTLI_VERSION}.tar.gz -o brotli-${BROTLI_VERSION}.tar.gz && \ tar xf brotli-${BROTLI_VERSION}.tar.gz RUN cd brotli-${BROTLI_VERSION} && \ @@ -86,8 +86,8 @@ RUN mkdir boringssl/build/lib && \ ln -s ../ssl/libssl.a boringssl/build/lib/libssl.a && \ cp -R boringssl/include boringssl/build -ARG NGHTTP2_VERSION=nghttp2-1.56.0 -ARG NGHTTP2_URL=https://github.com/nghttp2/nghttp2/releases/download/v1.56.0/nghttp2-1.56.0.tar.bz2 +ARG NGHTTP2_VERSION=nghttp2-1.61.0 +ARG NGHTTP2_URL=https://github.com/nghttp2/nghttp2/releases/download/v1.61.0/nghttp2-1.61.0.tar.bz2 # Download nghttp2 for HTTP/2.0 support. RUN curl -o ${NGHTTP2_VERSION}.tar.bz2 -L ${NGHTTP2_URL} @@ -99,7 +99,7 @@ RUN cd ${NGHTTP2_VERSION} && \ make && make install # Download curl. -ARG CURL_VERSION=curl-8.5.0 +ARG CURL_VERSION=curl-8.7.1 RUN curl -o ${CURL_VERSION}.tar.xz https://curl.se/download/${CURL_VERSION}.tar.xz RUN tar xf ${CURL_VERSION}.tar.xz diff --git a/docs/03_LIBCURL_IMPERSONATE_PYTHON.md b/docs/03_LIBCURL_IMPERSONATE_PYTHON.md index d0c0de36..d181ff50 100644 --- a/docs/03_LIBCURL_IMPERSONATE_PYTHON.md +++ b/docs/03_LIBCURL_IMPERSONATE_PYTHON.md @@ -1,4 +1,4 @@ # Using libcurl-impersonate in Python scripts -You can use the Python binding [curl_cffi](https://github.com:yifeikong/curl_cffi), which works on Linux, macOS and Windows. +You can use the Python binding [curl_cffi](https://github.com/yifeikong/curl_cffi), which works on Linux, macOS and Windows. diff --git a/win/build.sh b/win/build.sh index 5e23d81a..3d326a8e 100644 --- a/win/build.sh +++ b/win/build.sh @@ -2,7 +2,7 @@ set -ex -mkdir build/ +mkdir -p build/ cd build/ # Download and patch boringssl @@ -33,12 +33,13 @@ export BROTLI_LIBS='-lbrotlidec -lbrotlicommon' export NGHTTP2_PATH=nghttp2_stub export LIBIDN2_PATH=idn2_stub export SSL=1 +export SSL_PATH=$PWD/boringssl export OPENSSL_PATH=$PWD/boringssl export OPENSSL_LIBPATH=$PWD/boringssl/lib export OPENSSL_LIBS='-lssl -lcrypto' -CURL_VERSION=curl-8_5_0 +CURL_VERSION=curl-8_7_1 curl -L https://github.com/curl/curl/archive/${CURL_VERSION}.zip -o curl.zip unzip -q -o curl.zip @@ -52,21 +53,50 @@ cd curl patchfile=../../chrome/patches/curl-impersonate.patch patch -p1 < $patchfile -sed -i 's/-shared/-s -static -shared/g' lib/Makefile.mk -sed -i 's/-static/-s -static/g' src/Makefile.mk - -sed -i 's/-DUSE_NGHTTP2/-DUSE_NGHTTP2 -DNGHTTP2_STATICLIB/g' lib/Makefile.mk -sed -i 's/-DUSE_NGHTTP2/-DUSE_NGHTTP2 -DNGHTTP2_STATICLIB/g' src/Makefile.mk +# sed -i 's/-shared/-s -static -shared/g' lib/Makefile.mk +# sed -i 's/-static/-s -static/g' src/Makefile.mk +# +# sed -i 's/-DUSE_NGHTTP2/-DUSE_NGHTTP2 -DNGHTTP2_STATICLIB/g' lib/Makefile.mk +# sed -i 's/-DUSE_NGHTTP2/-DUSE_NGHTTP2 -DNGHTTP2_STATICLIB/g' src/Makefile.mk sed -i 's/-lidn2/-lidn2 -lunistring -liconv/g' lib/Makefile.mk sed -i 's/-lidn2/-lidn2 -lunistring -liconv/g' src/Makefile.mk -mingw32-make -f Makefile.dist mingw32-clean -mingw32-make -f Makefile.dist mingw32 -j CFLAGS="-DUSE_HTTP2=1 -DUSE_WEBSOCKETS=1 -DUSE_ECH=1 -Wno-unused-variable" CFG=-ssl-zlib-nghttp2-idn2-brotli-zstd-ipv6 +# print all options +cmake -LAH + +cmake -B build -G "MinGW Makefiles" \ + -DSSL_PATH=$PWD/boringssl \ + -DOPENSSL_LIBS='-lssl -lcrypto' \ + -DENABLE_IPV6=ON \ + -DENABLE_UNICODE=ON \ + -DUSE_NGHTTP2=ON \ + -DENABLE_WEBSOCKETS=ON \ + -DCURL_BROTLI=ON \ + -DCURL_ZLIB=ON \ + -DCURL_ZSTD=ON \ + -DENABLE_IPV6=ON \ + -DCURL_ENABLE_SSL=ON \ + -DCURL_USE_OPENSSL=ON \ + -DHAVE_BORINGSSL=1 \ + -DUSE_ECH=ON \ + -DHAVE_ECH=ON \ + -DBUILD_STATIC_CURL=ON \ + -DBUILD_STATIC_LIBS=ON \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_C_FLAGS=-Wno-unused-variable \ + +cd build + +mingw32-make clean +mingw32-make -j CFLAGS="-Wno-unused-variable" CFG=-ssl-zlib-nghttp2-idn2-brotli-zstd-ipv6 + +cd .. mkdir -p ../dist -mv lib/libcurl* ../dist/ -mv src/*.exe ../dist/ +ls build +mv build/lib/libcurl* ../dist/ +mv build/src/*.exe ../dist/ cd .. -dist/curl -V +dist/curl.exe -V