From d48a5723440b23b16efeb61f0f67c5d64c996f77 Mon Sep 17 00:00:00 2001 From: lwthiker <99899249+lwthiker@users.noreply.github.com> Date: Fri, 15 Sep 2023 17:46:02 +0300 Subject: [PATCH] Upgrade baseline curl to 8.1.1 (#160) * Upgrade baseline curl to 8.1.1 New curl version includes bugfixes, new options but mainly websocket support which was long requested in curl impersonate. Upstream curl reworked a lot of their http2 code which necessitated a lot of changes on our side as well. * Fix build on mac due to bad header priorities On macos, clang gives priority to /usr/local/include over locations specified with -isystem for some unknown reason. In turn this causes clang to use the system's openssl, which conflicts with curl-impersonate's boringssl headers. To prevent that, disable curl's automatic conversion of -I flags to -isystem. * Upgrade zlib version * Upgrade GitHub Mac runner to macos-12 * Upgrade nghttp2 version to 1.56.0 curl-8.1.1 uses an nghttp2 function that only exists in newer versions of nghttp2. --- .github/workflows/build-and-test-make.yml | 14 +- Dockerfile.template | 6 +- Makefile.in | 9 +- chrome/Dockerfile | 6 +- chrome/Dockerfile.alpine | 6 +- chrome/curl_chrome100 | 2 +- chrome/curl_chrome101 | 2 +- chrome/curl_chrome104 | 2 +- chrome/curl_chrome107 | 2 +- chrome/curl_chrome110 | 2 +- chrome/curl_chrome99 | 2 +- chrome/curl_chrome99_android | 2 +- chrome/curl_edge101 | 2 +- chrome/curl_edge99 | 2 +- chrome/curl_safari15_3 | 2 +- chrome/curl_safari15_5 | 2 +- chrome/patches/curl-impersonate.patch | 1161 ++++++++++++--------- firefox/Dockerfile | 6 +- firefox/Dockerfile.alpine | 6 +- firefox/patches/curl-impersonate.patch | 634 +++++------ 20 files changed, 1064 insertions(+), 806 deletions(-) diff --git a/.github/workflows/build-and-test-make.yml b/.github/workflows/build-and-test-make.yml index 80dc1a1..6dacdf2 100644 --- a/.github/workflows/build-and-test-make.yml +++ b/.github/workflows/build-and-test-make.yml @@ -20,7 +20,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-20.04, macos-11] + os: [ubuntu-20.04, macos-12] arch: [x86_64] include: - os: ubuntu-20.04 @@ -38,7 +38,7 @@ jobs: host: arm-linux-gnueabihf capture_interface: eth0 make: make - - os: macos-11 + - os: macos-12 arch: x86_64 host: x86_64-macos capture_interface: en0 @@ -66,7 +66,7 @@ jobs: sudo apt-get install gcc-${{ matrix.host }} g++-${{ matrix.host }} - name: Install macOS dependencies - if: matrix.os == 'macos-11' + if: matrix.os == 'macos-12' run: | brew install pkg-config make cmake ninja autoconf automake libtool # Chrome version dependencies @@ -92,9 +92,9 @@ jobs: # When cross compiling we need to build zlib first. - name: Build zlib run: | - curl -LO https://zlib.net/zlib-1.2.13.tar.gz - tar xf zlib-1.2.13.tar.gz - cd zlib-1.2.13 + curl -LO https://zlib.net/zlib-1.3.tar.gz + tar xf zlib-1.3.tar.gz + cd zlib-1.3 CHOST=${{ matrix.host }} ./configure --prefix=${{ runner.temp }}/zlib make make install @@ -255,4 +255,4 @@ jobs: with: files: | ${{ env.release_file_lib }} - ${{ env.release_file_bin }} \ No newline at end of file + ${{ env.release_file_bin }} diff --git a/Dockerfile.template b/Dockerfile.template index 06a0da6..c33cc3b 100644 --- a/Dockerfile.template +++ b/Dockerfile.template @@ -109,8 +109,8 @@ RUN mkdir boringssl/build/lib && \ cp -R boringssl/include boringssl/build {{/chrome}} -ARG NGHTTP2_VERSION=nghttp2-1.46.0 -ARG NGHTTP2_URL=https://github.com/nghttp2/nghttp2/releases/download/v1.46.0/nghttp2-1.46.0.tar.bz2 +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 # Download nghttp2 for HTTP/2.0 support. RUN curl -o ${NGHTTP2_VERSION}.tar.bz2 -L ${NGHTTP2_URL} @@ -122,7 +122,7 @@ RUN cd ${NGHTTP2_VERSION} && \ make && make install # Download curl. -ARG CURL_VERSION=curl-7.84.0 +ARG CURL_VERSION=curl-8.1.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/Makefile.in b/Makefile.in index d54f34f..b27e5be 100644 --- a/Makefile.in +++ b/Makefile.in @@ -14,9 +14,9 @@ NSS_VERSION := nss-3.87 NSS_URL := https://ftp.mozilla.org/pub/security/nss/releases/NSS_3_87_RTM/src/nss-3.87-with-nspr-4.35.tar.gz # In case this is changed, update build-and-test-make.yml as well BORING_SSL_COMMIT := 3a667d10e94186fd503966f5638e134fe9fb4080 -NGHTTP2_VERSION := nghttp2-1.46.0 -NGHTTP2_URL := https://github.com/nghttp2/nghttp2/releases/download/v1.46.0/nghttp2-1.46.0.tar.bz2 -CURL_VERSION := curl-7.84.0 +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.1.1 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 @@ -423,12 +423,11 @@ $(CURL_VERSION)/.chrome: $(chrome_libs) $(CURL_VERSION).tar.xz $(CURL_VERSION)/. config_flags="$$config_flags --with-ca-path=$(with_ca_path)"; \ fi; \ add_libs="-pthread"; \ - add_cflags="-I$(boringssl_install_dir)"; \ } echo "Configuring curl with: $$config_flags" - ./configure $$config_flags CFLAGS="$$add_cflags" LIBS="$$add_libs" + ./configure $$config_flags LIBS="$$add_libs" # Remove possible leftovers from a previous compilation $(MAKE) clean MAKEFLAGS= diff --git a/chrome/Dockerfile b/chrome/Dockerfile index 42275f7..7c749ed 100644 --- a/chrome/Dockerfile +++ b/chrome/Dockerfile @@ -54,8 +54,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.46.0 -ARG NGHTTP2_URL=https://github.com/nghttp2/nghttp2/releases/download/v1.46.0/nghttp2-1.46.0.tar.bz2 +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 # Download nghttp2 for HTTP/2.0 support. RUN curl -o ${NGHTTP2_VERSION}.tar.bz2 -L ${NGHTTP2_URL} @@ -67,7 +67,7 @@ RUN cd ${NGHTTP2_VERSION} && \ make && make install # Download curl. -ARG CURL_VERSION=curl-7.84.0 +ARG CURL_VERSION=curl-8.1.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/chrome/Dockerfile.alpine b/chrome/Dockerfile.alpine index b5004f2..652b6db 100644 --- a/chrome/Dockerfile.alpine +++ b/chrome/Dockerfile.alpine @@ -51,8 +51,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.46.0 -ARG NGHTTP2_URL=https://github.com/nghttp2/nghttp2/releases/download/v1.46.0/nghttp2-1.46.0.tar.bz2 +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 # Download nghttp2 for HTTP/2.0 support. RUN curl -o ${NGHTTP2_VERSION}.tar.bz2 -L ${NGHTTP2_URL} @@ -64,7 +64,7 @@ RUN cd ${NGHTTP2_VERSION} && \ make && make install # Download curl. -ARG CURL_VERSION=curl-7.84.0 +ARG CURL_VERSION=curl-8.1.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/chrome/curl_chrome100 b/chrome/curl_chrome100 index fe82dfb..045aace 100755 --- a/chrome/curl_chrome100 +++ b/chrome/curl_chrome100 @@ -21,6 +21,6 @@ dir=${0%/*} -H 'Accept-Encoding: gzip, deflate, br' \ -H 'Accept-Language: en-US,en;q=0.9' \ --http2 --false-start --compressed \ - --tlsv1.2 --no-npn --alps \ + --tlsv1.2 --alps \ --cert-compression brotli \ "$@" diff --git a/chrome/curl_chrome101 b/chrome/curl_chrome101 index 7073f3a..a0b1855 100755 --- a/chrome/curl_chrome101 +++ b/chrome/curl_chrome101 @@ -21,6 +21,6 @@ dir=${0%/*} -H 'Accept-Encoding: gzip, deflate, br' \ -H 'Accept-Language: en-US,en;q=0.9' \ --http2 --false-start --compressed \ - --tlsv1.2 --no-npn --alps \ + --tlsv1.2 --alps \ --cert-compression brotli \ "$@" diff --git a/chrome/curl_chrome104 b/chrome/curl_chrome104 index 81f25d2..1868e82 100755 --- a/chrome/curl_chrome104 +++ b/chrome/curl_chrome104 @@ -21,6 +21,6 @@ dir=${0%/*} -H 'Accept-Encoding: gzip, deflate, br' \ -H 'Accept-Language: en-US,en;q=0.9' \ --http2 --false-start --compressed \ - --tlsv1.2 --no-npn --alps \ + --tlsv1.2 --alps \ --cert-compression brotli \ "$@" diff --git a/chrome/curl_chrome107 b/chrome/curl_chrome107 index 5c7a9e7..2c6153e 100755 --- a/chrome/curl_chrome107 +++ b/chrome/curl_chrome107 @@ -21,6 +21,6 @@ dir=${0%/*} -H 'Accept-Encoding: gzip, deflate, br' \ -H 'Accept-Language: en-US,en;q=0.9' \ --http2 --http2-no-server-push --false-start --compressed \ - --tlsv1.2 --no-npn --alps \ + --tlsv1.2 --alps \ --cert-compression brotli \ "$@" diff --git a/chrome/curl_chrome110 b/chrome/curl_chrome110 index 23617b5..5887096 100755 --- a/chrome/curl_chrome110 +++ b/chrome/curl_chrome110 @@ -21,6 +21,6 @@ dir=${0%/*} -H 'Accept-Encoding: gzip, deflate, br' \ -H 'Accept-Language: en-US,en;q=0.9' \ --http2 --http2-no-server-push --false-start --compressed \ - --tlsv1.2 --no-npn --alps --tls-permute-extensions \ + --tlsv1.2 --alps --tls-permute-extensions \ --cert-compression brotli \ "$@" diff --git a/chrome/curl_chrome99 b/chrome/curl_chrome99 index 079538a..2341b60 100755 --- a/chrome/curl_chrome99 +++ b/chrome/curl_chrome99 @@ -21,6 +21,6 @@ dir=${0%/*} -H 'Accept-Encoding: gzip, deflate, br' \ -H 'Accept-Language: en-US,en;q=0.9' \ --http2 --false-start --compressed \ - --tlsv1.2 --no-npn --alps \ + --tlsv1.2 --alps \ --cert-compression brotli \ "$@" diff --git a/chrome/curl_chrome99_android b/chrome/curl_chrome99_android index 9bf6bf6..2e7a4c8 100755 --- a/chrome/curl_chrome99_android +++ b/chrome/curl_chrome99_android @@ -21,6 +21,6 @@ dir=${0%/*} -H 'Accept-Encoding: gzip, deflate, br' \ -H 'Accept-Language: en-US,en;q=0.9' \ --http2 --false-start --compressed \ - --tlsv1.2 --no-npn --alps \ + --tlsv1.2 --alps \ --cert-compression brotli \ "$@" diff --git a/chrome/curl_edge101 b/chrome/curl_edge101 index 654298f..d69ee5c 100755 --- a/chrome/curl_edge101 +++ b/chrome/curl_edge101 @@ -21,6 +21,6 @@ dir=${0%/*} -H 'Accept-Encoding: gzip, deflate, br' \ -H 'Accept-Language: en-US,en;q=0.9' \ --http2 --false-start --compressed \ - --tlsv1.2 --no-npn --alps \ + --tlsv1.2 --alps \ --cert-compression brotli \ "$@" diff --git a/chrome/curl_edge99 b/chrome/curl_edge99 index 1a3e55b..f4b3b3f 100755 --- a/chrome/curl_edge99 +++ b/chrome/curl_edge99 @@ -21,6 +21,6 @@ dir=${0%/*} -H 'Accept-Encoding: gzip, deflate, br' \ -H 'Accept-Language: en-US,en;q=0.9' \ --http2 --false-start --compressed \ - --tlsv1.2 --no-npn --alps \ + --tlsv1.2 --alps \ --cert-compression brotli \ "$@" diff --git a/chrome/curl_safari15_3 b/chrome/curl_safari15_3 index 71b5b15..5821758 100755 --- a/chrome/curl_safari15_3 +++ b/chrome/curl_safari15_3 @@ -15,6 +15,6 @@ dir=${0%/*} -H 'Accept-Language: en-us' \ -H 'Accept-Encoding: gzip, deflate, br' \ --http2 --false-start --compressed \ - --tlsv1.0 --no-npn --no-tls-session-ticket \ + --tlsv1.0 --no-tls-session-ticket \ --http2-pseudo-headers-order 'mspa' \ "$@" diff --git a/chrome/curl_safari15_5 b/chrome/curl_safari15_5 index 61cdfb1..8b6ebf4 100755 --- a/chrome/curl_safari15_5 +++ b/chrome/curl_safari15_5 @@ -15,7 +15,7 @@ dir=${0%/*} -H 'Accept-Language: en-GB,en-US;q=0.9,en;q=0.8' \ -H 'Accept-Encoding: gzip, deflate, br' \ --http2 --false-start --compressed \ - --tlsv1.0 --no-npn --no-tls-session-ticket \ + --tlsv1.0 --no-tls-session-ticket \ --cert-compression zlib \ --http2-pseudo-headers-order 'mspa' \ "$@" diff --git a/chrome/patches/curl-impersonate.patch b/chrome/patches/curl-impersonate.patch index 1c5bdb5..103e9c4 100644 --- a/chrome/patches/curl-impersonate.patch +++ b/chrome/patches/curl-impersonate.patch @@ -1,8 +1,8 @@ diff --git a/Makefile.am b/Makefile.am -index 40771ed38..a7c51eea7 100644 +index f25e4e2f0..ff0c5630b 100644 --- a/Makefile.am +++ b/Makefile.am -@@ -155,13 +155,13 @@ CLEANFILES = $(VC10_LIBVCXPROJ) $(VC10_SRCVCXPROJ) $(VC11_LIBVCXPROJ) \ +@@ -156,13 +156,13 @@ CLEANFILES = $(VC10_LIBVCXPROJ) $(VC10_SRCVCXPROJ) $(VC11_LIBVCXPROJ) \ $(VC14_SRCVCXPROJ) $(VC14_10_LIBVCXPROJ) $(VC14_10_SRCVCXPROJ) \ $(VC14_30_LIBVCXPROJ) $(VC14_30_SRCVCXPROJ) @@ -19,10 +19,10 @@ index 40771ed38..a7c51eea7 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 de2dee5a4..ab8a92db4 100644 +index 75a882b12..71fd3290a 100644 --- a/configure.ac +++ b/configure.ac -@@ -1331,7 +1331,8 @@ if test X"$OPT_BROTLI" != Xno; then +@@ -1493,7 +1493,8 @@ if test X"$OPT_BROTLI" != Xno; then dnl if given with a prefix, we set -L and -I based on that if test -n "$PREFIX_BROTLI"; then @@ -32,7 +32,7 @@ index de2dee5a4..ab8a92db4 100644 LD_BROTLI=-L${PREFIX_BROTLI}/lib$libsuff CPP_BROTLI=-I${PREFIX_BROTLI}/include DIR_BROTLI=${PREFIX_BROTLI}/lib$libsuff -@@ -1341,7 +1342,11 @@ if test X"$OPT_BROTLI" != Xno; then +@@ -1503,7 +1504,11 @@ if test X"$OPT_BROTLI" != Xno; then CPPFLAGS="$CPPFLAGS $CPP_BROTLI" LIBS="$LIB_BROTLI $LIBS" @@ -45,8 +45,8 @@ index de2dee5a4..ab8a92db4 100644 AC_CHECK_HEADERS(brotli/decode.h, curl_brotli_msg="enabled (libbrotlidec)" -@@ -4426,8 +4431,8 @@ AC_CONFIG_FILES([Makefile \ - tests/unit/Makefile \ +@@ -4706,8 +4711,8 @@ AC_CONFIG_FILES([Makefile \ + tests/http/clients/Makefile \ packages/Makefile \ packages/vms/Makefile \ - curl-config \ @@ -57,7 +57,7 @@ index de2dee5a4..ab8a92db4 100644 AC_OUTPUT diff --git a/curl-config.in b/curl-config.in -index aaf2b8a43..ccfa52985 100644 +index 54f92d931..ea5895e9b 100644 --- a/curl-config.in +++ b/curl-config.in @@ -163,9 +163,9 @@ while test $# -gt 0; do @@ -76,41 +76,41 @@ index aaf2b8a43..ccfa52985 100644 --static-libs) if test "X@ENABLE_STATIC@" != "Xno" ; then -- echo @libdir@/libcurl.@libext@ @LDFLAGS@ @LIBCURL_LIBS@ -+ echo @libdir@/libcurl-impersonate-chrome.@libext@ @LDFLAGS@ @LIBCURL_LIBS@ +- echo "@libdir@/libcurl.@libext@" @LDFLAGS@ @LIBCURL_LIBS@ ++ echo "@libdir@/libcurl-impersonate-chrome.@libext@" @LDFLAGS@ @LIBCURL_LIBS@ else echo "curl was built with static libraries disabled" >&2 exit 1 diff --git a/include/curl/curl.h b/include/curl/curl.h -index b00648e79..a8edd2e2d 100644 +index 944352421..532fe3acd 100644 --- a/include/curl/curl.h +++ b/include/curl/curl.h -@@ -2143,6 +2143,50 @@ typedef enum { - /* set the SSH host key callback custom pointer */ - CURLOPT(CURLOPT_SSH_HOSTKEYDATA, CURLOPTTYPE_CBPOINT, 317), +@@ -2207,6 +2207,50 @@ typedef enum { + /* Can leak things, gonna exit() soon */ + CURLOPT(CURLOPT_QUICK_EXIT, CURLOPTTYPE_LONG, 322), + /* curl-impersonate: A list of headers used by the impersonated browser. + * If given, merged with CURLOPT_HTTPHEADER. */ -+ CURLOPT(CURLOPT_HTTPBASEHEADER, CURLOPTTYPE_SLISTPOINT, 318), ++ CURLOPT(CURLOPT_HTTPBASEHEADER, CURLOPTTYPE_SLISTPOINT, 323), + + /* 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, 319), ++ CURLOPT(CURLOPT_SSL_SIG_HASH_ALGS, CURLOPTTYPE_STRINGPOINT, 324), + + /* 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, 320), ++ CURLOPT(CURLOPT_SSL_ENABLE_ALPS, CURLOPTTYPE_LONG, 325), + + /* 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, 321), ++ CURLOPT(CURLOPT_SSL_CERT_COMPRESSION, CURLOPTTYPE_STRINGPOINT, 326), + + /* Enable/disable TLS session ticket extension (RFC5077) */ -+ CURLOPT(CURLOPT_SSL_ENABLE_TICKET, CURLOPTTYPE_LONG, 322), ++ CURLOPT(CURLOPT_SSL_ENABLE_TICKET, CURLOPTTYPE_LONG, 327), + + /* + * curl-impersonate: @@ -119,25 +119,25 @@ index b00648e79..a8edd2e2d 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, 323), ++ CURLOPT(CURLOPT_HTTP2_PSEUDO_HEADERS_ORDER, CURLOPTTYPE_STRINGPOINT, 328), + + /* + * curl-impersonate: + * Disable HTTP2 server push in the HTTP2 SETTINGS. + */ -+ CURLOPT(CURLOPT_HTTP2_NO_SERVER_PUSH, CURLOPTTYPE_LONG, 324), ++ CURLOPT(CURLOPT_HTTP2_NO_SERVER_PUSH, CURLOPTTYPE_LONG, 329), + + /* + * 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, 325), ++ CURLOPT(CURLOPT_SSL_PERMUTE_EXTENSIONS, CURLOPTTYPE_LONG, 330), + CURLOPT_LASTENTRY /* the last unused */ } CURLoption; diff --git a/include/curl/easy.h b/include/curl/easy.h -index 9c7e63ada..a3c54c4af 100644 +index 1285101c5..c620065dc 100644 --- a/include/curl/easy.h +++ b/include/curl/easy.h @@ -43,6 +43,16 @@ CURL_EXTERN CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...); @@ -158,21 +158,25 @@ index 9c7e63ada..a3c54c4af 100644 * NAME curl_easy_getinfo() * diff --git a/lib/Makefile.am b/lib/Makefile.am -index 18ce47ea9..9cbd81534 100644 +index 3c0a70912..61a9eb90b 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am -@@ -30,7 +30,7 @@ EXTRA_DIST = Makefile.m32 config-win32.h config-win32ce.h config-plan9.h \ - libcurl.plist libcurl.rc config-amigaos.h makefile.amiga config-win32ce.h \ - config-os400.h setup-os400.h $(CMAKE_DIST) setup-win32.h .checksrc +@@ -31,7 +31,7 @@ EXTRA_DIST = Makefile.mk config-win32.h config-win32ce.h config-plan9.h \ + config-os400.h setup-os400.h $(CMAKE_DIST) setup-win32.h .checksrc \ + Makefile.soname -lib_LTLIBRARIES = libcurl.la +lib_LTLIBRARIES = libcurl-impersonate-chrome.la if BUILD_UNITTESTS noinst_LTLIBRARIES = libcurlu.la -@@ -75,43 +75,43 @@ AM_CPPFLAGS += -DBUILDING_LIBCURL - AM_LDFLAGS = - AM_CFLAGS = +@@ -67,51 +67,51 @@ AM_CFLAGS = + # Makefile.inc provides the CSOURCES and HHEADERS defines + include Makefile.inc + +-libcurl_la_SOURCES = $(CSOURCES) $(HHEADERS) ++libcurl_impersonate_chrome_la_SOURCES = $(CSOURCES) $(HHEADERS) + libcurlu_la_SOURCES = $(CSOURCES) $(HHEADERS) -libcurl_la_CPPFLAGS_EXTRA = -libcurl_la_LDFLAGS_EXTRA = @@ -210,6 +214,12 @@ index 18ce47ea9..9cbd81534 100644 if USE_CPPFLAG_CURL_STATICLIB -libcurl_la_CPPFLAGS_EXTRA += -DCURL_STATICLIB +libcurl_impersonate_chrome_la_CPPFLAGS_EXTRA += -DCURL_STATICLIB + else + if HAVE_WINDRES +-libcurl_la_SOURCES += $(LIB_RCFILES) ++libcurl_impersonate_chrome_la_SOURCES += $(LIB_RCFILES) + $(LIB_RCFILES): $(top_srcdir)/include/curl/curlver.h + endif endif if DOING_CURL_SYMBOL_HIDING @@ -228,41 +238,83 @@ index 18ce47ea9..9cbd81534 100644 libcurlu_la_CPPFLAGS = $(AM_CPPFLAGS) -DCURL_STATICLIB -DUNITTESTS libcurlu_la_LDFLAGS = $(AM_LDFLAGS) -static $(LIBCURL_LIBS) -@@ -120,7 +120,7 @@ libcurlu_la_CFLAGS = $(AM_CFLAGS) - # Makefile.inc provides the CSOURCES and HHEADERS defines - include Makefile.inc - --libcurl_la_SOURCES = $(CSOURCES) $(HHEADERS) -+libcurl_impersonate_chrome_la_SOURCES = $(CSOURCES) $(HHEADERS) - libcurlu_la_SOURCES = $(CSOURCES) $(HHEADERS) - - CHECKSRC = $(CS_$(V)) diff --git a/lib/Makefile.inc b/lib/Makefile.inc -index 9bd8e324b..bfd5e90e2 100644 +index f815170a7..9d9417edc 100644 --- a/lib/Makefile.inc +++ b/lib/Makefile.inc -@@ -165,6 +165,7 @@ LIB_CFILES = \ - idn_win32.c \ +@@ -174,6 +174,7 @@ LIB_CFILES = \ + idn.c \ if2ip.c \ imap.c \ + impersonate.c \ inet_ntop.c \ inet_pton.c \ krb5.c \ +diff --git a/lib/dynhds.c b/lib/dynhds.c +index b325e0060..4c8a73bab 100644 +--- a/lib/dynhds.c ++++ b/lib/dynhds.c +@@ -52,6 +52,8 @@ entry_new(const char *name, size_t namelen, + e->valuelen = valuelen; + if(opts & DYNHDS_OPT_LOWERCASE) + Curl_strntolower(e->name, e->name, e->namelen); ++ if(opts & DYNHDS_OPT_LOWERCASE_VAL) ++ Curl_strntolower(e->value, e->value, e->valuelen); + return e; + } + +@@ -134,6 +136,16 @@ void Curl_dynhds_set_opts(struct dynhds *dynhds, int opts) + dynhds->opts = opts; + } + ++void Curl_dynhds_set_opt(struct dynhds *dynhds, int opt) ++{ ++ dynhds->opts |= opt; ++} ++ ++void Curl_dynhds_del_opt(struct dynhds *dynhds, int opt) ++{ ++ dynhds->opts &= ~opt; ++} ++ + struct dynhds_entry *Curl_dynhds_getn(struct dynhds *dynhds, size_t n) + { + DEBUGASSERT(dynhds); +diff --git a/lib/dynhds.h b/lib/dynhds.h +index 777baa58a..2d542dfd6 100644 +--- a/lib/dynhds.h ++++ b/lib/dynhds.h +@@ -53,6 +53,7 @@ struct dynhds { + + #define DYNHDS_OPT_NONE (0) + #define DYNHDS_OPT_LOWERCASE (1 << 0) ++#define DYNHDS_OPT_LOWERCASE_VAL (1 << 1) + + /** + * Init for use on first time or after a reset. +@@ -82,6 +83,8 @@ size_t Curl_dynhds_count(struct dynhds *dynhds); + * This will not have an effect on already existing headers. + */ + void Curl_dynhds_set_opts(struct dynhds *dynhds, int opts); ++void Curl_dynhds_set_opt(struct dynhds *dynhds, int opt); ++void Curl_dynhds_del_opt(struct dynhds *dynhds, int opt); + + /** + * Return the n-th header entry or NULL if it does not exist. diff --git a/lib/easy.c b/lib/easy.c -index 704a59df6..f486362c0 100644 +index d36cc03d1..65e94f1ad 100644 --- a/lib/easy.c +++ b/lib/easy.c -@@ -81,6 +81,8 @@ +@@ -73,6 +73,8 @@ #include "dynbuf.h" #include "altsvc.h" #include "hsts.h" +#include "strcase.h" +#include "impersonate.h" - /* The last 3 #include files should be in this order */ - #include "curl_printf.h" -@@ -332,6 +334,134 @@ CURLsslset curl_global_sslset(curl_sslbackend id, const char *name, + #include "easy_lock.h" + +@@ -330,6 +332,134 @@ CURLsslset curl_global_sslset(curl_sslbackend id, const char *name, return rc; } @@ -280,7 +332,7 @@ index 704a59df6..f486362c0 100644 + struct curl_slist *headers = NULL; + + for(opts = impersonations; opts->target != NULL; opts++) { -+ if (Curl_safe_strcasecompare(target, opts->target)) { ++ if (strcasecompare(target, opts->target)) { + break; + } + } @@ -397,7 +449,7 @@ index 704a59df6..f486362c0 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. -@@ -340,6 +470,8 @@ struct Curl_easy *curl_easy_init(void) +@@ -338,6 +468,8 @@ struct Curl_easy *curl_easy_init(void) { CURLcode result; struct Curl_easy *data; @@ -406,7 +458,7 @@ index 704a59df6..f486362c0 100644 /* Make sure we inited the global SSL stuff */ global_init_lock(); -@@ -362,6 +494,29 @@ struct Curl_easy *curl_easy_init(void) +@@ -360,6 +492,29 @@ struct Curl_easy *curl_easy_init(void) return NULL; } @@ -421,7 +473,7 @@ index 704a59df6..f486362c0 100644 + env_headers = curl_getenv("CURL_IMPERSONATE_HEADERS"); + if(env_headers) { + result = curl_easy_impersonate(data, env_target, -+ !Curl_strcasecompare(env_headers, "no")); ++ !strcasecompare(env_headers, "no")); + free(env_headers); + } else { + result = curl_easy_impersonate(data, env_target, true); @@ -436,7 +488,7 @@ index 704a59df6..f486362c0 100644 return data; } -@@ -936,6 +1091,13 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) +@@ -930,6 +1085,13 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) outcurl->state.referer_alloc = TRUE; } @@ -450,7 +502,7 @@ index 704a59df6..f486362c0 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]) { -@@ -1025,6 +1187,9 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) +@@ -1019,6 +1181,9 @@ fail: */ void curl_easy_reset(struct Curl_easy *data) { @@ -460,7 +512,7 @@ index 704a59df6..f486362c0 100644 Curl_free_request_state(data); /* zero out UserDefined data: */ -@@ -1049,6 +1214,23 @@ void curl_easy_reset(struct Curl_easy *data) +@@ -1043,6 +1208,23 @@ void curl_easy_reset(struct Curl_easy *data) #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH) Curl_http_auth_cleanup_digest(data); #endif @@ -474,7 +526,7 @@ index 704a59df6..f486362c0 100644 + env_headers = curl_getenv("CURL_IMPERSONATE_HEADERS"); + if(env_headers) { + curl_easy_impersonate(data, env_target, -+ !Curl_strcasecompare(env_headers, "no")); ++ !strcasecompare(env_headers, "no")); + free(env_headers); + } else { + curl_easy_impersonate(data, env_target, true); @@ -485,10 +537,10 @@ index 704a59df6..f486362c0 100644 /* diff --git a/lib/easyoptions.c b/lib/easyoptions.c -index c99f135ff..6b63fe4ae 100644 +index a9c1efd00..136a43e22 100644 --- a/lib/easyoptions.c +++ b/lib/easyoptions.c -@@ -130,8 +130,12 @@ struct curl_easyoption Curl_easyopts[] = { +@@ -132,8 +132,12 @@ struct curl_easyoption Curl_easyopts[] = { {"HSTS_CTRL", CURLOPT_HSTS_CTRL, CURLOT_LONG, 0}, {"HTTP09_ALLOWED", CURLOPT_HTTP09_ALLOWED, CURLOT_LONG, 0}, {"HTTP200ALIASES", CURLOPT_HTTP200ALIASES, CURLOT_SLIST, 0}, @@ -501,7 +553,7 @@ index c99f135ff..6b63fe4ae 100644 {"HTTPHEADER", CURLOPT_HTTPHEADER, CURLOT_SLIST, 0}, {"HTTPPOST", CURLOPT_HTTPPOST, CURLOT_OBJECT, 0}, {"HTTPPROXYTUNNEL", CURLOPT_HTTPPROXYTUNNEL, CURLOT_LONG, 0}, -@@ -297,18 +301,23 @@ struct curl_easyoption Curl_easyopts[] = { +@@ -302,18 +306,23 @@ 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}, @@ -525,200 +577,27 @@ index c99f135ff..6b63fe4ae 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}, -@@ -364,6 +373,6 @@ struct curl_easyoption Curl_easyopts[] = { +@@ -370,6 +379,6 @@ struct curl_easyoption Curl_easyopts[] = { */ int Curl_easyopts_check(void) { -- return ((CURLOPT_LASTENTRY%10000) != (317 + 1)); -+ return ((CURLOPT_LASTENTRY%10000) != (325 + 1)); +- return ((CURLOPT_LASTENTRY%10000) != (322 + 1)); ++ return ((CURLOPT_LASTENTRY%10000) != (330 + 1)); } #endif -diff --git a/lib/h2h3.c b/lib/h2h3.c -index 9453cf55b..01f8918ea 100644 ---- a/lib/h2h3.c -+++ b/lib/h2h3.c -@@ -41,10 +41,6 @@ - - #if defined(USE_NGHTTP2) || defined(ENABLE_QUIC) - --/* Index where :authority header field will appear in request header -- field list. */ --#define AUTHORITY_DST_IDX 3 -- - /* USHRT_MAX is 65535 == 0xffff */ - #define HEADER_OVERFLOW(x) \ - (x.namelen > 0xffff || x.valuelen > 0xffff - x.namelen) -@@ -115,6 +111,53 @@ static header_instruction inspect_header(const char *name, size_t namelen, - } - } - -+/* -+ * curl-impersonate: -+ * Determine the position of HTTP/2 pseudo headers. -+ * The pseudo headers ":method", ":path", ":scheme", ":authority" -+ * are sent in different order by different browsers. An important part of the -+ * impersonation is ordering them like the browser does. -+ */ -+static int http2_pseudo_header_index(struct Curl_easy *data, -+ const char *header, -+ size_t *index) -+{ -+ char *off; -+ // Use the Chrome ordering by default: -+ // :method, :authority, :scheme, :path -+ char *order = "masp"; -+ if(data->set.str[STRING_HTTP2_PSEUDO_HEADERS_ORDER]) -+ order = data->set.str[STRING_HTTP2_PSEUDO_HEADERS_ORDER]; -+ -+ if(strlen(order) != 4) -+ return CURLE_BAD_FUNCTION_ARGUMENT; -+ -+ // :method should always be first -+ if(order[0] != 'm') -+ return CURLE_BAD_FUNCTION_ARGUMENT; -+ -+ // All pseudo-headers must be present -+ if(!strchr(order, 'm') || -+ !strchr(order, 'a') || -+ !strchr(order, 's') || -+ !strchr(order, 'p')) -+ return CURLE_BAD_FUNCTION_ARGUMENT; -+ -+ if(strcasecompare(header, ":method")) -+ off = strchr(order, 'm'); -+ else if(strcasecompare(header, ":authority")) -+ off = strchr(order, 'a'); -+ else if(strcasecompare(header, ":scheme")) -+ off = strchr(order, 's'); -+ else if(strcasecompare(header, ":path")) -+ off = strchr(order, 'p'); -+ else -+ return CURLE_BAD_FUNCTION_ARGUMENT; -+ -+ *index = off - order; -+ return CURLE_OK; -+} -+ - CURLcode Curl_pseudo_headers(struct Curl_easy *data, - const char *mem, /* the request */ - const size_t len /* size of request */, -@@ -123,6 +166,7 @@ CURLcode Curl_pseudo_headers(struct Curl_easy *data, - struct connectdata *conn = data->conn; - size_t nheader = 0; - size_t i; -+ size_t header_idx; - size_t authority_idx; - char *hdbuf = (char *)mem; - char *end, *line_end; -@@ -164,10 +208,19 @@ CURLcode Curl_pseudo_headers(struct Curl_easy *data, - end = memchr(hdbuf, ' ', line_end - hdbuf); - if(!end || end == hdbuf) - goto fail; -- nva[0].name = H2H3_PSEUDO_METHOD; -- nva[0].namelen = sizeof(H2H3_PSEUDO_METHOD) - 1; -- nva[0].value = hdbuf; -- nva[0].valuelen = (size_t)(end - hdbuf); -+ /* curl-impersonate: Set the index of ":method" based on libcurl option */ -+ if(http2_pseudo_header_index(data, ":authority", &authority_idx)) -+ goto fail; -+ if(http2_pseudo_header_index(data, ":method", &header_idx)) -+ goto fail; -+ /* This is needed to overcome the fact that curl will only move the authority -+ * header into its place after all other headers have been placed. */ -+ if(header_idx > authority_idx) -+ header_idx--; -+ nva[header_idx].name = H2H3_PSEUDO_METHOD; -+ nva[header_idx].namelen = sizeof(H2H3_PSEUDO_METHOD) - 1; -+ nva[header_idx].value = hdbuf; -+ nva[header_idx].valuelen = (size_t)(end - hdbuf); - - hdbuf = end + 1; - -@@ -181,28 +234,38 @@ CURLcode Curl_pseudo_headers(struct Curl_easy *data, - } - if(!end || end == hdbuf) - goto fail; -- nva[1].name = H2H3_PSEUDO_PATH; -- nva[1].namelen = sizeof(H2H3_PSEUDO_PATH) - 1; -- nva[1].value = hdbuf; -- nva[1].valuelen = (end - hdbuf); -- -- nva[2].name = H2H3_PSEUDO_SCHEME; -- nva[2].namelen = sizeof(H2H3_PSEUDO_SCHEME) - 1; -+ /* curl-impersonate: Set the index of ":path" based on libcurl option */ -+ if(http2_pseudo_header_index(data, ":path", &header_idx)) -+ goto fail; -+ if(header_idx > authority_idx) -+ header_idx--; -+ nva[header_idx].name = H2H3_PSEUDO_PATH; -+ nva[header_idx].namelen = sizeof(H2H3_PSEUDO_PATH) - 1; -+ nva[header_idx].value = hdbuf; -+ nva[header_idx].valuelen = (end - hdbuf); -+ -+ /* curl-impersonate: Set the index of ":scheme" based on libcurl option */ -+ if(http2_pseudo_header_index(data, ":scheme", &header_idx)) -+ goto fail; -+ if(header_idx > authority_idx) -+ header_idx--; -+ nva[header_idx].name = H2H3_PSEUDO_SCHEME; -+ nva[header_idx].namelen = sizeof(H2H3_PSEUDO_SCHEME) - 1; - vptr = Curl_checkheaders(data, STRCONST(H2H3_PSEUDO_SCHEME)); - if(vptr) { - vptr += sizeof(H2H3_PSEUDO_SCHEME); - while(*vptr && ISSPACE(*vptr)) - vptr++; -- nva[2].value = vptr; -+ nva[header_idx].value = vptr; - infof(data, "set pseudo header %s to %s", H2H3_PSEUDO_SCHEME, vptr); - } - else { - if(conn->handler->flags & PROTOPT_SSL) -- nva[2].value = "https"; -+ nva[header_idx].value = "https"; - else -- nva[2].value = "http"; -+ nva[header_idx].value = "http"; - } -- nva[2].valuelen = strlen((char *)nva[2].value); -+ nva[header_idx].valuelen = strlen((char *)nva[header_idx].value); - - authority_idx = 0; - i = 3; -@@ -258,16 +321,16 @@ CURLcode Curl_pseudo_headers(struct Curl_easy *data, - nva[i].valuelen = (end - hdbuf); - } - -- nva[i].value = hdbuf; -- nva[i].valuelen = (end - hdbuf); -- - ++i; - } - -+ /* curl-impersonate: Set the index of ":authority" based on libcurl option */ -+ if(http2_pseudo_header_index(data, ":authority", &header_idx)) -+ goto fail; - /* :authority must come before non-pseudo header fields */ -- if(authority_idx && authority_idx != AUTHORITY_DST_IDX) { -+ if(authority_idx && authority_idx != header_idx) { - struct h2h3pseudo authority = nva[authority_idx]; -- for(i = authority_idx; i > AUTHORITY_DST_IDX; --i) { -+ for(i = authority_idx; i > header_idx; --i) { - nva[i] = nva[i - 1]; - } - nva[i] = authority; diff --git a/lib/http.c b/lib/http.c -index 258722a60..9a06e281a 100644 +index 219dcc2c0..7b04c6c36 100644 --- a/lib/http.c +++ b/lib/http.c -@@ -85,6 +85,7 @@ - #include "altsvc.h" - #include "hsts.h" +@@ -90,6 +90,7 @@ + #include "ws.h" #include "c-hyper.h" + #include "curl_ctype.h" +#include "slist.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" -@@ -1804,6 +1805,15 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data, +@@ -1881,6 +1882,15 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data, int numlists = 1; /* by default */ int i; @@ -734,7 +613,7 @@ index 258722a60..9a06e281a 100644 #ifndef CURL_DISABLE_PROXY enum proxy_use proxy; -@@ -1815,10 +1825,10 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data, +@@ -1892,10 +1902,10 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data, switch(proxy) { case HEADER_SERVER: @@ -747,7 +626,7 @@ index 258722a60..9a06e281a 100644 if(data->set.sep_headers) { h[1] = data->set.proxyheaders; numlists++; -@@ -1828,12 +1838,12 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data, +@@ -1905,12 +1915,12 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data, if(data->set.sep_headers) h[0] = data->set.proxyheaders; else @@ -762,7 +641,7 @@ index 258722a60..9a06e281a 100644 #endif /* loop through one or two lists */ -@@ -2069,6 +2079,108 @@ void Curl_http_method(struct Curl_easy *data, struct connectdata *conn, +@@ -2146,6 +2156,108 @@ void Curl_http_method(struct Curl_easy *data, struct connectdata *conn, *reqp = httpreq; } @@ -871,7 +750,7 @@ index 258722a60..9a06e281a 100644 CURLcode Curl_http_useragent(struct Curl_easy *data) { /* The User-Agent string might have been allocated in url.c already, because -@@ -3088,6 +3200,11 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) +@@ -3165,6 +3277,11 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) http = data->req.p.http; DEBUGASSERT(http); @@ -883,95 +762,166 @@ index 258722a60..9a06e281a 100644 result = Curl_http_host(data, conn); if(result) return result; -diff --git a/lib/http.h b/lib/http.h -index 9eff6b1ff..d6ecbd6c0 100644 ---- a/lib/http.h -+++ b/lib/http.h -@@ -327,7 +327,8 @@ struct http_conn { - struct h2settings settings; +@@ -4777,12 +4894,41 @@ static bool h2_non_field(const char *name, size_t namelen) + return FALSE; + } + ++/* ++ * curl-impersonate: ++ * Determine the position of HTTP/2 pseudo headers. ++ * The pseudo headers ":method", ":path", ":scheme", ":authority" ++ * are sent in different order by different browsers. An important part of the ++ * impersonation is ordering them like the browser does. ++ */ ++static CURLcode h2_check_pseudo_header_order(const char *order) ++{ ++ if(strlen(order) != 4) ++ return CURLE_BAD_FUNCTION_ARGUMENT; ++ ++ // :method should always be first ++ if(order[0] != 'm') ++ return CURLE_BAD_FUNCTION_ARGUMENT; ++ ++ // All pseudo-headers must be present ++ if(!strchr(order, 'm') || ++ !strchr(order, 'a') || ++ !strchr(order, 's') || ++ !strchr(order, 'p')) ++ return CURLE_BAD_FUNCTION_ARGUMENT; ++ ++ return CURLE_OK; ++} ++ + CURLcode Curl_http_req_to_h2(struct dynhds *h2_headers, + struct httpreq *req, struct Curl_easy *data) + { + const char *scheme = NULL, *authority = NULL; + struct dynhds_entry *e; + size_t i; ++ // Use the Chrome ordering by default: ++ // :method, :authority, :scheme, :path ++ char *order = "masp"; + CURLcode result; + + DEBUGASSERT(req); +@@ -4816,25 +4962,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); +- result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_METHOD), +- req->method, strlen(req->method)); +- if(!result && scheme) { +- result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_SCHEME), +- scheme, strlen(scheme)); +- } +- if(!result && authority) { +- result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_AUTHORITY), +- authority, strlen(authority)); ++ ++ /* curl-impersonate: order of pseudo headers is different from the default */ ++ if(data->set.str[STRING_HTTP2_PSEUDO_HEADERS_ORDER]) { ++ order = data->set.str[STRING_HTTP2_PSEUDO_HEADERS_ORDER]; + } +- if(!result && req->path) { +- result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_PATH), +- req->path, strlen(req->path)); ++ ++ result = h2_check_pseudo_header_order(order); ++ ++ /* curl-impersonate: add http2 pseudo headers according to the specified order. */ ++ for(i = 0; !result && i < strlen(order); ++i) { ++ switch(order[i]) { ++ case 'm': ++ result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_METHOD), ++ req->method, strlen(req->method)); ++ break; ++ case 'a': ++ if(authority) { ++ result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_AUTHORITY), ++ authority, strlen(authority)); ++ } ++ break; ++ case 's': ++ if(scheme) { ++ result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_SCHEME), ++ scheme, strlen(scheme)); ++ } ++ break; ++ case 'p': ++ if(req->path) { ++ result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_PATH), ++ req->path, strlen(req->path)); ++ } ++ break; ++ } + } ++ + for(i = 0; !result && i < Curl_dynhds_count(&req->headers); ++i) { + e = Curl_dynhds_getn(&req->headers, i); + if(!h2_non_field(e->name, e->namelen)) { ++ /* curl-impersonate: ++ * Some HTTP/2 servers reject 'te' header value that is not lowercase (e.g. 'Trailers). ++ * Convert to lowercase explicitly. ++ */ ++ if(e->namelen == 2 && strcasecompare(e->name, "te")) ++ Curl_dynhds_set_opt(h2_headers, DYNHDS_OPT_LOWERCASE_VAL); ++ + result = Curl_dynhds_add(h2_headers, e->name, e->namelen, + e->value, e->valuelen); ++ ++ Curl_dynhds_del_opt(h2_headers, DYNHDS_OPT_LOWERCASE_VAL); + } + } - /* list of settings that will be sent */ -- nghttp2_settings_entry local_settings[3]; -+ /* curl-impersonate: Align HTTP/2 settings to Chrome's */ -+ nghttp2_settings_entry local_settings[8]; - size_t local_settings_num; - #else - int unused; /* prevent a compiler warning */ diff --git a/lib/http2.c b/lib/http2.c -index f6364d0e0..e0b6d4a2d 100644 +index c666192fc..5ea7d04c8 100644 --- a/lib/http2.c +++ b/lib/http2.c -@@ -46,6 +46,7 @@ +@@ -50,6 +50,7 @@ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" +#include "rand.h" - #define H2_BUFSIZE 32768 + #if (NGHTTP2_VERSION_NUM < 0x010c00) + #error too old nghttp2 version, upgrade! +@@ -68,7 +69,7 @@ + * use 16K as chunk size, as that fits H2 DATA frames well */ + #define H2_CHUNK_SIZE (16 * 1024) + /* this is how much we want "in flight" for a stream */ +-#define H2_STREAM_WINDOW_SIZE (10 * 1024 * 1024) ++#define H2_STREAM_WINDOW_SIZE (1024 * 1024) + /* on receving from TLS, we prep for holding a full stream window */ + #define H2_NW_RECV_CHUNKS (H2_STREAM_WINDOW_SIZE / H2_CHUNK_SIZE) + /* on send into TLS, we just want to accumulate small frames */ +@@ -86,24 +87,48 @@ + * will block their received QUOTA in the connection window. And if we + * run out of space, the server is blocked from sending us any data. + * See #10988 for an issue with this. */ +-#define HTTP2_HUGE_WINDOW_SIZE (100 * H2_STREAM_WINDOW_SIZE) ++/* curl-impersonate: match Chrome window size. */ ++#define HTTP2_HUGE_WINDOW_SIZE (15 * H2_STREAM_WINDOW_SIZE) -@@ -61,7 +62,7 @@ - #define NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE 1 - #endif +-#define H2_SETTINGS_IV_LEN 3 ++#define H2_SETTINGS_IV_LEN 8 + #define H2_BINSETTINGS_LEN 80 --#define HTTP2_HUGE_WINDOW_SIZE (32 * 1024 * 1024) /* 32 MB */ -+#define HTTP2_HUGE_WINDOW_SIZE (15 * 1024 * 1024) /* 15 MB */ - - #ifdef DEBUG_HTTP2 - #define H2BUGF(x) x -@@ -79,13 +80,20 @@ static int h2_process_pending_input(struct Curl_easy *data, - struct http_conn *httpc, - CURLcode *err); - -+/* -+ * curl-impersonate: Use Chrome's default HTTP/2 stream weight. -+ */ -+ -+#define CHROME_DEFAULT_STREAM_WEIGHT (256) -+ - /* - * Curl_http2_init_state() is called when the easy handle is created and - * allows for HTTP/2 specific init of state. - */ - void Curl_http2_init_state(struct UrlState *state) + static int populate_settings(nghttp2_settings_entry *iv, + struct Curl_easy *data) { -- state->stream_weight = NGHTTP2_DEFAULT_WEIGHT; -+ state->stream_weight = CHROME_DEFAULT_STREAM_WEIGHT; -+ state->stream_depends_e = TRUE; - } - - /* -@@ -94,7 +102,8 @@ void Curl_http2_init_state(struct UrlState *state) - */ - void Curl_http2_init_userset(struct UserDefined *set) - { -- set->stream_weight = NGHTTP2_DEFAULT_WEIGHT; -+ set->stream_weight = CHROME_DEFAULT_STREAM_WEIGHT; -+ set->stream_depends_e = TRUE; - } - - static int http2_getsock(struct Curl_easy *data, -@@ -1210,18 +1219,40 @@ static int error_callback(nghttp2_session *session, - static void populate_settings(struct Curl_easy *data, - struct http_conn *httpc) - { -+ int i = 0; - nghttp2_settings_entry *iv = httpc->local_settings; - - iv[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS; - iv[0].value = Curl_multi_max_concurrent_streams(data->multi); -- ++ int i = 0; + - iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE; -- iv[1].value = HTTP2_HUGE_WINDOW_SIZE; -- -- iv[2].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH; -- iv[2].value = data->multi->push_cb != NULL; -- -- httpc->local_settings_num = 3; +- iv[1].value = H2_STREAM_WINDOW_SIZE; + /* curl-impersonate: Align HTTP/2 settings to Chrome's */ + iv[i].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE; + iv[i].value = 0x10000; + i++; -+ + +- iv[2].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH; +- iv[2].value = data->multi->push_cb != NULL; + if(data->set.http2_no_server_push) { + iv[i].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH; + iv[i].value = 0; @@ -985,7 +935,8 @@ index f6364d0e0..e0b6d4a2d 100644 + iv[i].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE; + iv[i].value = 0x600000; + i++; -+ + +- return 3; + iv[i].settings_id = NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE; + iv[i].value = 0x40000; + i++; @@ -997,12 +948,80 @@ index f6364d0e0..e0b6d4a2d 100644 + // Curl_rand(data, (unsigned char *)&iv[4].settings_id, sizeof(iv[4].settings_id)); + // Curl_rand(data, (unsigned char *)&iv[4].value, sizeof(iv[4].value)); + -+ httpc->local_settings_num = i; ++ return i; } - void Curl_http2_done(struct Curl_easy *data, bool premature) + static size_t populate_binsettings(uint8_t *binsettings, +@@ -1616,11 +1641,17 @@ out: + return rv; + } + ++/* ++ * curl-impersonate: Use Chrome's default HTTP/2 stream weight ++ * instead of NGINX default stream weight. ++ */ ++#define CHROME_DEFAULT_STREAM_WEIGHT (256) ++ + static int sweight_wanted(const struct Curl_easy *data) + { + /* 0 weight is not set by user and we take the nghttp2 default one */ + return data->set.priority.weight? +- data->set.priority.weight : NGHTTP2_DEFAULT_WEIGHT; ++ data->set.priority.weight : CHROME_DEFAULT_STREAM_WEIGHT; + } + + static int sweight_in_effect(const struct Curl_easy *data) +@@ -1642,9 +1673,11 @@ static void h2_pri_spec(struct Curl_easy *data, + struct Curl_data_priority *prio = &data->set.priority; + struct stream_ctx *depstream = H2_STREAM_CTX(prio->parent); + int32_t depstream_id = depstream? depstream->id:0; ++ /* curl-impersonate: Set stream exclusive flag to true. */ ++ int exclusive = 1; + nghttp2_priority_spec_init(pri_spec, depstream_id, + sweight_wanted(data), +- data->set.priority.exclusive); ++ exclusive); + data->state.priority = *prio; + } + +@@ -1661,20 +1694,25 @@ static CURLcode h2_progress_egress(struct Curl_cfilter *cf, + struct stream_ctx *stream = H2_STREAM_CTX(data); + int rv = 0; + +- if((sweight_wanted(data) != sweight_in_effect(data)) || +- (data->set.priority.exclusive != data->state.priority.exclusive) || +- (data->set.priority.parent != data->state.priority.parent) ) { ++ /* curl-impersonate: Check if stream exclusive flag is true. */ ++ if(stream && stream->id > 0 && ++ ((sweight_wanted(data) != sweight_in_effect(data)) || ++ (data->set.priority.exclusive != 1) || ++ (data->set.priority.parent != data->state.priority.parent))) { + /* send new weight and/or dependency */ + nghttp2_priority_spec pri_spec; + + h2_pri_spec(data, &pri_spec); +- DEBUGF(LOG_CF(data, cf, "[h2sid=%d] Queuing PRIORITY", +- stream->id)); +- DEBUGASSERT(stream->id != -1); +- rv = nghttp2_submit_priority(ctx->h2, NGHTTP2_FLAG_NONE, +- stream->id, &pri_spec); +- if(rv) +- goto out; ++ /* curl-impersonate: Don't send PRIORITY frames for main stream. */ ++ if(stream->id != 1) { ++ DEBUGF(LOG_CF(data, cf, "[h2sid=%d] Queuing PRIORITY", ++ stream->id)); ++ DEBUGASSERT(stream->id != -1); ++ rv = nghttp2_submit_priority(ctx->h2, NGHTTP2_FLAG_NONE, ++ stream->id, &pri_spec); ++ if(rv) ++ goto out; ++ } + } + + while(!rv && nghttp2_session_want_write(ctx->h2)) diff --git a/lib/http2.h b/lib/http2.h -index f0390596c..cf9b7a9d5 100644 +index 562c05c99..b99c085d5 100644 --- a/lib/http2.h +++ b/lib/http2.h @@ -31,7 +31,8 @@ @@ -1017,12 +1036,14 @@ index f0390596c..cf9b7a9d5 100644 * Store nghttp2 version info in this buffer. diff --git a/lib/impersonate.c b/lib/impersonate.c new file mode 100644 -index 000000000..025bd58ef +index 000000000..4f5c24f5d --- /dev/null +++ b/lib/impersonate.c -@@ -0,0 +1,480 @@ +@@ -0,0 +1,482 @@ +#include "curl_setup.h" + ++#include ++ +#include "impersonate.h" + +const struct impersonate_opts impersonations[] = { @@ -1553,21 +1574,21 @@ index 000000000..c62991c5a + +#endif /* HEADER_CURL_IMPERSONATE_H */ diff --git a/lib/multi.c b/lib/multi.c -index e0280447c..dc1fdab68 100644 +index d1d32b793..3b49a1b4c 100644 --- a/lib/multi.c +++ b/lib/multi.c -@@ -395,7 +395,8 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */ +@@ -424,7 +424,8 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */ /* -1 means it not set by user, use the default value */ multi->maxconnects = -1; - multi->max_concurrent_streams = 100; + /* curl-impersonate: Use 1000 concurrent streams like Chrome. */ + multi->max_concurrent_streams = 1000; - multi->ipv6_works = Curl_ipv6works(NULL); #ifdef USE_WINSOCK + multi->wsa_event = WSACreateEvent(); diff --git a/lib/setopt.c b/lib/setopt.c -index 6b16e1c7c..189b54025 100644 +index 0c3b9634d..c22591f72 100644 --- a/lib/setopt.c +++ b/lib/setopt.c @@ -50,6 +50,7 @@ @@ -1578,7 +1599,7 @@ index 6b16e1c7c..189b54025 100644 /* The last 3 #include files should be in this order */ #include "curl_printf.h" -@@ -674,6 +675,23 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) +@@ -712,6 +713,23 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) va_arg(param, char *)); break; @@ -1599,10 +1620,10 @@ index 6b16e1c7c..189b54025 100644 + result = CURLE_OUT_OF_MEMORY; + break; + - case CURLOPT_HTTPHEADER: + #ifndef CURL_DISABLE_PROXY + case CURLOPT_PROXYHEADER: /* - * Set a list with HTTP headers to use (or replace internals with) -@@ -2318,6 +2336,27 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) +@@ -2410,6 +2428,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; @@ -1630,7 +1651,7 @@ index 6b16e1c7c..189b54025 100644 #endif case CURLOPT_IPRESOLVE: arg = va_arg(param, long); -@@ -2861,6 +2900,22 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) +@@ -2953,6 +2992,22 @@ 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)) ? TRUE : FALSE; break; @@ -1654,10 +1675,10 @@ index 6b16e1c7c..189b54025 100644 case CURLOPT_UNIX_SOCKET_PATH: data->set.abstract_unix_socket = FALSE; diff --git a/lib/transfer.c b/lib/transfer.c -index 1720b24b1..dcae3c143 100644 +index d2ff0c24c..56e2090b6 100644 --- a/lib/transfer.c +++ b/lib/transfer.c -@@ -104,7 +104,15 @@ char *Curl_checkheaders(const struct Curl_easy *data, +@@ -106,7 +106,15 @@ char *Curl_checkheaders(const struct Curl_easy *data, DEBUGASSERT(thislen); DEBUGASSERT(thisheader[thislen-1] != ':'); @@ -1675,10 +1696,10 @@ index 1720b24b1..dcae3c143 100644 Curl_headersep(head->data[thislen]) ) return head->data; diff --git a/lib/url.c b/lib/url.c -index 1114c6c12..75b724357 100644 +index b37d13f8f..f1b3b5440 100644 --- a/lib/url.c +++ b/lib/url.c -@@ -465,6 +465,11 @@ CURLcode Curl_close(struct Curl_easy **datap) +@@ -444,6 +444,11 @@ CURLcode Curl_close(struct Curl_easy **datap) Curl_safefree(data->state.aptr.proxyuser); Curl_safefree(data->state.aptr.proxypasswd); @@ -1690,15 +1711,15 @@ index 1114c6c12..75b724357 100644 #ifndef CURL_DISABLE_DOH if(data->req.doh) { Curl_dyn_free(&data->req.doh->probe[0].serverdoh); -@@ -620,6 +625,7 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data) +@@ -595,6 +600,7 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data) + set->tcp_fastopen = FALSE; set->tcp_nodelay = TRUE; - set->ssl_enable_npn = TRUE; set->ssl_enable_alpn = TRUE; + set->ssl_enable_ticket = 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; -@@ -3883,6 +3889,9 @@ static CURLcode create_conn(struct Curl_easy *data, +@@ -3584,6 +3590,9 @@ static CURLcode create_conn(struct Curl_easy *data, data->set.ssl.primary.cert_blob = data->set.blobs[BLOB_CERT]; data->set.ssl.primary.ca_info_blob = data->set.blobs[BLOB_CAINFO]; data->set.ssl.primary.curves = data->set.str[STRING_SSL_EC_CURVES]; @@ -1708,10 +1729,10 @@ index 1114c6c12..75b724357 100644 #ifndef CURL_DISABLE_PROXY data->set.proxy_ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH_PROXY]; -@@ -3996,8 +4005,21 @@ static CURLcode create_conn(struct Curl_easy *data, +@@ -3695,6 +3704,11 @@ static CURLcode create_conn(struct Curl_easy *data, + (default) */ + if(data->set.ssl_enable_alpn) conn->bits.tls_enable_alpn = TRUE; - if(data->set.ssl_enable_npn) - conn->bits.tls_enable_npn = TRUE; + + /* curl-impersonate: Turn on ALPS if ALPN is enabled and the bit is + * enabled. */ @@ -1719,41 +1740,31 @@ index 1114c6c12..75b724357 100644 + conn->bits.tls_enable_alps = TRUE; } -+ /* curl-impersonate: Add the TLS session ticket extension. */ -+ if(data->set.ssl_enable_ticket) -+ conn->bits.tls_enable_ticket = TRUE; -+ -+ /* curl-impersonate: Add the TLS extension permutation. */ -+ if(data->set.ssl_permute_extensions) -+ conn->bits.tls_permute_extensions = TRUE; -+ if(waitpipe) - /* There is a connection that *might* become usable for multiplexing - "soon", and we wait for that */ diff --git a/lib/urldata.h b/lib/urldata.h -index bcb4d460c..01e015706 100644 +index f02e66541..d628112a0 100644 --- a/lib/urldata.h +++ b/lib/urldata.h -@@ -254,6 +254,8 @@ struct ssl_primary_config { - enum CURL_TLSAUTH authtype; /* TLS authentication type (default SRP) */ +@@ -277,6 +277,8 @@ struct ssl_primary_config { + char *password; /* TLS password (for, e.g., SRP) */ #endif char *curves; /* list of curves to use */ + char *sig_hash_algs; /* List of signature hash algorithms to use */ + char *cert_compression; /* List of certificate compression algorithms. */ unsigned char ssl_options; /* the CURLOPT_SSL_OPTIONS bitmask */ - BIT(verifypeer); /* set TRUE if this is desired */ - BIT(verifyhost); /* set TRUE if CN/SAN must match hostname */ -@@ -509,6 +511,9 @@ struct ConnectBits { + unsigned int version_max; /* max supported version the client wants to use */ + unsigned char version; /* what version the client wants to use */ +@@ -526,6 +528,9 @@ struct ConnectBits { + BIT(multiplex); /* connection is multiplexed */ BIT(tcp_fastopen); /* use TCP Fast Open */ - BIT(tls_enable_npn); /* TLS NPN extension? */ 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(connect_only); #ifndef CURL_DISABLE_DOH BIT(doh); -@@ -1453,6 +1458,19 @@ struct UrlState { + #endif +@@ -1395,6 +1400,19 @@ struct UrlState { CURLcode hresult; /* used to pass return codes back from hyper callbacks */ #endif @@ -1773,19 +1784,19 @@ index bcb4d460c..01e015706 100644 /* Dynamically allocated strings, MUST be freed before this struct is killed. */ struct dynamically_allocated_data { -@@ -1608,6 +1626,9 @@ enum dupstring { - STRING_DNS_LOCAL_IP4, +@@ -1563,6 +1581,9 @@ enum dupstring { STRING_DNS_LOCAL_IP6, STRING_SSL_EC_CURVES, + STRING_AWS_SIGV4, /* Parameters for V4 signature */ + STRING_SSL_SIG_HASH_ALGS, + STRING_SSL_CERT_COMPRESSION, + STRING_HTTP2_PSEUDO_HEADERS_ORDER, /* -- end of null-terminated strings -- */ -@@ -1893,6 +1914,9 @@ struct UserDefined { +@@ -1857,6 +1878,9 @@ struct UserDefined { + BIT(tcp_keepalive); /* use TCP keepalives */ BIT(tcp_fastopen); /* use TCP Fast Open */ - BIT(ssl_enable_npn); /* TLS NPN extension? */ BIT(ssl_enable_alpn);/* TLS ALPN extension? */ + BIT(ssl_enable_alps);/* TLS ALPS extension? */ + BIT(ssl_enable_ticket); /* TLS session ticket extension */ @@ -1793,10 +1804,10 @@ index bcb4d460c..01e015706 100644 BIT(path_as_is); /* allow dotdots? */ BIT(pipewait); /* wait for multiplex status before starting a new connection */ -@@ -1911,6 +1935,9 @@ struct UserDefined { - BIT(doh_verifystatus); /* DoH certificate status verification */ +@@ -1877,6 +1901,9 @@ struct UserDefined { + #ifdef USE_WEBSOCKETS + BIT(ws_raw_mode); #endif - BIT(http09_allowed); /* allow HTTP/0.9 responses */ +#ifdef USE_HTTP2 + BIT(http2_no_server_push); /* Disable HTTP2 server push */ +#endif @@ -1804,24 +1815,25 @@ index bcb4d460c..01e015706 100644 struct Names { diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c -index 78aacd022..9f66af846 100644 +index 6543fb19a..da4882af8 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c -@@ -78,6 +78,13 @@ +@@ -79,6 +79,14 @@ + #include #include #include - -+#ifdef HAVE_ZLIB_H ++#include ++ ++#ifdef HAVE_LIBZ +#include +#endif +#ifdef HAVE_BROTLI +#include +#endif -+ - #ifdef USE_AMISSL - #include "amigaos.h" - #endif -@@ -262,6 +269,113 @@ + + #if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_OCSP) + #include +@@ -266,6 +274,113 @@ #define HAVE_OPENSSL_VERSION #endif @@ -1932,11 +1944,11 @@ index 78aacd022..9f66af846 100644 + +#endif + - struct ssl_backend_data { - struct Curl_easy *logger; /* transfer handle to pass trace logs to, only - using sockindex 0 */ -@@ -2623,6 +2737,151 @@ static CURLcode load_cacert_from_memory(SSL_CTX *ctx, - return (count > 0 ? CURLE_OK : CURLE_SSL_CACERT_BADFILE); + #ifdef OPENSSL_IS_BORINGSSL + typedef uint32_t sslerr_t; + #else +@@ -2583,6 +2698,151 @@ static const char *tls_rt_type(int type) + } } +#ifdef HAVE_LIBZ @@ -2084,15 +2096,15 @@ index 78aacd022..9f66af846 100644 +} +#endif + - static CURLcode ossl_connect_step1(struct Curl_easy *data, - struct connectdata *conn, int sockindex) - { -@@ -2762,7 +3021,14 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, + /* + * Our callback from the SSL/TLS layers. + */ +@@ -3536,7 +3796,14 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, ctx_options = SSL_OP_ALL; #ifdef SSL_OP_NO_TICKET - ctx_options |= SSL_OP_NO_TICKET; -+ if(conn->bits.tls_enable_ticket) { ++ if(data->set.ssl_enable_ticket) { + /* curl-impersonate: + * Turn off SSL_OP_NO_TICKET, we want TLS extension 35 (session_ticket) + * to be present in the client hello. */ @@ -2103,7 +2115,24 @@ index 78aacd022..9f66af846 100644 #endif #ifdef SSL_OP_NO_COMPRESSION -@@ -2907,6 +3173,35 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, +@@ -3603,6 +3870,16 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, + } + #endif + ++ SSL_CTX_set_options(backend->ctx, ++ SSL_OP_LEGACY_SERVER_CONNECT); ++ SSL_CTX_set_mode(backend->ctx, ++ SSL_MODE_CBC_RECORD_SPLITTING | SSL_MODE_ENABLE_FALSE_START); ++ ++ /* curl-impersonate: Enable TLS extensions 5 - status_request and ++ * 18 - signed_certificate_timestamp. */ ++ SSL_CTX_enable_signed_cert_timestamps(backend->ctx); ++ SSL_CTX_enable_ocsp_stapling(backend->ctx); ++ + if(ssl_cert || ssl_cert_blob || ssl_cert_type) { + if(!result && + !cert_stuff(data, backend->ctx, +@@ -3656,6 +3933,35 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, } #endif @@ -2113,7 +2142,7 @@ index 78aacd022..9f66af846 100644 + size_t nalgs; + /* curl-impersonate: Set the signature algorithms (TLS extension 13). + * See net/socket/ssl_client_socket_impl.cc in Chromium's source. */ -+ char *sig_hash_algs = SSL_CONN_CONFIG(sig_hash_algs); ++ char *sig_hash_algs = conn_config->sig_hash_algs; + if (sig_hash_algs) { + CURLcode result = parse_sig_algs(data, sig_hash_algs, algs, &nalgs); + if (result) @@ -2137,9 +2166,9 @@ index 78aacd022..9f66af846 100644 +#endif + #ifdef USE_OPENSSL_SRP - if((ssl_authtype == CURL_TLSAUTH_SRP) && - Curl_allow_auth_to_host(data)) { -@@ -2933,6 +3228,28 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, + if(ssl_config->primary.username && Curl_auth_allowed_to_host(data)) { + char * const ssl_username = ssl_config->primary.username; +@@ -3681,6 +3987,30 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, } #endif @@ -2156,67 +2185,86 @@ index 78aacd022..9f66af846 100644 + * curl-impersonate: Enable TLS extension permutation, enabled by default + * since Chrome 110. + */ -+ if(conn->bits.tls_permute_extensions) { ++ if(data->set.ssl_permute_extensions) { + SSL_CTX_set_permute_extensions(backend->ctx, 1); + } + -+ if(SSL_CONN_CONFIG(cert_compression) && ++ if(conn_config->cert_compression && + add_cert_compression(data, + backend->ctx, -+ SSL_CONN_CONFIG(cert_compression))) ++ conn_config->cert_compression)) + return CURLE_SSL_CIPHER; ++ ++ + /* 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 +@@ -3727,6 +4057,23 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, - #if defined(USE_WIN32_CRYPTO) - /* Import certificates from the Windows root certificate store if requested. -@@ -3232,6 +3549,33 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, + SSL_set_app_data(backend->handle, cf); - SSL_set_connect_state(backend->handle); - -+#if defined(HAS_ALPN) && defined(USE_HTTP2) -+ if(conn->bits.tls_enable_alpn && -+ data->state.httpwant >= CURL_HTTP_VERSION_2 && -+ conn->bits.tls_enable_alps) { -+ /* curl-impersonate: This adds the ALPS extension (17513). -+ * Chromium calls this function as well in SSLClientSocketImpl::Init(). -+ * The 4th parameter is called "settings", and I don't know what it -+ * should contain. For now, use an empty string. */ -+ SSL_add_application_settings(backend->handle, ALPN_H2, ALPN_H2_LENGTH, -+ NULL, 0); -+ infof(data, "ALPS, offering %s", ALPN_H2); ++#ifdef HAS_ALPN ++ if(connssl->alps) { ++ size_t i; ++ struct alpn_proto_buf proto; ++ ++ for(i = 0; i < connssl->alps->count; ++i) { ++ /* curl-impersonate: Add the ALPS extension (17513) like Chrome does. */ ++ SSL_add_application_settings(backend->handle, connssl->alps->entries[i], ++ strlen(connssl->alps->entries[i]), NULL, ++ 0); ++ } ++ ++ Curl_alpn_to_proto_str(&proto, connssl->alps); ++ infof(data, VTLS_INFOF_ALPS_OFFER_1STR, proto.data); + } +#endif + -+ SSL_set_options(backend->handle, -+ SSL_OP_LEGACY_SERVER_CONNECT); -+ SSL_set_mode(backend->handle, -+ SSL_MODE_CBC_RECORD_SPLITTING | SSL_MODE_ENABLE_FALSE_START); -+ -+ /* curl-impersonate: Enable TLS extensions 5 - status_request and -+ * 18 - signed_certificate_timestamp. */ -+ SSL_enable_signed_cert_timestamps(backend->handle); -+ SSL_enable_ocsp_stapling(backend->handle); -+ -+ /* curl-impersonate: Some SSL settings copied over from Chrome. */ -+ SSL_set_shed_handshake_config(backend->handle, 1); -+ - backend->server_cert = 0x0; - #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME - if((0 == Curl_inet_pton(AF_INET, hostname, &addr)) && + #if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ + !defined(OPENSSL_NO_OCSP) + if(conn_config->verifystatus) diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c -index faa1b5141..dbb170d72 100644 +index 32334016b..1a8a75ade 100644 --- a/lib/vtls/vtls.c +++ b/lib/vtls/vtls.c -@@ -153,6 +153,9 @@ Curl_ssl_config_matches(struct ssl_primary_config *data, - Curl_safe_strcasecompare(data->cipher_list, needle->cipher_list) && - Curl_safe_strcasecompare(data->cipher_list13, needle->cipher_list13) && - Curl_safe_strcasecompare(data->curves, needle->curves) && -+ Curl_safe_strcasecompare(data->sig_hash_algs, needle->sig_hash_algs) && -+ Curl_safe_strcasecompare(data->cert_compression, -+ needle->cert_compression) && - Curl_safe_strcasecompare(data->CRLfile, needle->CRLfile) && - Curl_safe_strcasecompare(data->pinned_key, needle->pinned_key)) +@@ -141,6 +141,9 @@ static const struct alpn_spec ALPN_SPEC_H11 = { + static const struct alpn_spec ALPN_SPEC_H2_H11 = { + { ALPN_H2, ALPN_HTTP_1_1 }, 2 + }; ++static const struct alpn_spec ALPN_SPEC_H2 = { ++ { ALPN_H2 }, 1 ++}; + #endif + + static const struct alpn_spec *alpn_get_spec(int httpwant, bool use_alpn) +@@ -155,6 +158,17 @@ static const struct alpn_spec *alpn_get_spec(int httpwant, bool use_alpn) + #endif + return &ALPN_SPEC_H11; + } ++ ++static const struct alpn_spec *alps_get_spec(int httpwant, bool use_alps) ++{ ++ if(!use_alps) ++ return NULL; ++#ifdef USE_HTTP2 ++ if(httpwant >= CURL_HTTP_VERSION_2) ++ return &ALPN_SPEC_H2; ++#endif ++ return NULL; ++} + #endif /* USE_SSL */ + + +@@ -182,6 +196,8 @@ Curl_ssl_config_matches(struct ssl_primary_config *data, + strcasecompare(data->cipher_list, needle->cipher_list) && + strcasecompare(data->cipher_list13, needle->cipher_list13) && + strcasecompare(data->curves, needle->curves) && ++ strcasecompare(data->sig_hash_algs, needle->sig_hash_algs) && ++ strcasecompare(data->cert_compression, needle->cert_compression) && + strcasecompare(data->CRLfile, needle->CRLfile) && + strcasecompare(data->pinned_key, needle->pinned_key)) return TRUE; -@@ -186,6 +189,8 @@ Curl_clone_primary_ssl_config(struct ssl_primary_config *source, +@@ -212,6 +228,8 @@ Curl_clone_primary_ssl_config(struct ssl_primary_config *source, CLONE_STRING(cipher_list13); CLONE_STRING(pinned_key); CLONE_STRING(curves); @@ -2225,7 +2273,7 @@ index faa1b5141..dbb170d72 100644 CLONE_STRING(CRLfile); #ifdef USE_TLS_SRP CLONE_STRING(username); -@@ -208,6 +213,8 @@ void Curl_free_primary_ssl_config(struct ssl_primary_config *sslc) +@@ -234,6 +252,8 @@ void Curl_free_primary_ssl_config(struct ssl_primary_config *sslc) Curl_safefree(sslc->ca_info_blob); Curl_safefree(sslc->issuercert_blob); Curl_safefree(sslc->curves); @@ -2234,8 +2282,83 @@ index faa1b5141..dbb170d72 100644 Curl_safefree(sslc->CRLfile); #ifdef USE_TLS_SRP Curl_safefree(sslc->username); +@@ -318,7 +338,8 @@ static bool ssl_prefs_check(struct Curl_easy *data) + } + + static struct ssl_connect_data *cf_ctx_new(struct Curl_easy *data, +- const struct alpn_spec *alpn) ++ const struct alpn_spec *alpn, ++ const struct alpn_spec *alps) + { + struct ssl_connect_data *ctx; + +@@ -328,6 +349,7 @@ static struct ssl_connect_data *cf_ctx_new(struct Curl_easy *data, + return NULL; + + ctx->alpn = alpn; ++ ctx->alps = alps; + ctx->backend = calloc(1, Curl_ssl->sizeof_ssl_backend_data); + if(!ctx->backend) { + free(ctx); +@@ -1760,8 +1782,11 @@ static CURLcode cf_ssl_create(struct Curl_cfilter **pcf, + + DEBUGASSERT(data->conn); + +- ctx = cf_ctx_new(data, alpn_get_spec(data->state.httpwant, +- conn->bits.tls_enable_alpn)); ++ ctx = cf_ctx_new(data, ++ alpn_get_spec(data->state.httpwant, ++ conn->bits.tls_enable_alpn), ++ alps_get_spec(data->state.httpwant, ++ conn->bits.tls_enable_alps)); + if(!ctx) { + result = CURLE_OUT_OF_MEMORY; + goto out; +@@ -1811,6 +1836,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; ++ bool use_alps = conn->bits.tls_enable_alps; + int httpwant = CURL_HTTP_VERSION_1_1; + + #ifdef USE_HTTP2 +@@ -1820,7 +1846,8 @@ static CURLcode cf_ssl_proxy_create(struct Curl_cfilter **pcf, + } + #endif + +- ctx = cf_ctx_new(data, alpn_get_spec(httpwant, use_alpn)); ++ ctx = cf_ctx_new(data, alpn_get_spec(httpwant, use_alpn), ++ alps_get_spec(httpwant, use_alps)); + if(!ctx) { + result = CURLE_OUT_OF_MEMORY; + goto out; +diff --git a/lib/vtls/vtls.h b/lib/vtls/vtls.h +index f24dca15b..595d437f9 100644 +--- a/lib/vtls/vtls.h ++++ b/lib/vtls/vtls.h +@@ -44,6 +44,8 @@ struct Curl_ssl_session; + "ALPN: server did not agree on a protocol. Uses default." + #define VTLS_INFOF_ALPN_OFFER_1STR \ + "ALPN: offers %s" ++#define VTLS_INFOF_ALPS_OFFER_1STR \ ++ "ALPS: offers %s" + #define VTLS_INFOF_ALPN_ACCEPTED_1STR \ + 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 ed49339e4..9fddc7494 100644 +--- a/lib/vtls/vtls_int.h ++++ b/lib/vtls/vtls_int.h +@@ -73,6 +73,7 @@ struct ssl_connect_data { + char *hostname; /* hostname for verification */ + char *dispname; /* display version of hostname */ + const struct alpn_spec *alpn; /* ALPN to use or NULL for none */ ++ const struct alpn_spec *alps; /* ALPS to use or NULL for none */ + struct ssl_backend_data *backend; /* vtls backend specific props */ + struct cf_call_data call_data; /* data handle used in current call */ + struct curltime handshake_done; /* time when handshake finished */ diff --git a/libcurl.pc.in b/libcurl.pc.in -index 49485f192..7f6590b36 100644 +index 9db6b0f89..14c2f23e0 100644 --- a/libcurl.pc.in +++ b/libcurl.pc.in @@ -36,6 +36,6 @@ Name: libcurl @@ -2246,8 +2369,103 @@ index 49485f192..7f6590b36 100644 +Libs: -L${libdir} -lcurl-impersonate-chrome @LIBCURL_NO_SHARED@ Libs.private: @LIBCURL_LIBS@ Cflags: -I${includedir} @CPPFLAG_CURL_STATICLIB@ +diff --git a/m4/curl-compilers.m4 b/m4/curl-compilers.m4 +index caa2b14cb..0a0af4361 100644 +--- a/m4/curl-compilers.m4 ++++ b/m4/curl-compilers.m4 +@@ -373,42 +373,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]) +- if test "$compiler_id" = "GNU_C" || +- test "$compiler_id" = "CLANG"; then +- AC_MSG_RESULT([yes]) +- tmp_has_include="no" +- tmp_chg_FLAGS="$CFLAGS" +- for word1 in $tmp_chg_FLAGS; do +- case "$word1" in +- -I*) +- tmp_has_include="yes" +- ;; +- esac +- done +- if test "$tmp_has_include" = "yes"; then +- tmp_chg_FLAGS=`echo "$tmp_chg_FLAGS" | "$SED" 's/^-I/ -isystem /g'` +- tmp_chg_FLAGS=`echo "$tmp_chg_FLAGS" | "$SED" 's/ -I/ -isystem /g'` +- CFLAGS="$tmp_chg_FLAGS" +- squeeze CFLAGS +- fi +- tmp_has_include="no" +- tmp_chg_FLAGS="$CPPFLAGS" +- for word1 in $tmp_chg_FLAGS; do +- case "$word1" in +- -I*) +- tmp_has_include="yes" +- ;; +- esac +- done +- if test "$tmp_has_include" = "yes"; then +- tmp_chg_FLAGS=`echo "$tmp_chg_FLAGS" | "$SED" 's/^-I/ -isystem /g'` +- tmp_chg_FLAGS=`echo "$tmp_chg_FLAGS" | "$SED" 's/ -I/ -isystem /g'` +- CPPFLAGS="$tmp_chg_FLAGS" +- squeeze CPPFLAGS +- fi +- else ++ case $host_os in ++ darwin*) ++ dnl curl-impersonate: On macos, clang gives priority to /usr/local/include ++ dnl over locations specified with -isystem for some unknown reason. In turn ++ dnl this causes clang to use the system's openssl, which conflicts with ++ dnl curl-impersonate's boringssl headers. ++ dnl To prevent that, disable curl's automatic conversion of -I flags to ++ dnl -isystem. + AC_MSG_RESULT([no]) +- fi ++ ;; ++ *) ++ if test "$compiler_id" = "GNU_C" || ++ test "$compiler_id" = "CLANG"; then ++ AC_MSG_RESULT([yes]) ++ tmp_has_include="no" ++ tmp_chg_FLAGS="$CFLAGS" ++ for word1 in $tmp_chg_FLAGS; do ++ case "$word1" in ++ -I*) ++ tmp_has_include="yes" ++ ;; ++ esac ++ done ++ if test "$tmp_has_include" = "yes"; then ++ tmp_chg_FLAGS=`echo "$tmp_chg_FLAGS" | "$SED" 's/^-I/ -isystem /g'` ++ tmp_chg_FLAGS=`echo "$tmp_chg_FLAGS" | "$SED" 's/ -I/ -isystem /g'` ++ CFLAGS="$tmp_chg_FLAGS" ++ squeeze CFLAGS ++ fi ++ tmp_has_include="no" ++ tmp_chg_FLAGS="$CPPFLAGS" ++ for word1 in $tmp_chg_FLAGS; do ++ case "$word1" in ++ -I*) ++ tmp_has_include="yes" ++ ;; ++ esac ++ done ++ if test "$tmp_has_include" = "yes"; then ++ tmp_chg_FLAGS=`echo "$tmp_chg_FLAGS" | "$SED" 's/^-I/ -isystem /g'` ++ tmp_chg_FLAGS=`echo "$tmp_chg_FLAGS" | "$SED" 's/ -I/ -isystem /g'` ++ CPPFLAGS="$tmp_chg_FLAGS" ++ squeeze CPPFLAGS ++ fi ++ else ++ AC_MSG_RESULT([no]) ++ fi ++ ;; ++ esac + ]) + + diff --git a/src/Makefile.am b/src/Makefile.am -index 706f0aac3..7124bf13e 100644 +index f24cb6924..30b4fdb0a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -43,7 +43,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/include \ @@ -2259,16 +2477,19 @@ index 706f0aac3..7124bf13e 100644 SUBDIRS = ../docs -@@ -54,7 +54,7 @@ endif +@@ -54,9 +54,9 @@ endif include Makefile.inc # CURL_FILES comes from Makefile.inc -curl_SOURCES = $(CURL_FILES) +curl_impersonate_chrome_SOURCES = $(CURL_FILES) + if HAVE_WINDRES +-curl_SOURCES += $(CURL_RCFILES) ++curl_impersonate_chrome_SOURCES += $(CURL_RCFILES) + $(CURL_RCFILES): tool_version.h + endif - # This might hold -Werror - CFLAGS += @CURL_CFLAG_EXTRAS@ -@@ -63,9 +63,9 @@ CFLAGS += @CURL_CFLAG_EXTRAS@ +@@ -67,9 +67,9 @@ CFLAGS += @CURL_CFLAG_EXTRAS@ LIBS = $(BLANK_AT_MAKETIME) if USE_EXPLICIT_LIB_DEPS @@ -2281,10 +2502,10 @@ index 706f0aac3..7124bf13e 100644 # if unit tests are enabled, build a static library to link them with diff --git a/src/tool_cfgable.h b/src/tool_cfgable.h -index 7e43fe754..6b698c3b1 100644 +index 9a15659bc..7bf73bd3b 100644 --- a/src/tool_cfgable.h +++ b/src/tool_cfgable.h -@@ -165,8 +165,12 @@ struct OperationConfig { +@@ -160,8 +160,12 @@ struct OperationConfig { bool crlf; char *customrequest; char *ssl_ec_curves; @@ -2297,7 +2518,7 @@ index 7e43fe754..6b698c3b1 100644 long httpversion; bool http09_allowed; bool nobuffer; -@@ -196,6 +200,7 @@ struct OperationConfig { +@@ -191,6 +195,7 @@ struct OperationConfig { struct curl_slist *prequote; long ssl_version; long ssl_version_max; @@ -2305,9 +2526,9 @@ index 7e43fe754..6b698c3b1 100644 long proxy_ssl_version; long ip_version; long create_file_mode; /* CURLOPT_NEW_FILE_PERMS */ -@@ -275,6 +280,8 @@ struct OperationConfig { +@@ -266,6 +271,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 nonpn; /* enable/disable TLS NPN extension */ bool noalpn; /* enable/disable TLS ALPN extension */ + bool alps; /* enable/disable TLS ALPS extension */ + bool noticket; /* enable/disable TLS session ticket */ @@ -2315,10 +2536,10 @@ index 7e43fe754..6b698c3b1 100644 bool abstract_unix_socket; /* path to an abstract Unix domain socket */ bool falsestart; diff --git a/src/tool_getparam.c b/src/tool_getparam.c -index 27e801a98..d02540f76 100644 +index c9810e9d4..0be823c2b 100644 --- a/src/tool_getparam.c +++ b/src/tool_getparam.c -@@ -282,6 +282,13 @@ static const struct LongShort aliases[]= { +@@ -287,6 +287,13 @@ static const struct LongShort aliases[]= { {"EC", "etag-save", ARG_FILENAME}, {"ED", "etag-compare", ARG_FILENAME}, {"EE", "curves", ARG_STRING}, @@ -2332,7 +2553,7 @@ index 27e801a98..d02540f76 100644 {"f", "fail", ARG_BOOL}, {"fa", "fail-early", ARG_BOOL}, {"fb", "styled-output", ARG_BOOL}, -@@ -1859,6 +1866,39 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ +@@ -1940,6 +1947,39 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ GetStr(&config->ssl_ec_curves, nextarg); break; @@ -2373,7 +2594,7 @@ index 27e801a98..d02540f76 100644 return PARAM_OPTION_UNKNOWN; } diff --git a/src/tool_listhelp.c b/src/tool_listhelp.c -index 266f9b0bd..a96c12de0 100644 +index 61550de72..63ea135b3 100644 --- a/src/tool_listhelp.c +++ b/src/tool_listhelp.c @@ -108,6 +108,24 @@ const struct helptxt helptext[] = { @@ -2401,7 +2622,7 @@ index 266f9b0bd..a96c12de0 100644 {"-d, --data ", "HTTP POST data", CURLHELP_IMPORTANT | CURLHELP_HTTP | CURLHELP_POST | CURLHELP_UPLOAD}, -@@ -384,6 +402,9 @@ const struct helptxt helptext[] = { +@@ -387,6 +405,9 @@ const struct helptxt helptext[] = { {" --no-alpn", "Disable the ALPN TLS extension", CURLHELP_TLS | CURLHELP_HTTP}, @@ -2412,10 +2633,10 @@ index 266f9b0bd..a96c12de0 100644 "Disable buffering of the output stream", CURLHELP_CURL}, diff --git a/src/tool_operate.c b/src/tool_operate.c -index c317b3ba7..481c6cd00 100644 +index ead7dca63..dc9f435f5 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c -@@ -1433,6 +1433,15 @@ static CURLcode single_transfer(struct GlobalConfig *global, +@@ -1493,6 +1493,15 @@ static CURLcode single_transfer(struct GlobalConfig *global, return result; } @@ -2428,10 +2649,10 @@ index c317b3ba7..481c6cd00 100644 + my_setopt(curl, CURLOPT_HTTP2_NO_SERVER_PUSH, + config->http2_no_server_push ? 1L : 0L); + - } /* (built_in_protos & CURLPROTO_HTTP) */ + } /* (proto_http) */ - my_setopt_str(curl, CURLOPT_FTPPORT, config->ftpport); -@@ -1520,6 +1529,14 @@ static CURLcode single_transfer(struct GlobalConfig *global, + if(proto_ftp) +@@ -1581,6 +1590,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); @@ -2443,10 +2664,10 @@ index c317b3ba7..481c6cd00 100644 + my_setopt_str(curl, CURLOPT_SSL_CERT_COMPRESSION, + config->ssl_cert_compression); + - if(curlinfo->features & CURL_VERSION_SSL) { - /* Check if config->cert is a PKCS#11 URI and set the - * config->cert_type if necessary */ -@@ -1846,6 +1863,10 @@ static CURLcode single_transfer(struct GlobalConfig *global, + if(config->writeout) + my_setopt_str(curl, CURLOPT_CERTINFO, 1L); + +@@ -1914,6 +1931,10 @@ static CURLcode single_transfer(struct GlobalConfig *global, my_setopt_str(curl, CURLOPT_PROXY_TLS13_CIPHERS, config->proxy_cipher13_list); @@ -2457,7 +2678,7 @@ index c317b3ba7..481c6cd00 100644 /* new in libcurl 7.9.2: */ if(config->disable_epsv) /* disable it */ -@@ -2057,6 +2078,14 @@ static CURLcode single_transfer(struct GlobalConfig *global, +@@ -2123,6 +2144,14 @@ static CURLcode single_transfer(struct GlobalConfig *global, my_setopt(curl, CURLOPT_SSL_ENABLE_ALPN, 0L); } @@ -2473,10 +2694,10 @@ index c317b3ba7..481c6cd00 100644 if(config->unix_socket_path) { if(config->abstract_unix_socket) { diff --git a/src/tool_setopt.c b/src/tool_setopt.c -index 5ff86c7f5..be26f91ea 100644 +index 0f3cc83b9..1c14e9854 100644 --- a/src/tool_setopt.c +++ b/src/tool_setopt.c -@@ -180,6 +180,8 @@ static const struct NameValue setopt_nv_CURLNONZERODEFAULTS[] = { +@@ -153,6 +153,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), @@ -2485,17 +2706,3 @@ index 5ff86c7f5..be26f91ea 100644 NV1(CURLOPT_TCP_NODELAY, 1), NV1(CURLOPT_PROXY_SSL_VERIFYPEER, 1), NV1(CURLOPT_PROXY_SSL_VERIFYHOST, 1), -diff --git a/lib/easy_lock.h b/lib/easy_lock.h -index 819f50ce8..1f54289ce 100644 ---- a/lib/easy_lock.h -+++ b/lib/easy_lock.h -@@ -36,6 +36,9 @@ - - #elif defined (HAVE_ATOMIC) - #include -+#if defined(HAVE_SCHED_YIELD) -+#include -+#endif - - #define curl_simple_lock atomic_bool - #define CURL_SIMPLE_LOCK_INIT false diff --git a/firefox/Dockerfile b/firefox/Dockerfile index 6830c75..4f50042 100644 --- a/firefox/Dockerfile +++ b/firefox/Dockerfile @@ -50,8 +50,8 @@ RUN tar xf ${NSS_VERSION}.tar.gz && \ cd ${NSS_VERSION}/nss && \ ./build.sh -o --disable-tests --static --python=python3 -ARG NGHTTP2_VERSION=nghttp2-1.46.0 -ARG NGHTTP2_URL=https://github.com/nghttp2/nghttp2/releases/download/v1.46.0/nghttp2-1.46.0.tar.bz2 +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 # Download nghttp2 for HTTP/2.0 support. RUN curl -o ${NGHTTP2_VERSION}.tar.bz2 -L ${NGHTTP2_URL} @@ -63,7 +63,7 @@ RUN cd ${NGHTTP2_VERSION} && \ make && make install # Download curl. -ARG CURL_VERSION=curl-7.84.0 +ARG CURL_VERSION=curl-8.1.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/firefox/Dockerfile.alpine b/firefox/Dockerfile.alpine index afb5d58..9804617 100644 --- a/firefox/Dockerfile.alpine +++ b/firefox/Dockerfile.alpine @@ -43,8 +43,8 @@ RUN tar xf ${NSS_VERSION}.tar.gz && \ cd ${NSS_VERSION}/nss && \ ./build.sh -o --disable-tests --static --python=python3 -ARG NGHTTP2_VERSION=nghttp2-1.46.0 -ARG NGHTTP2_URL=https://github.com/nghttp2/nghttp2/releases/download/v1.46.0/nghttp2-1.46.0.tar.bz2 +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 # Download nghttp2 for HTTP/2.0 support. RUN curl -o ${NGHTTP2_VERSION}.tar.bz2 -L ${NGHTTP2_URL} @@ -56,7 +56,7 @@ RUN cd ${NGHTTP2_VERSION} && \ make && make install # Download curl. -ARG CURL_VERSION=curl-7.84.0 +ARG CURL_VERSION=curl-8.1.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/firefox/patches/curl-impersonate.patch b/firefox/patches/curl-impersonate.patch index 444f1e0..28e3b11 100644 --- a/firefox/patches/curl-impersonate.patch +++ b/firefox/patches/curl-impersonate.patch @@ -1,8 +1,8 @@ diff --git a/Makefile.am b/Makefile.am -index 40771ed38..5de6f11b6 100644 +index f25e4e2f0..9a8026915 100644 --- a/Makefile.am +++ b/Makefile.am -@@ -155,13 +155,13 @@ CLEANFILES = $(VC10_LIBVCXPROJ) $(VC10_SRCVCXPROJ) $(VC11_LIBVCXPROJ) \ +@@ -156,13 +156,13 @@ CLEANFILES = $(VC10_LIBVCXPROJ) $(VC10_SRCVCXPROJ) $(VC11_LIBVCXPROJ) \ $(VC14_SRCVCXPROJ) $(VC14_10_LIBVCXPROJ) $(VC14_10_SRCVCXPROJ) \ $(VC14_30_LIBVCXPROJ) $(VC14_30_SRCVCXPROJ) @@ -19,10 +19,10 @@ index 40771ed38..5de6f11b6 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 de2dee5a4..d2cbe4ee1 100644 +index 75a882b12..9310059b9 100644 --- a/configure.ac +++ b/configure.ac -@@ -1331,7 +1331,8 @@ if test X"$OPT_BROTLI" != Xno; then +@@ -1493,7 +1493,8 @@ if test X"$OPT_BROTLI" != Xno; then dnl if given with a prefix, we set -L and -I based on that if test -n "$PREFIX_BROTLI"; then @@ -32,7 +32,7 @@ index de2dee5a4..d2cbe4ee1 100644 LD_BROTLI=-L${PREFIX_BROTLI}/lib$libsuff CPP_BROTLI=-I${PREFIX_BROTLI}/include DIR_BROTLI=${PREFIX_BROTLI}/lib$libsuff -@@ -1341,7 +1342,11 @@ if test X"$OPT_BROTLI" != Xno; then +@@ -1503,7 +1504,11 @@ if test X"$OPT_BROTLI" != Xno; then CPPFLAGS="$CPPFLAGS $CPP_BROTLI" LIBS="$LIB_BROTLI $LIBS" @@ -45,8 +45,8 @@ index de2dee5a4..d2cbe4ee1 100644 AC_CHECK_HEADERS(brotli/decode.h, curl_brotli_msg="enabled (libbrotlidec)" -@@ -4426,8 +4431,8 @@ AC_CONFIG_FILES([Makefile \ - tests/unit/Makefile \ +@@ -4706,8 +4711,8 @@ AC_CONFIG_FILES([Makefile \ + tests/http/clients/Makefile \ packages/Makefile \ packages/vms/Makefile \ - curl-config \ @@ -57,7 +57,7 @@ index de2dee5a4..d2cbe4ee1 100644 AC_OUTPUT diff --git a/curl-config.in b/curl-config.in -index aaf2b8a43..47eff151b 100644 +index 54f92d931..531bec977 100644 --- a/curl-config.in +++ b/curl-config.in @@ -163,9 +163,9 @@ while test $# -gt 0; do @@ -76,28 +76,28 @@ index aaf2b8a43..47eff151b 100644 --static-libs) if test "X@ENABLE_STATIC@" != "Xno" ; then -- echo @libdir@/libcurl.@libext@ @LDFLAGS@ @LIBCURL_LIBS@ -+ echo @libdir@/libcurl-impersonate-ff.@libext@ @LDFLAGS@ @LIBCURL_LIBS@ +- echo "@libdir@/libcurl.@libext@" @LDFLAGS@ @LIBCURL_LIBS@ ++ echo "@libdir@/libcurl-impersonate-ff.@libext@" @LDFLAGS@ @LIBCURL_LIBS@ else echo "curl was built with static libraries disabled" >&2 exit 1 diff --git a/include/curl/curl.h b/include/curl/curl.h -index b00648e79..eefa36f2e 100644 +index 944352421..07d08a0bb 100644 --- a/include/curl/curl.h +++ b/include/curl/curl.h -@@ -2143,6 +2143,10 @@ typedef enum { - /* set the SSH host key callback custom pointer */ - CURLOPT(CURLOPT_SSH_HOSTKEYDATA, CURLOPTTYPE_CBPOINT, 317), +@@ -2207,6 +2207,10 @@ typedef enum { + /* Can leak things, gonna exit() soon */ + CURLOPT(CURLOPT_QUICK_EXIT, CURLOPTTYPE_LONG, 322), + /* curl-impersonate: A list of headers used by the impersonated browser. + * If given, merged with CURLOPT_HTTPHEADER. */ -+ CURLOPT(CURLOPT_HTTPBASEHEADER, CURLOPTTYPE_SLISTPOINT, 318), ++ CURLOPT(CURLOPT_HTTPBASEHEADER, CURLOPTTYPE_SLISTPOINT, 323), + CURLOPT_LASTENTRY /* the last unused */ } CURLoption; diff --git a/include/curl/easy.h b/include/curl/easy.h -index 9c7e63ada..a3c54c4af 100644 +index 1285101c5..c620065dc 100644 --- a/include/curl/easy.h +++ b/include/curl/easy.h @@ -43,6 +43,16 @@ CURL_EXTERN CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...); @@ -118,21 +118,26 @@ index 9c7e63ada..a3c54c4af 100644 * NAME curl_easy_getinfo() * diff --git a/lib/Makefile.am b/lib/Makefile.am -index 18ce47ea9..ea403a105 100644 +index 3c0a70912..e4a77a0e8 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am -@@ -30,7 +30,7 @@ EXTRA_DIST = Makefile.m32 config-win32.h config-win32ce.h config-plan9.h \ - libcurl.plist libcurl.rc config-amigaos.h makefile.amiga config-win32ce.h \ - config-os400.h setup-os400.h $(CMAKE_DIST) setup-win32.h .checksrc +@@ -31,7 +31,7 @@ EXTRA_DIST = Makefile.mk config-win32.h config-win32ce.h config-plan9.h \ + config-os400.h setup-os400.h $(CMAKE_DIST) setup-win32.h .checksrc \ + Makefile.soname -lib_LTLIBRARIES = libcurl.la +lib_LTLIBRARIES = libcurl-impersonate-ff.la if BUILD_UNITTESTS noinst_LTLIBRARIES = libcurlu.la -@@ -75,43 +75,43 @@ AM_CPPFLAGS += -DBUILDING_LIBCURL - AM_LDFLAGS = - AM_CFLAGS = +@@ -67,51 +67,51 @@ AM_CFLAGS = + # Makefile.inc provides the CSOURCES and HHEADERS defines + include Makefile.inc + +-libcurl_la_SOURCES = $(CSOURCES) $(HHEADERS) +-libcurlu_la_SOURCES = $(CSOURCES) $(HHEADERS) ++libcurl_impersonate_ff_la_SOURCES = $(CSOURCES) $(HHEADERS) ++libcurlu_impersonate_ff_la_SOURCES = $(CSOURCES) $(HHEADERS) -libcurl_la_CPPFLAGS_EXTRA = -libcurl_la_LDFLAGS_EXTRA = @@ -170,6 +175,12 @@ index 18ce47ea9..ea403a105 100644 if USE_CPPFLAG_CURL_STATICLIB -libcurl_la_CPPFLAGS_EXTRA += -DCURL_STATICLIB +libcurl_impersonate_ff_la_CPPFLAGS_EXTRA += -DCURL_STATICLIB + else + if HAVE_WINDRES +-libcurl_la_SOURCES += $(LIB_RCFILES) ++libcurl_impersonate_ff_la_SOURCES += $(LIB_RCFILES) + $(LIB_RCFILES): $(top_srcdir)/include/curl/curlver.h + endif endif if DOING_CURL_SYMBOL_HIDING @@ -188,41 +199,83 @@ index 18ce47ea9..ea403a105 100644 libcurlu_la_CPPFLAGS = $(AM_CPPFLAGS) -DCURL_STATICLIB -DUNITTESTS libcurlu_la_LDFLAGS = $(AM_LDFLAGS) -static $(LIBCURL_LIBS) -@@ -120,7 +120,7 @@ libcurlu_la_CFLAGS = $(AM_CFLAGS) - # Makefile.inc provides the CSOURCES and HHEADERS defines - include Makefile.inc - --libcurl_la_SOURCES = $(CSOURCES) $(HHEADERS) -+libcurl_impersonate_ff_la_SOURCES = $(CSOURCES) $(HHEADERS) - libcurlu_la_SOURCES = $(CSOURCES) $(HHEADERS) - - CHECKSRC = $(CS_$(V)) diff --git a/lib/Makefile.inc b/lib/Makefile.inc -index 9bd8e324b..bfd5e90e2 100644 +index f815170a7..9d9417edc 100644 --- a/lib/Makefile.inc +++ b/lib/Makefile.inc -@@ -165,6 +165,7 @@ LIB_CFILES = \ - idn_win32.c \ +@@ -174,6 +174,7 @@ LIB_CFILES = \ + idn.c \ if2ip.c \ imap.c \ + impersonate.c \ inet_ntop.c \ inet_pton.c \ krb5.c \ +diff --git a/lib/dynhds.c b/lib/dynhds.c +index b325e0060..4c8a73bab 100644 +--- a/lib/dynhds.c ++++ b/lib/dynhds.c +@@ -52,6 +52,8 @@ entry_new(const char *name, size_t namelen, + e->valuelen = valuelen; + if(opts & DYNHDS_OPT_LOWERCASE) + Curl_strntolower(e->name, e->name, e->namelen); ++ if(opts & DYNHDS_OPT_LOWERCASE_VAL) ++ Curl_strntolower(e->value, e->value, e->valuelen); + return e; + } + +@@ -134,6 +136,16 @@ void Curl_dynhds_set_opts(struct dynhds *dynhds, int opts) + dynhds->opts = opts; + } + ++void Curl_dynhds_set_opt(struct dynhds *dynhds, int opt) ++{ ++ dynhds->opts |= opt; ++} ++ ++void Curl_dynhds_del_opt(struct dynhds *dynhds, int opt) ++{ ++ dynhds->opts &= ~opt; ++} ++ + struct dynhds_entry *Curl_dynhds_getn(struct dynhds *dynhds, size_t n) + { + DEBUGASSERT(dynhds); +diff --git a/lib/dynhds.h b/lib/dynhds.h +index 777baa58a..2d542dfd6 100644 +--- a/lib/dynhds.h ++++ b/lib/dynhds.h +@@ -53,6 +53,7 @@ struct dynhds { + + #define DYNHDS_OPT_NONE (0) + #define DYNHDS_OPT_LOWERCASE (1 << 0) ++#define DYNHDS_OPT_LOWERCASE_VAL (1 << 1) + + /** + * Init for use on first time or after a reset. +@@ -82,6 +83,8 @@ size_t Curl_dynhds_count(struct dynhds *dynhds); + * This will not have an effect on already existing headers. + */ + void Curl_dynhds_set_opts(struct dynhds *dynhds, int opts); ++void Curl_dynhds_set_opt(struct dynhds *dynhds, int opt); ++void Curl_dynhds_del_opt(struct dynhds *dynhds, int opt); + + /** + * Return the n-th header entry or NULL if it does not exist. diff --git a/lib/easy.c b/lib/easy.c -index 704a59df6..349d03933 100644 +index d36cc03d1..c5a21e4e3 100644 --- a/lib/easy.c +++ b/lib/easy.c -@@ -81,6 +81,8 @@ +@@ -73,6 +73,8 @@ #include "dynbuf.h" #include "altsvc.h" #include "hsts.h" +#include "strcase.h" +#include "impersonate.h" - /* The last 3 #include files should be in this order */ - #include "curl_printf.h" -@@ -332,6 +334,76 @@ CURLsslset curl_global_sslset(curl_sslbackend id, const char *name, + #include "easy_lock.h" + +@@ -330,6 +332,76 @@ CURLsslset curl_global_sslset(curl_sslbackend id, const char *name, return rc; } @@ -240,7 +293,7 @@ index 704a59df6..349d03933 100644 + struct curl_slist *headers = NULL; + + for (opts = impersonations; opts->target != NULL; opts++) { -+ if (Curl_strncasecompare(target, opts->target, strlen(opts->target))) { ++ if (strncasecompare(target, opts->target, strlen(opts->target))) { + break; + } + } @@ -299,7 +352,7 @@ index 704a59df6..349d03933 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. -@@ -340,6 +412,8 @@ struct Curl_easy *curl_easy_init(void) +@@ -338,6 +410,8 @@ struct Curl_easy *curl_easy_init(void) { CURLcode result; struct Curl_easy *data; @@ -308,7 +361,7 @@ index 704a59df6..349d03933 100644 /* Make sure we inited the global SSL stuff */ global_init_lock(); -@@ -362,6 +436,29 @@ struct Curl_easy *curl_easy_init(void) +@@ -360,6 +434,29 @@ struct Curl_easy *curl_easy_init(void) return NULL; } @@ -323,7 +376,7 @@ index 704a59df6..349d03933 100644 + env_headers = curl_getenv("CURL_IMPERSONATE_HEADERS"); + if(env_headers) { + result = curl_easy_impersonate(data, env_target, -+ !Curl_strcasecompare(env_headers, "no")); ++ !strcasecompare(env_headers, "no")); + free(env_headers); + } else { + result = curl_easy_impersonate(data, env_target, true); @@ -338,7 +391,7 @@ index 704a59df6..349d03933 100644 return data; } -@@ -936,6 +1033,13 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) +@@ -930,6 +1027,13 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) outcurl->state.referer_alloc = TRUE; } @@ -352,7 +405,7 @@ index 704a59df6..349d03933 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]) { -@@ -1025,6 +1129,9 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) +@@ -1019,6 +1123,9 @@ fail: */ void curl_easy_reset(struct Curl_easy *data) { @@ -362,7 +415,7 @@ index 704a59df6..349d03933 100644 Curl_free_request_state(data); /* zero out UserDefined data: */ -@@ -1049,6 +1156,23 @@ void curl_easy_reset(struct Curl_easy *data) +@@ -1043,6 +1150,23 @@ void curl_easy_reset(struct Curl_easy *data) #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH) Curl_http_auth_cleanup_digest(data); #endif @@ -376,7 +429,7 @@ index 704a59df6..349d03933 100644 + env_headers = curl_getenv("CURL_IMPERSONATE_HEADERS"); + if(env_headers) { + curl_easy_impersonate(data, env_target, -+ !Curl_strcasecompare(env_headers, "no")); ++ !strcasecompare(env_headers, "no")); + free(env_headers); + } else { + curl_easy_impersonate(data, env_target, true); @@ -387,10 +440,10 @@ index 704a59df6..349d03933 100644 /* diff --git a/lib/easyoptions.c b/lib/easyoptions.c -index c99f135ff..d70ff8c51 100644 +index a9c1efd00..e04b42381 100644 --- a/lib/easyoptions.c +++ b/lib/easyoptions.c -@@ -132,6 +132,7 @@ struct curl_easyoption Curl_easyopts[] = { +@@ -134,6 +134,7 @@ struct curl_easyoption Curl_easyopts[] = { {"HTTP200ALIASES", CURLOPT_HTTP200ALIASES, CURLOT_SLIST, 0}, {"HTTPAUTH", CURLOPT_HTTPAUTH, CURLOT_VALUES, 0}, {"HTTPGET", CURLOPT_HTTPGET, CURLOT_LONG, 0}, @@ -398,43 +451,19 @@ index c99f135ff..d70ff8c51 100644 {"HTTPHEADER", CURLOPT_HTTPHEADER, CURLOT_SLIST, 0}, {"HTTPPOST", CURLOPT_HTTPPOST, CURLOT_OBJECT, 0}, {"HTTPPROXYTUNNEL", CURLOPT_HTTPPROXYTUNNEL, CURLOT_LONG, 0}, -diff --git a/lib/h2h3.c b/lib/h2h3.c -index 9453cf55b..ba9433cb9 100644 ---- a/lib/h2h3.c -+++ b/lib/h2h3.c -@@ -43,7 +43,8 @@ - - /* Index where :authority header field will appear in request header - field list. */ --#define AUTHORITY_DST_IDX 3 -+/* curl-impersonate: Put the ":authority" header in the second place. */ -+#define AUTHORITY_DST_IDX 2 - - /* USHRT_MAX is 65535 == 0xffff */ - #define HEADER_OVERFLOW(x) \ -@@ -258,9 +259,6 @@ CURLcode Curl_pseudo_headers(struct Curl_easy *data, - nva[i].valuelen = (end - hdbuf); - } - -- nva[i].value = hdbuf; -- nva[i].valuelen = (end - hdbuf); -- - ++i; - } - diff --git a/lib/http.c b/lib/http.c -index 258722a60..9a06e281a 100644 +index 219dcc2c0..19ddd1d36 100644 --- a/lib/http.c +++ b/lib/http.c -@@ -85,6 +85,7 @@ - #include "altsvc.h" +@@ -89,6 +89,7 @@ #include "hsts.h" + #include "ws.h" #include "c-hyper.h" +#include "slist.h" + #include "curl_ctype.h" /* The last 3 #include files should be in this order */ - #include "curl_printf.h" -@@ -1804,6 +1805,15 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data, +@@ -1881,6 +1882,15 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data, int numlists = 1; /* by default */ int i; @@ -450,7 +479,7 @@ index 258722a60..9a06e281a 100644 #ifndef CURL_DISABLE_PROXY enum proxy_use proxy; -@@ -1815,10 +1825,10 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data, +@@ -1892,10 +1902,10 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data, switch(proxy) { case HEADER_SERVER: @@ -463,7 +492,7 @@ index 258722a60..9a06e281a 100644 if(data->set.sep_headers) { h[1] = data->set.proxyheaders; numlists++; -@@ -1828,12 +1838,12 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data, +@@ -1905,12 +1915,12 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data, if(data->set.sep_headers) h[0] = data->set.proxyheaders; else @@ -478,7 +507,7 @@ index 258722a60..9a06e281a 100644 #endif /* loop through one or two lists */ -@@ -2069,6 +2079,108 @@ void Curl_http_method(struct Curl_easy *data, struct connectdata *conn, +@@ -2146,6 +2156,108 @@ void Curl_http_method(struct Curl_easy *data, struct connectdata *conn, *reqp = httpreq; } @@ -587,7 +616,7 @@ index 258722a60..9a06e281a 100644 CURLcode Curl_http_useragent(struct Curl_easy *data) { /* The User-Agent string might have been allocated in url.c already, because -@@ -3088,6 +3200,11 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) +@@ -3165,6 +3277,11 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) http = data->req.p.http; DEBUGASSERT(http); @@ -599,54 +628,79 @@ index 258722a60..9a06e281a 100644 result = Curl_http_host(data, conn); if(result) return result; +@@ -4818,23 +4935,32 @@ CURLcode Curl_http_req_to_h2(struct dynhds *h2_headers, + Curl_dynhds_set_opts(h2_headers, DYNHDS_OPT_LOWERCASE); + result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_METHOD), + req->method, strlen(req->method)); +- if(!result && scheme) { +- result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_SCHEME), +- scheme, strlen(scheme)); ++ if(!result && req->path) { ++ result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_PATH), ++ req->path, strlen(req->path)); + } + if(!result && authority) { + result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_AUTHORITY), + authority, strlen(authority)); + } +- if(!result && req->path) { +- result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_PATH), +- req->path, strlen(req->path)); ++ if(!result && scheme) { ++ result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_SCHEME), ++ scheme, strlen(scheme)); + } + for(i = 0; !result && i < Curl_dynhds_count(&req->headers); ++i) { + e = Curl_dynhds_getn(&req->headers, i); + if(!h2_non_field(e->name, e->namelen)) { ++ /* curl-impersonate: ++ * Some HTTP/2 servers reject 'te' header value that is not lowercase (e.g. 'Trailers). ++ * Convert to lowercase explicitly. ++ */ ++ if(e->namelen == 2 && strcasecompare(e->name, "te")) ++ Curl_dynhds_set_opt(h2_headers, DYNHDS_OPT_LOWERCASE_VAL); ++ + result = Curl_dynhds_add(h2_headers, e->name, e->namelen, + e->value, e->valuelen); ++ ++ Curl_dynhds_del_opt(h2_headers, DYNHDS_OPT_LOWERCASE_VAL); + } + } + diff --git a/lib/http2.c b/lib/http2.c -index f6364d0e0..b5cb05e7e 100644 +index c666192fc..e926eb3f5 100644 --- a/lib/http2.c +++ b/lib/http2.c -@@ -61,7 +61,7 @@ +@@ -63,12 +63,13 @@ #define NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE 1 #endif --#define HTTP2_HUGE_WINDOW_SIZE (32 * 1024 * 1024) /* 32 MB */ -+#define HTTP2_HUGE_WINDOW_SIZE (12 * 1024 * 1024) /* 12 MB */ +- + /* buffer dimensioning: + * use 16K as chunk size, as that fits H2 DATA frames well */ + #define H2_CHUNK_SIZE (16 * 1024) + /* this is how much we want "in flight" for a stream */ +-#define H2_STREAM_WINDOW_SIZE (10 * 1024 * 1024) ++/* curl-impersonate: Set H2_STREAM_WINDOW_SIZE to 128kb so that the initial ++ * window size matches what Firefox sends. */ ++#define H2_STREAM_WINDOW_SIZE (128 * 1024) + /* on receving from TLS, we prep for holding a full stream window */ + #define H2_NW_RECV_CHUNKS (H2_STREAM_WINDOW_SIZE / H2_CHUNK_SIZE) + /* on send into TLS, we just want to accumulate small frames */ +@@ -86,7 +87,8 @@ + * will block their received QUOTA in the connection window. And if we + * run out of space, the server is blocked from sending us any data. + * See #10988 for an issue with this. */ +-#define HTTP2_HUGE_WINDOW_SIZE (100 * H2_STREAM_WINDOW_SIZE) ++/* curl-impersonate: set HTTP2_HUGE_WINDOW_SIZE to 12MB to match Firefox. */ ++#define HTTP2_HUGE_WINDOW_SIZE (96 * H2_STREAM_WINDOW_SIZE) - #ifdef DEBUG_HTTP2 - #define H2BUGF(x) x -@@ -79,13 +79,20 @@ static int h2_process_pending_input(struct Curl_easy *data, - struct http_conn *httpc, - CURLcode *err); - -+ -+/* -+ * curl-impersonate: Set the HTTP/2 stream weight to the one used by Firefox -+ * by default to fetch html resources. -+ */ -+#define FIREFOX_DEFAULT_STREAM_WEIGHT (42) -+ - /* - * Curl_http2_init_state() is called when the easy handle is created and - * allows for HTTP/2 specific init of state. - */ - void Curl_http2_init_state(struct UrlState *state) + #define H2_SETTINGS_IV_LEN 3 + #define H2_BINSETTINGS_LEN 80 +@@ -94,14 +96,18 @@ + static int populate_settings(nghttp2_settings_entry *iv, + struct Curl_easy *data) { -- state->stream_weight = NGHTTP2_DEFAULT_WEIGHT; -+ state->stream_weight = FIREFOX_DEFAULT_STREAM_WEIGHT; - } - - /* -@@ -94,7 +101,7 @@ void Curl_http2_init_state(struct UrlState *state) - */ - void Curl_http2_init_userset(struct UserDefined *set) - { -- set->stream_weight = NGHTTP2_DEFAULT_WEIGHT; -+ set->stream_weight = FIREFOX_DEFAULT_STREAM_WEIGHT; - } - - static int http2_getsock(struct Curl_easy *data, -@@ -1212,14 +1219,18 @@ static void populate_settings(struct Curl_easy *data, - { - nghttp2_settings_entry *iv = httpc->local_settings; - - iv[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS; - iv[0].value = Curl_multi_max_concurrent_streams(data->multi); + /* curl-impersonate: Align HTTP/2 settings to Firefox's */ @@ -654,8 +708,7 @@ index f6364d0e0..b5cb05e7e 100644 + iv[0].value = 0x10000; iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE; -- iv[1].value = HTTP2_HUGE_WINDOW_SIZE; -+ iv[1].value = 0x20000; + iv[1].value = H2_STREAM_WINDOW_SIZE; - iv[2].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH; - iv[2].value = data->multi->push_cb != NULL; @@ -665,9 +718,123 @@ index f6364d0e0..b5cb05e7e 100644 + // iv[2].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH; + // iv[2].value = data->multi->push_cb != NULL; - httpc->local_settings_num = 3; + return 3; } -@@ -1586,12 +1597,18 @@ static ssize_t http2_handle_stream_close(struct connectdata *conn, +@@ -392,6 +398,71 @@ static void multi_connchanged(struct Curl_multi *multi) + multi->recheckstate = TRUE; + } + ++/* ++ * curl-impersonate: Start with stream id 15 as Firefox does. ++ */ ++#define FIREFOX_DEFAULT_STREAM_ID (15) ++ ++static CURLcode http2_set_stream_priority(struct Curl_cfilter *cf, ++ struct Curl_easy *data, ++ int32_t stream_id, ++ int32_t dep_stream_id, ++ int32_t weight) ++{ ++ int rv; ++ struct cf_h2_ctx *ctx = cf->ctx; ++ nghttp2_priority_spec pri_spec; ++ ++ nghttp2_priority_spec_init(&pri_spec, dep_stream_id, weight, 0); ++ rv = nghttp2_submit_priority(ctx->h2, NGHTTP2_FLAG_NONE, ++ stream_id, &pri_spec); ++ if(rv) { ++ failf(data, "nghttp2_submit_priority() failed: %s(%d)", ++ nghttp2_strerror(rv), rv); ++ return CURLE_HTTP2; ++ } ++ ++ return CURLE_OK; ++} ++ ++/* ++ * curl-impersonate: Firefox uses an elaborate scheme of http/2 streams to ++ * split the load for html/js/css/images. It builds a tree of streams with ++ * different weights (priorities) by default and communicates this to the ++ * server. Imitate that behavior. ++ */ ++static CURLcode http2_set_stream_priorities(struct Curl_cfilter *cf, ++ struct Curl_easy *data) ++{ ++ CURLcode result; ++ ++ result = http2_set_stream_priority(cf, data, 3, 0, 201); ++ if(result) ++ return result; ++ ++ result = http2_set_stream_priority(cf, data, 5, 0, 101); ++ if(result) ++ return result; ++ ++ result = http2_set_stream_priority(cf, data, 7, 0, 0); ++ if(result) ++ return result; ++ ++ result = http2_set_stream_priority(cf, data, 9, 7, 0); ++ if(result) ++ return result; ++ ++ result = http2_set_stream_priority(cf, data, 11, 3, 0); ++ if(result) ++ return result; ++ ++ result = http2_set_stream_priority(cf, data, 13, 0, 241); ++ if(result) ++ return result; ++ ++ return CURLE_OK; ++} ++ + /* + * Initialize the cfilter context + */ +@@ -492,6 +563,13 @@ static CURLcode cf_h2_ctx_init(struct Curl_cfilter *cf, + goto out; + } + ++ result = http2_set_stream_priorities(cf, data); ++ if(result) ++ goto out; ++ ++ /* Best effort to set the request's stream id to 15, like Firefox does. */ ++ nghttp2_session_set_next_stream_id(ctx->h2, FIREFOX_DEFAULT_STREAM_ID); ++ + /* all set, traffic will be send on connect */ + result = CURLE_OK; + +@@ -1616,18 +1694,25 @@ out: + return rv; + } + ++ ++/* ++ * curl-impersonate: Set the HTTP/2 stream weight to the one used by Firefox ++ * by default to fetch html resources. ++ */ ++#define FIREFOX_DEFAULT_STREAM_WEIGHT (42) ++ + static int sweight_wanted(const struct Curl_easy *data) + { + /* 0 weight is not set by user and we take the nghttp2 default one */ + return data->set.priority.weight? +- data->set.priority.weight : NGHTTP2_DEFAULT_WEIGHT; ++ data->set.priority.weight : FIREFOX_DEFAULT_STREAM_WEIGHT; + } + + 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; + } + + /* +@@ -1636,12 +1721,18 @@ static int sweight_in_effect(const struct Curl_easy *data) * struct. */ @@ -680,117 +847,22 @@ index f6364d0e0..b5cb05e7e 100644 static void h2_pri_spec(struct Curl_easy *data, nghttp2_priority_spec *pri_spec) { - struct HTTP *depstream = (data->set.stream_depends_on? - data->set.stream_depends_on->req.p.http:NULL); -- int32_t depstream_id = depstream? depstream->stream_id:0; -+ int32_t depstream_id = depstream? depstream->stream_id:FIREFOX_DEFAULT_STREAM_DEP; - nghttp2_priority_spec_init(pri_spec, depstream_id, data->set.stream_weight, - data->set.stream_depends_e); - data->state.stream_weight = data->set.stream_weight; -@@ -2068,6 +2085,73 @@ CURLcode Curl_http2_setup(struct Curl_easy *data, - return CURLE_OK; - } - -+/* -+ * curl-impersonate: Start with stream id 15 as Firefox does. -+ */ -+#define FIREFOX_DEFAULT_STREAM_ID (15) -+ -+static CURLcode http2_set_stream_priority(struct Curl_easy *data, -+ int32_t stream_id, -+ int32_t dep_stream_id, -+ int32_t weight) -+{ -+ int rv; -+ nghttp2_priority_spec pri_spec; -+ struct connectdata *conn = data->conn; -+ struct http_conn *httpc = &conn->proto.httpc; -+ -+ nghttp2_priority_spec_init(&pri_spec, dep_stream_id, weight, 0); -+ rv = nghttp2_submit_priority(httpc->h2, NGHTTP2_FLAG_NONE, -+ stream_id, &pri_spec); -+ if(rv) { -+ failf(data, "nghttp2_submit_priority() failed: %s(%d)", -+ nghttp2_strerror(rv), rv); -+ return CURLE_HTTP2; -+ } -+ -+ return CURLE_OK; -+} -+ -+ -+/* -+ * curl-impersonate: Firefox uses an elaborate scheme of http/2 streams to -+ * split the load for html/js/css/images. It builds a tree of streams with -+ * different weights (priorities) by default and communicates this to the -+ * server. Imitate that behavior. -+ */ -+static CURLcode http2_set_stream_priorities(struct Curl_easy *data) -+{ -+ CURLcode result; -+ struct connectdata *conn = data->conn; -+ struct http_conn *httpc = &conn->proto.httpc; -+ -+ result = http2_set_stream_priority(data, 3, 0, 201); -+ if(result) -+ return result; -+ -+ result = http2_set_stream_priority(data, 5, 0, 101); -+ if(result) -+ return result; -+ -+ result = http2_set_stream_priority(data, 7, 0, 0); -+ if(result) -+ return result; -+ -+ result = http2_set_stream_priority(data, 9, 7, 0); -+ if(result) -+ return result; -+ -+ result = http2_set_stream_priority(data, 11, 3, 0); -+ if(result) -+ return result; -+ -+ result = http2_set_stream_priority(data, 13, 0, 241); -+ if(result) -+ return result; -+ -+ return CURLE_OK; -+} -+ - CURLcode Curl_http2_switched(struct Curl_easy *data, - const char *mem, size_t nread) - { -@@ -2076,6 +2160,7 @@ CURLcode Curl_http2_switched(struct Curl_easy *data, - struct http_conn *httpc = &conn->proto.httpc; - int rv; - struct HTTP *stream = data->req.p.http; -+ nghttp2_priority_spec pri_spec; - - result = Curl_http2_setup(data, conn); - if(result) -@@ -2130,6 +2215,13 @@ CURLcode Curl_http2_switched(struct Curl_easy *data, - return CURLE_HTTP2; - } - -+ result = http2_set_stream_priorities(data); -+ if(result) -+ return result; -+ -+ /* Best effort to set the request's stream id to 15, like Firefox does. */ -+ nghttp2_session_set_next_stream_id(httpc->h2, FIREFOX_DEFAULT_STREAM_ID); -+ - /* we are going to copy mem to httpc->inbuf. This is required since - mem is part of buffer pointed by stream->mem, and callbacks - called by nghttp2_session_mem_recv() will write stream specific + struct Curl_data_priority *prio = &data->set.priority; + struct 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; + nghttp2_priority_spec_init(pri_spec, depstream_id, + sweight_wanted(data), + data->set.priority.exclusive); diff --git a/lib/impersonate.c b/lib/impersonate.c new file mode 100644 -index 000000000..33b822c1a +index 000000000..de3d5a258 --- /dev/null +++ b/lib/impersonate.c -@@ -0,0 +1,221 @@ +@@ -0,0 +1,222 @@ +#include "curl_setup.h" + ++#include +#include "impersonate.h" + +const struct impersonate_opts impersonations[] = { @@ -1042,7 +1114,7 @@ index 000000000..964b81f2e + +#endif /* HEADER_CURL_IMPERSONATE_H */ diff --git a/lib/setopt.c b/lib/setopt.c -index 6b16e1c7c..a83d69917 100644 +index 0c3b9634d..bd7c6746d 100644 --- a/lib/setopt.c +++ b/lib/setopt.c @@ -50,6 +50,7 @@ @@ -1053,10 +1125,10 @@ index 6b16e1c7c..a83d69917 100644 /* The last 3 #include files should be in this order */ #include "curl_printf.h" -@@ -674,6 +675,23 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) - va_arg(param, char *)); - break; - +@@ -967,6 +968,23 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) + #if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_SMTP) || \ + !defined(CURL_DISABLE_IMAP) + # if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_MIME) + case CURLOPT_HTTPBASEHEADER: + /* + * curl-impersonate: @@ -1078,10 +1150,10 @@ index 6b16e1c7c..a83d69917 100644 /* * Set a list with HTTP headers to use (or replace internals with) diff --git a/lib/transfer.c b/lib/transfer.c -index 1720b24b1..dcae3c143 100644 +index d2ff0c24c..56e2090b6 100644 --- a/lib/transfer.c +++ b/lib/transfer.c -@@ -104,7 +104,15 @@ char *Curl_checkheaders(const struct Curl_easy *data, +@@ -106,7 +106,15 @@ char *Curl_checkheaders(const struct Curl_easy *data, DEBUGASSERT(thislen); DEBUGASSERT(thisheader[thislen-1] != ':'); @@ -1099,10 +1171,10 @@ index 1720b24b1..dcae3c143 100644 Curl_headersep(head->data[thislen]) ) return head->data; diff --git a/lib/url.c b/lib/url.c -index 1114c6c12..89e29be62 100644 +index b37d13f8f..ffb74cc4f 100644 --- a/lib/url.c +++ b/lib/url.c -@@ -465,6 +465,11 @@ CURLcode Curl_close(struct Curl_easy **datap) +@@ -444,6 +444,11 @@ CURLcode Curl_close(struct Curl_easy **datap) Curl_safefree(data->state.aptr.proxyuser); Curl_safefree(data->state.aptr.proxypasswd); @@ -1115,10 +1187,10 @@ index 1114c6c12..89e29be62 100644 if(data->req.doh) { Curl_dyn_free(&data->req.doh->probe[0].serverdoh); diff --git a/lib/urldata.h b/lib/urldata.h -index bcb4d460c..148cd1927 100644 +index f02e66541..d6162a80e 100644 --- a/lib/urldata.h +++ b/lib/urldata.h -@@ -1453,6 +1453,19 @@ struct UrlState { +@@ -1395,6 +1395,19 @@ struct UrlState { CURLcode hresult; /* used to pass return codes back from hyper callbacks */ #endif @@ -1139,7 +1211,7 @@ index bcb4d460c..148cd1927 100644 killed. */ struct dynamically_allocated_data { diff --git a/lib/vtls/nss.c b/lib/vtls/nss.c -index 9d3a8584c..8ffd68171 100644 +index 5e5dbb744..2604fc755 100644 --- a/lib/vtls/nss.c +++ b/lib/vtls/nss.c @@ -145,6 +145,7 @@ static const struct cipher_s cipherlist[] = { @@ -1246,7 +1318,7 @@ index 9d3a8584c..8ffd68171 100644 /* * Return true if at least one cipher-suite is enabled. Used to determine * if we need to call NSS_SetDomesticPolicy() to enable the default ciphers. -@@ -1347,6 +1437,7 @@ static CURLcode nss_load_module(SECMODModule **pmod, const char *library, +@@ -1341,6 +1431,7 @@ static CURLcode nss_load_module(SECMODModule **pmod, const char *library, if(module) SECMOD_DestroyModule(module); @@ -1254,20 +1326,20 @@ index 9d3a8584c..8ffd68171 100644 return CURLE_FAILED_INIT; } -@@ -1970,6 +2061,12 @@ static CURLcode nss_setup_connect(struct Curl_easy *data, +@@ -1923,6 +2014,12 @@ static CURLcode nss_setup_connect(struct Curl_cfilter *cf, if(SSL_OptionSet(model, SSL_NO_CACHE, ssl_no_cache) != SECSuccess) goto error; -+ if(SSL_SET_OPTION(primary.sessionid)) { ++ if(ssl_config->primary.sessionid) { + if(SSL_OptionSet(model, SSL_ENABLE_SESSION_TICKETS, + PR_TRUE) != SECSuccess) + goto error; + } + /* enable/disable the requested SSL version(s) */ - if(nss_init_sslver(&sslver, data, conn) != CURLE_OK) + if(nss_init_sslver(&sslver, cf, data) != CURLE_OK) goto error; -@@ -2009,6 +2106,14 @@ static CURLcode nss_setup_connect(struct Curl_easy *data, +@@ -1962,6 +2059,14 @@ static CURLcode nss_setup_connect(struct Curl_cfilter *cf, } } @@ -1279,32 +1351,24 @@ index 9d3a8584c..8ffd68171 100644 + goto error; + } + - if(!SSL_CONN_CONFIG(verifypeer) && SSL_CONN_CONFIG(verifyhost)) + if(!conn_config->verifypeer && conn_config->verifyhost) infof(data, "WARNING: ignoring value of ssl.verifyhost"); -@@ -2165,6 +2270,10 @@ static CURLcode nss_setup_connect(struct Curl_easy *data, - int cur = 0; - unsigned char protocols[128]; - -+ protocols[cur++] = ALPN_HTTP_1_1_LENGTH; -+ memcpy(&protocols[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH); -+ cur += ALPN_HTTP_1_1_LENGTH; -+ +diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c +index 32334016b..a9b6299b2 100644 +--- a/lib/vtls/vtls.c ++++ b/lib/vtls/vtls.c +@@ -139,7 +139,7 @@ static const struct alpn_spec ALPN_SPEC_H11 = { + }; #ifdef USE_HTTP2 - if(data->state.httpwant >= CURL_HTTP_VERSION_2 - #ifndef CURL_DISABLE_PROXY -@@ -2176,9 +2285,6 @@ static CURLcode nss_setup_connect(struct Curl_easy *data, - cur += ALPN_H2_LENGTH; - } + static const struct alpn_spec ALPN_SPEC_H2_H11 = { +- { ALPN_H2, ALPN_HTTP_1_1 }, 2 ++ { ALPN_HTTP_1_1, ALPN_H2 }, 2 + }; #endif -- protocols[cur++] = ALPN_HTTP_1_1_LENGTH; -- memcpy(&protocols[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH); -- cur += ALPN_HTTP_1_1_LENGTH; - if(SSL_SetNextProtoNego(backend->handle, protocols, cur) != SECSuccess) - goto error; diff --git a/libcurl.pc.in b/libcurl.pc.in -index 49485f192..7c2ea437c 100644 +index 9db6b0f89..9e2f19af9 100644 --- a/libcurl.pc.in +++ b/libcurl.pc.in @@ -36,6 +36,6 @@ Name: libcurl @@ -1316,7 +1380,7 @@ index 49485f192..7c2ea437c 100644 Libs.private: @LIBCURL_LIBS@ Cflags: -I${includedir} @CPPFLAG_CURL_STATICLIB@ diff --git a/m4/curl-nss.m4 b/m4/curl-nss.m4 -index cb162755d..13ee571aa 100644 +index 2916c3613..f07fa30ac 100644 --- a/m4/curl-nss.m4 +++ b/m4/curl-nss.m4 @@ -76,7 +76,123 @@ if test "x$OPT_NSS" != xno; then @@ -1354,7 +1418,7 @@ index cb162755d..13ee571aa 100644 + + case $host_cpu in + arm) -+ addlib="$addlib -larmv8_c_lib -l:libgcm-aes-arm32-neon_c_lib.a" ++ addlib="$addlib -larmv8_c_lib -lgcm-aes-arm32-neon_c_lib" + ;; + aarch64) + addlib="$addlib -larmv8_c_lib -lgcm-aes-aarch64_c_lib" @@ -1465,7 +1529,7 @@ index cb162755d..13ee571aa 100644 if test "x$USE_NSS" = "xyes"; then diff --git a/src/Makefile.am b/src/Makefile.am -index 706f0aac3..0ad94622e 100644 +index f24cb6924..5750eaba8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -43,7 +43,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/include \ @@ -1477,16 +1541,19 @@ index 706f0aac3..0ad94622e 100644 SUBDIRS = ../docs -@@ -54,7 +54,7 @@ endif +@@ -54,9 +54,9 @@ endif include Makefile.inc # CURL_FILES comes from Makefile.inc -curl_SOURCES = $(CURL_FILES) +curl_impersonate_ff_SOURCES = $(CURL_FILES) + if HAVE_WINDRES +-curl_SOURCES += $(CURL_RCFILES) ++curl_impersonate_ff_SOURCES += $(CURL_RCFILES) + $(CURL_RCFILES): tool_version.h + endif - # This might hold -Werror - CFLAGS += @CURL_CFLAG_EXTRAS@ -@@ -63,9 +63,9 @@ CFLAGS += @CURL_CFLAG_EXTRAS@ +@@ -67,9 +67,9 @@ CFLAGS += @CURL_CFLAG_EXTRAS@ LIBS = $(BLANK_AT_MAKETIME) if USE_EXPLICIT_LIB_DEPS @@ -1498,18 +1565,3 @@ index 706f0aac3..0ad94622e 100644 endif # if unit tests are enabled, build a static library to link them with -diff --git a/lib/easy_lock.h b/lib/easy_lock.h -index 819f50ce8..1f54289ce 100644 ---- a/lib/easy_lock.h -+++ b/lib/easy_lock.h -@@ -36,6 +36,9 @@ - - #elif defined (HAVE_ATOMIC) - #include -+#if defined(HAVE_SCHED_YIELD) -+#include -+#endif - - #define curl_simple_lock atomic_bool - #define CURL_SIMPLE_LOCK_INIT false -