Repository: cloudflare/daphne
Pull request #662 (2024-08-27 14:08:02)

Add support for SSLKEYLOGFILE in dapf


Patch:
diff --git a/Cargo.lock b/Cargo.lock
index 3eb9b0c..a11121c 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -210,6 +210,33 @@ version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
 
+[[package]]
+name = "aws-lc-rs"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ae74d9bd0a7530e8afd1770739ad34b36838829d6ad61818f9230f683f5ad77"
+dependencies = [
+ "aws-lc-sys",
+ "mirai-annotations",
+ "paste",
+ "zeroize",
+]
+
+[[package]]
+name = "aws-lc-sys"
+version = "0.20.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0f0e249228c6ad2d240c2dc94b714d711629d52bad946075d8e9b2f5391f0703"
+dependencies = [
+ "bindgen",
+ "cc",
+ "cmake",
+ "dunce",
+ "fs_extra",
+ "libc",
+ "paste",
+]
+
 [[package]]
 name = "axum"
 version = "0.6.20"
@@ -390,6 +417,29 @@ dependencies = [
  "serde",
 ]
 
+[[package]]
+name = "bindgen"
+version = "0.69.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0"
+dependencies = [
+ "bitflags 2.6.0",
+ "cexpr",
+ "clang-sys",
+ "itertools 0.12.1",
+ "lazy_static",
+ "lazycell",
+ "log",
+ "prettyplease",
+ "proc-macro2",
+ "quote",
+ "regex",
+ "rustc-hash 1.1.0",
+ "shlex",
+ "syn 2.0.76",
+ "which",
+]
+
 [[package]]
 name = "bitflags"
 version = "1.3.2"
@@ -431,9 +481,9 @@ checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
 
 [[package]]
 name = "bytemuck"
-version = "1.17.0"
+version = "1.17.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6fd4c6dcc3b0aea2f5c0b4b82c2b15fe39ddbc76041a310848f4706edf76bb31"
+checksum = "773d90827bc3feecfb67fab12e24de0749aad83c74b9504ecde46237b5cd24e2"
 
 [[package]]
 name = "byteorder"
@@ -479,13 +529,24 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
 
 [[package]]
 name = "cc"
-version = "1.1.14"
+version = "1.1.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "50d2eb3cd3d1bf4529e31c215ee6f93ec5a3d536d9f578f93d9d33ee19562932"
+checksum = "57b6a275aa2903740dc87da01c62040406b8812552e97129a63ea8850a17c6e6"
 dependencies = [
+ "jobserver",
+ "libc",
  "shlex",
 ]
 
+[[package]]
+name = "cexpr"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
+dependencies = [
+ "nom",
+]
+
 [[package]]
 name = "cfg-if"
 version = "1.0.0"
@@ -527,7 +588,7 @@ dependencies = [
  "js-sys",
  "num-traits",
  "wasm-bindgen",
- "windows-targets 0.52.6",
+ "windows-targets",
 ]
 
 [[package]]
@@ -568,6 +629,17 @@ dependencies = [
  "zeroize",
 ]
 
+[[package]]
+name = "clang-sys"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
+dependencies = [
+ "glob",
+ "libc",
+ "libloading",
+]
+
 [[package]]
 name = "clap"
 version = "4.5.16"
@@ -608,6 +680,15 @@ version = "0.7.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
 
+[[package]]
+name = "cmake"
+version = "0.1.51"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fb1e43aa7fd152b1f968787f7dbcdeb306d1867ff373c69955211876c053f91a"
+dependencies = [
+ "cc",
+]
+
 [[package]]
 name = "colorchoice"
 version = "1.0.2"
@@ -825,7 +906,9 @@ dependencies = [
  "prometheus",
  "rand",
  "rayon",
- "reqwest 0.11.27",
+ "reqwest",
+ "rustls 0.23.12",
+ "rustls-native-certs",
  "sentry",
  "serde_json",
  "tokio",
@@ -892,7 +975,7 @@ dependencies = [
  "rand",
  "rayon",
  "rcgen",
- "reqwest 0.11.27",
+ "reqwest",
  "serde",
  "serde_json",
  "thiserror",
@@ -950,7 +1033,7 @@ dependencies = [
  "prio",
  "prometheus",
  "rand",
- "reqwest 0.11.27",
+ "reqwest",
  "reqwest-wasm",
  "ring",
  "serde",
@@ -1079,6 +1162,12 @@ version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0688c2a7f92e427f44895cd63841bff7b29f8d7a1648b9e7e07a4a365b2e1257"
 
+[[package]]
+name = "dunce"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
+
 [[package]]
 name = "ecdsa"
 version = "0.16.9"
@@ -1227,6 +1316,12 @@ dependencies = [
  "percent-encoding",
 ]
 
+[[package]]
+name = "fs_extra"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
+
 [[package]]
 name = "funty"
 version = "2.0.0"
@@ -1362,6 +1457,12 @@ version = "0.29.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
 
+[[package]]
+name = "glob"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
+
 [[package]]
 name = "group"
 version = "0.13.0"
@@ -1486,6 +1587,15 @@ dependencies = [
  "digest",
 ]
 
+[[package]]
+name = "home"
+version = "0.5.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5"
+dependencies = [
+ "windows-sys 0.52.0",
+]
+
 [[package]]
 name = "hostname"
 version = "0.4.0"
@@ -1648,20 +1758,6 @@ dependencies = [
  "want",
 ]
 
-[[package]]
-name = "hyper-rustls"
-version = "0.24.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590"
-dependencies = [
- "futures-util",
- "http 0.2.12",
- "hyper 0.14.30",
- "rustls 0.21.12",
- "tokio",
- "tokio-rustls 0.24.1",
-]
-
 [[package]]
 name = "hyper-rustls"
 version = "0.27.2"
@@ -1673,9 +1769,10 @@ dependencies = [
  "hyper 1.4.1",
  "hyper-util",
  "rustls 0.23.12",
+ "rustls-native-certs",
  "rustls-pki-types",
  "tokio",
- "tokio-rustls 0.26.0",
+ "tokio-rustls",
  "tower-service",
  "webpki-roots 0.26.3",
 ]
@@ -1812,6 +1909,15 @@ version = "1.0.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
 
+[[package]]
+name = "jobserver"
+version = "0.1.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0"
+dependencies = [
+ "libc",
+]
+
 [[package]]
 name = "js-sys"
 version = "0.3.70"
@@ -1847,12 +1953,28 @@ version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
 
+[[package]]
+name = "lazycell"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
+
 [[package]]
 name = "libc"
 version = "0.2.158"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
 
+[[package]]
+name = "libloading"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4"
+dependencies = [
+ "cfg-if",
+ "windows-targets",
+]
+
 [[package]]
 name = "linked-hash-map"
 version = "0.5.6"
@@ -1941,6 +2063,12 @@ dependencies = [
  "windows-sys 0.52.0",
 ]
 
+[[package]]
+name = "mirai-annotations"
+version = "1.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c9be0862c1b3f26a88803c4a49de6889c10e608b3ee9344e6ef5b45fb37ad3d1"
+
 [[package]]
 name = "native-tls"
 version = "0.2.12"
@@ -2186,7 +2314,7 @@ dependencies = [
  "libc",
  "redox_syscall",
  "smallvec",
- "windows-targets 0.52.6",
+ "windows-targets",
 ]
 
 [[package]]
@@ -2385,6 +2513,16 @@ dependencies = [
  "zerocopy",
 ]
 
+[[package]]
+name = "prettyplease"
+version = "0.2.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba"
+dependencies = [
+ "proc-macro2",
+ "syn 2.0.76",
+]
+
 [[package]]
 name = "primeorder"
 version = "0.13.6"
@@ -2465,7 +2603,7 @@ dependencies = [
  "pin-project-lite",
  "quinn-proto",
  "quinn-udp",
- "rustc-hash",
+ "rustc-hash 2.0.0",
  "rustls 0.23.12",
  "socket2",
  "thiserror",
@@ -2482,7 +2620,7 @@ dependencies = [
  "bytes",
  "rand",
  "ring",
- "rustc-hash",
+ "rustc-hash 2.0.0",
  "rustls 0.23.12",
  "slab",
  "thiserror",
@@ -2633,47 +2771,6 @@ version = "0.8.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
 
-[[package]]
-name = "reqwest"
-version = "0.11.27"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62"
-dependencies = [
- "base64 0.21.7",
- "bytes",
- "encoding_rs",
- "futures-core",
- "futures-util",
- "h2",
- "http 0.2.12",
- "http-body 0.4.6",
- "hyper 0.14.30",
- "hyper-rustls 0.24.2",
- "ipnet",
- "js-sys",
- "log",
- "mime",
- "once_cell",
- "percent-encoding",
- "pin-project-lite",
- "rustls 0.21.12",
- "rustls-native-certs",
- "rustls-pemfile 1.0.4",
- "serde",
- "serde_json",
- "serde_urlencoded",
- "sync_wrapper 0.1.2",
- "system-configuration",
- "tokio",
- "tokio-rustls 0.24.1",
- "tower-service",
- "url",
- "wasm-bindgen",
- "wasm-bindgen-futures",
- "web-sys",
- "winreg 0.50.0",
-]
-
 [[package]]
 name = "reqwest"
 version = "0.12.7"
@@ -2689,7 +2786,7 @@ dependencies = [
  "http-body 1.0.1",
  "http-body-util",
  "hyper 1.4.1",
- "hyper-rustls 0.27.2",
+ "hyper-rustls",
  "hyper-util",
  "ipnet",
  "js-sys",
@@ -2700,14 +2797,15 @@ dependencies = [
  "pin-project-lite",
  "quinn",
  "rustls 0.23.12",
- "rustls-pemfile 2.1.3",
+ "rustls-native-certs",
+ "rustls-pemfile",
  "rustls-pki-types",
  "serde",
  "serde_json",
  "serde_urlencoded",
  "sync_wrapper 1.0.1",
  "tokio",
- "tokio-rustls 0.26.0",
+ "tokio-rustls",
  "tower-service",
  "url",
  "wasm-bindgen",
@@ -2752,7 +2850,7 @@ dependencies = [
  "wasm-bindgen",
  "wasm-bindgen-futures",
  "web-sys",
- "winreg 0.10.1",
+ "winreg",
 ]
 
 [[package]]
@@ -2807,6 +2905,12 @@ version = "0.1.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
 
+[[package]]
+name = "rustc-hash"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
+
 [[package]]
 name = "rustc-hash"
 version = "2.0.0"
@@ -2862,36 +2966,29 @@ version = "0.23.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044"
 dependencies = [
+ "aws-lc-rs",
  "log",
  "once_cell",
  "ring",
  "rustls-pki-types",
- "rustls-webpki 0.102.6",
+ "rustls-webpki 0.102.7",
  "subtle",
  "zeroize",
 ]
 
 [[package]]
 name = "rustls-native-certs"
-version = "0.6.3"
+version = "0.7.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00"
+checksum = "04182dffc9091a404e0fc069ea5cd60e5b866c3adf881eff99a32d048242dffa"
 dependencies = [
  "openssl-probe",
- "rustls-pemfile 1.0.4",
+ "rustls-pemfile",
+ "rustls-pki-types",
  "schannel",
  "security-framework",
 ]
 
-[[package]]
-name = "rustls-pemfile"
-version = "1.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c"
-dependencies = [
- "base64 0.21.7",
-]
-
 [[package]]
 name = "rustls-pemfile"
 version = "2.1.3"
@@ -2920,10 +3017,11 @@ dependencies = [
 
 [[package]]
 name = "rustls-webpki"
-version = "0.102.6"
+version = "0.102.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e6b52d4fda176fd835fdc55a835d4a89b8499cad995885a21149d5ad62f852e"
+checksum = "84678086bd54edf2b415183ed7a94d0efb049f1b646a33e22a36f3794be6ae56"
 dependencies = [
+ "aws-lc-rs",
  "ring",
  "rustls-pki-types",
  "untrusted",
@@ -3025,7 +3123,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "00421ed8fa0c995f07cde48ba6c89e80f2b312f74ff637326f392fbfd23abe02"
 dependencies = [
  "httpdate",
- "reqwest 0.12.7",
+ "reqwest",
  "rustls 0.21.12",
  "sentry-backtrace",
  "sentry-contexts",
@@ -3384,27 +3482,6 @@ dependencies = [
  "unicode-xid",
 ]
 
-[[package]]
-name = "system-configuration"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7"
-dependencies = [
- "bitflags 1.3.2",
- "core-foundation",
- "system-configuration-sys",
-]
-
-[[package]]
-name = "system-configuration-sys"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9"
-dependencies = [
- "core-foundation-sys",
- "libc",
-]
-
 [[package]]
 name = "tap"
 version = "1.0.1"
@@ -3569,16 +3646,6 @@ dependencies = [
  "tokio",
 ]
 
-[[package]]
-name = "tokio-rustls"
-version = "0.24.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081"
-dependencies = [
- "rustls 0.21.12",
- "tokio",
-]
-
 [[package]]
 name = "tokio-rustls"
 version = "0.26.0"
@@ -3985,6 +4052,18 @@ dependencies = [
  "rustls-pki-types",
 ]
 
+[[package]]
+name = "which"
+version = "4.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7"
+dependencies = [
+ "either",
+ "home",
+ "once_cell",
+ "rustix",
+]
+
 [[package]]
 name = "winapi"
 version = "0.3.9"
@@ -4023,7 +4102,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
 dependencies = [
  "windows-core",
- "windows-targets 0.52.6",
+ "windows-targets",
 ]
 
 [[package]]
@@ -4032,7 +4111,7 @@ version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
 dependencies = [
- "windows-targets 0.52.6",
+ "windows-targets",
 ]
 
 [[package]]
@@ -4043,7 +4122,7 @@ checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0"
 dependencies = [
  "windows-result",
  "windows-strings",
- "windows-targets 0.52.6",
+ "windows-targets",
 ]
 
 [[package]]
@@ -4052,7 +4131,7 @@ version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e"
 dependencies = [
- "windows-targets 0.52.6",
+ "windows-targets",
 ]
 
 [[package]]
@@ -4062,16 +4141,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"
 dependencies = [
  "windows-result",
- "windows-targets 0.52.6",
-]
-
-[[package]]
-name = "windows-sys"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
-dependencies = [
- "windows-targets 0.48.5",
+ "windows-targets",
 ]
 
 [[package]]
@@ -4080,7 +4150,7 @@ version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
 dependencies = [
- "windows-targets 0.52.6",
+ "windows-targets",
 ]
 
 [[package]]
@@ -4089,22 +4159,7 @@ version = "0.59.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
 dependencies = [
- "windows-targets 0.52.6",
-]
-
-[[package]]
-name = "windows-targets"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
-dependencies = [
- "windows_aarch64_gnullvm 0.48.5",
- "windows_aarch64_msvc 0.48.5",
- "windows_i686_gnu 0.48.5",
- "windows_i686_msvc 0.48.5",
- "windows_x86_64_gnu 0.48.5",
- "windows_x86_64_gnullvm 0.48.5",
- "windows_x86_64_msvc 0.48.5",
+ "windows-targets",
 ]
 
 [[package]]
@@ -4113,46 +4168,28 @@ version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
 dependencies = [
- "windows_aarch64_gnullvm 0.52.6",
- "windows_aarch64_msvc 0.52.6",
- "windows_i686_gnu 0.52.6",
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
  "windows_i686_gnullvm",
- "windows_i686_msvc 0.52.6",
- "windows_x86_64_gnu 0.52.6",
- "windows_x86_64_gnullvm 0.52.6",
- "windows_x86_64_msvc 0.52.6",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
 ]
 
-[[package]]
-name = "windows_aarch64_gnullvm"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
-
 [[package]]
 name = "windows_aarch64_gnullvm"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
 
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
-
 [[package]]
 name = "windows_aarch64_msvc"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
 
-[[package]]
-name = "windows_i686_gnu"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
-
 [[package]]
 name = "windows_i686_gnu"
 version = "0.52.6"
@@ -4165,48 +4202,24 @@ version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
 
-[[package]]
-name = "windows_i686_msvc"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
-
 [[package]]
 name = "windows_i686_msvc"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
 
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
-
 [[package]]
 name = "windows_x86_64_gnu"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
 
-[[package]]
-name = "windows_x86_64_gnullvm"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
-
 [[package]]
 name = "windows_x86_64_gnullvm"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
 
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
-
 [[package]]
 name = "windows_x86_64_msvc"
 version = "0.52.6"
@@ -4222,16 +4235,6 @@ dependencies = [
  "winapi",
 ]
 
-[[package]]
-name = "winreg"
-version = "0.50.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
-dependencies = [
- "cfg-if",
- "windows-sys 0.48.0",
-]
-
 [[package]]
 name = "worker"
 version = "0.3.4"
diff --git a/Cargo.toml b/Cargo.toml
index 19503a5..a845880 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -68,9 +68,11 @@ rand = "0.8.5"
 rayon = "1.10.0"
 rcgen = "0.12.1"
 regex = "1.10.5"
-reqwest = { version = "0.11.27", default-features = false, features = ["rustls-tls-native-roots"] }
+reqwest = { version = "0.12.5", default-features = false, features = ["rustls-tls-native-roots"] }
 reqwest-wasm = "0.11.16"
 ring = "0.17.8"
+rustls = "0.23.10"
+rustls-native-certs = "0.7"
 serde = { version = "1.0.203", features = ["derive"] }
 serde-wasm-bindgen = "0.6.5"
 serde_json = "1.0.118"
diff --git a/crates/dapf/Cargo.toml b/crates/dapf/Cargo.toml
index ff48fdd..83dae89 100644
--- a/crates/dapf/Cargo.toml
+++ b/crates/dapf/Cargo.toml
@@ -28,6 +28,8 @@ prometheus.workspace = true
 rand.workspace = true
 rayon.workspace = true
 reqwest = { workspace = true, features = ["json"] }
+rustls.workspace = true
+rustls-native-certs.workspace = true
 sentry.workspace = true
 serde_json.workspace = true
 tokio.workspace = true
diff --git a/crates/dapf/src/acceptance/mod.rs b/crates/dapf/src/acceptance/mod.rs
index 748f6ce..14b1dd8 100644
--- a/crates/dapf/src/acceptance/mod.rs
+++ b/crates/dapf/src/acceptance/mod.rs
@@ -19,7 +19,7 @@
 pub mod load_testing;
 
 use crate::{
-    deduce_dap_version_from_url, response_to_anyhow, test_durations::TestDurations, HttpClientExt,
+    deduce_dap_version_from_url, response_to_anyhow, test_durations::TestDurations, HttpClient,
 };
 use anyhow::{anyhow, bail, Context, Result};
 use async_trait::async_trait;
@@ -46,7 +46,6 @@ use prio::codec::{Decode, ParameterizedEncode};
 use prometheus::{Encoder, HistogramVec, IntCounterVec, IntGaugeVec, TextEncoder};
 use rand::{rngs, Rng};
 use rayon::prelude::{IntoParallelIterator, ParallelIterator};
-use reqwest::{Client, Identity};
 use std::{
     convert::TryFrom,
     env,
@@ -159,52 +158,9 @@ impl DaphneMetrics for TestMetrics {
     fn agg_job_put_span_retry_inc(&self) {}
 }
 
-pub enum HttpClient {
-    NoReuse(Option<Identity>),
-    Reuse(Client),
-}
-
-impl HttpClient {
-    fn reused(leader_tls_identity: Option<Identity>) -> Self {
-        // Build the HTTP client.
-        let mut http_client_builder = reqwest::Client::builder()
-            // it takes too long to generate reports for larger dimensions, causing the worker
-            // to drop idle connections
-            .pool_max_idle_per_host(0)
-            // Don't handle redirects automatically so that we can control the client behavior.
-            .redirect(reqwest::redirect::Policy::none())
-            // We might as well use rustls because we already need the feature for
-            // `Identity::from_pem()`.
-            .use_rustls_tls();
-        if let Some(identity) = leader_tls_identity {
-            // Configure TLS certificate, if available.
-            http_client_builder = http_client_builder.identity(identity);
-        }
-        let http_client = http_client_builder
-            .build()
-            .expect("failed to build http client");
-        Self::Reuse(http_client)
-    }
-
-    fn no_reuse(leader_tls_identity: Option<Identity>) -> Self {
-        Self::NoReuse(leader_tls_identity)
-    }
-
-    pub fn client(&self) -> Client {
-        match self {
-            Self::Reuse(c) => c.clone(),
-            Self::NoReuse(identity) => match Self::reused(identity.clone()) {
-                Self::Reuse(client) => client,
-                Self::NoReuse(_) => unreachable!(),
-            },
-        }
-    }
-}
-
 pub struct Test {
     pub helper_url: Url,
     bearer_token: Option<BearerToken>,
-    using_mtls: bool,
     vdaf_verify_init: [u8; 32],
     http_client: HttpClient,
     metrics: TestMetrics,
@@ -256,7 +212,6 @@ struct TestTaskConfig {
 impl Test {
     pub fn new(
         http_client: HttpClient,
-        using_mtls: bool,
         helper_url: Url,
         vdaf_verify_init: &str,
         vdaf_config: VdafConfig,
@@ -295,7 +250,6 @@ impl Test {
         };
 
         Ok(Self {
-            using_mtls,
             helper_url,
             bearer_token: None,
             vdaf_verify_init,
@@ -311,46 +265,19 @@ impl Test {
         helper_url: Url,
         vdaf_config: VdafConfig,
         hpke_signing_certificate_path: Option<PathBuf>,
-        re_use_http_client: bool,
+        http_client: HttpClient,
         load_control: LoadControlParams,
     ) -> Result<Self> {
         const LEADER_BEARER_TOKEN_VAR: &str = "LEADER_BEARER_TOKEN";
-        const LEADER_TLS_CLIENT_CERT_VAR: &str = "LEADER_TLS_CLIENT_CERT";
-        const LEADER_TLS_CLIENT_KEY_VAR: &str = "LEADER_TLS_CLIENT_KEY";
         const VDAF_VERIFY_INIT_VAR: &str = "VDAF_VERIFY_INIT";
 
         let leader_bearer_token = env::var(LEADER_BEARER_TOKEN_VAR).ok();
-        let leader_tls_client_cert = env::var(LEADER_TLS_CLIENT_CERT_VAR).ok();
-        let leader_tls_client_key = env::var(LEADER_TLS_CLIENT_KEY_VAR).ok();
-        if leader_bearer_token.is_none()
-            && (leader_tls_client_cert.is_none() || leader_tls_client_key.is_none())
-        {
-            println!("leader client authorization not configured");
-        }
 
         let vdaf_verify_init = env::var(VDAF_VERIFY_INIT_VAR)
             .with_context(|| format!("failed to load {VDAF_VERIFY_INIT_VAR}"))?;
 
-        let leader_tls_identity = match (leader_tls_client_cert, leader_tls_client_key) {
-            (Some(cert), Some(key)) => Some(
-                reqwest::tls::Identity::from_pem((cert + "\n" + &key).as_bytes())
-                    .with_context(|| "failed to parse Leader TLS client certificate")?,
-            ),
-            (None, None) => None,
-            (Some(_), None) => bail!("{LEADER_TLS_CLIENT_KEY_VAR} is not set"),
-            (None, Some(_)) => bail!("{LEADER_TLS_CLIENT_CERT_VAR} is not set"),
-        };
-
-        let using_mtls = leader_tls_identity.is_some();
-        let http_client = if re_use_http_client {
-            HttpClient::reused(leader_tls_identity)
-        } else {
-            HttpClient::no_reuse(leader_tls_identity)
-        };
-
         let mut test = Test::new(
             http_client,
-            using_mtls,
             helper_url,
             &vdaf_verify_init,
             vdaf_config,
@@ -399,7 +326,6 @@ impl Test {
     pub async fn get_hpke_config(&self, aggregator: &Url) -> anyhow::Result<HpkeConfig> {
         Ok(self
             .http_client
-            .client()
             .get_hpke_config(aggregator, self.hpke_signing_certificate_path.as_deref())
             .await?
             .hpke_configs
@@ -431,7 +357,6 @@ impl Test {
             let start = Instant::now();
             let helper_hpke_config = self
                 .http_client
-                .client()
                 .get_hpke_config(
                     &self.helper_url,
                     self.hpke_signing_certificate_path.as_deref(),
@@ -592,7 +517,6 @@ impl Test {
         let start = Instant::now();
         let resp = send(
             self.http_client
-                .client()
                 .put(url)
                 .body(
                     agg_job_init_req
@@ -679,7 +603,6 @@ impl Test {
         ))?;
         let resp = send(
             self.http_client
-                .client()
                 .post(url)
                 .body(agg_share_req.get_encoded_with_param(&version).unwrap())
                 .headers(headers),
@@ -711,10 +634,10 @@ impl Test {
     pub async fn test_helper(&self, opt: &TestOptions) -> Result<TestDurations> {
         let res = self.test_helper_impl(opt).await;
         let c = |b: bool| ["F", "T"][b as usize];
-        let metric = self
-            .metrics
-            .test_success
-            .with_label_values(&[c(self.using_mtls), c(self.bearer_token.is_some())]);
+        let metric = self.metrics.test_success.with_label_values(&[
+            c(self.http_client.using_mtls()),
+            c(self.bearer_token.is_some()),
+        ]);
         if res.is_ok() {
             metric.inc()
         } else {
diff --git a/crates/dapf/src/http_client.rs b/crates/dapf/src/http_client.rs
new file mode 100644
index 0000000..184f427
--- /dev/null
+++ b/crates/dapf/src/http_client.rs
@@ -0,0 +1,194 @@
+// Copyright (c) 2024 Cloudflare, Inc. All rights reserved.
+// SPDX-License-Identifier: BSD-3-Clause
+
+use std::{borrow::Cow, env, io::Cursor, path::Path};
+
+use anyhow::{anyhow, bail, Context};
+use daphne::messages::{decode_base64url_vec, HpkeConfigList};
+use daphne_service_utils::http_headers;
+use prio::codec::Decode;
+use reqwest::{Client, Identity, IntoUrl, RequestBuilder};
+use url::Url;
+use webpki::{EndEntityCert, ECDSA_P256_SHA256};
+use x509_parser::pem::Pem;
+
+use crate::response_to_anyhow;
+
+pub struct HttpClient {
+    using_mtls: bool,
+    inner: HttpClientInner,
+}
+
+#[allow(clippy::large_enum_variant)]
+enum HttpClientInner {
+    /// Never reuse the same reqwest client for two different http requests. Usefull for specific
+    /// debugging or load testing scenarios.
+    NoReuse {
+        identity: Option<Identity>,
+        ssl_key_log_file_enabled_tls: Option<rustls::ClientConfig>,
+    },
+    /// Always use the same reqwest client when making requests, this is faster and probably what
+    /// you want.
+    Reuse(Client),
+}
+
+fn load_identity() -> anyhow::Result<Option<Identity>> {
+    // LEADER_ variables left here for backwards compatibility
+    const TLS_CLIENT_CERT_VAR: [&str; 2] = ["TLS_CLIENT_CERT", "LEADER_TLS_CLIENT_CERT"];
+    const TLS_CLIENT_KEY_VAR: [&str; 2] = ["TLS_CLIENT_KEY", "LEADER_TLS_CLIENT_KEY"];
+
+    let leader_tls_client_cert = TLS_CLIENT_CERT_VAR
+        .iter()
+        .find_map(|key| env::var(key).ok());
+    let leader_tls_client_key = TLS_CLIENT_KEY_VAR.iter().find_map(|key| env::var(key).ok());
+    match (leader_tls_client_cert, leader_tls_client_key) {
+        (Some(cert), Some(key)) => Ok(Some(
+            Identity::from_pem((cert + "\n" + &key).as_bytes())
+                .with_context(|| "failed to parse Leader TLS client certificate")?,
+        )),
+        (None, None) => Ok(None),
+        (Some(_), None) => bail!("{TLS_CLIENT_KEY_VAR:?} is not set"),
+        (None, Some(_)) => bail!("{TLS_CLIENT_CERT_VAR:?} is not set"),
+    }
+}
+
+fn ssl_key_log_file_tls_configuration() -> rustls::ClientConfig {
+    tracing::warn!("enabling SSLKEYLOGFILE");
+    let mut tls = rustls::ClientConfig::builder_with_provider(
+        rustls::crypto::aws_lc_rs::default_provider().into(),
+    )
+    .with_safe_default_protocol_versions()
+    .unwrap()
+    .with_root_certificates({
+        let mut store = rustls::RootCertStore::empty();
+        store.add_parsable_certificates(rustls_native_certs::load_native_certs().unwrap());
+        store
+    })
+    .with_no_client_auth();
+    tls.key_log = std::sync::Arc::new(rustls::KeyLogFile::new());
+    tls
+}
+
+fn init_reqwest_client(
+    identity: Option<Identity>,
+    ssl_key_log_file_enabled_tls: Option<rustls::ClientConfig>,
+) -> reqwest::Client {
+    // Build the HTTP client.
+    let mut http_client_builder = reqwest::Client::builder()
+        // it takes too long to generate reports for larger dimensions, causing the worker
+        // to drop idle connections
+        .pool_max_idle_per_host(0)
+        // Don't handle redirects automatically so that we can control the client behavior.
+        .redirect(reqwest::redirect::Policy::none());
+
+    // We might as well use rustls because we already need the feature for
+    // `Identity::from_pem()`.
+    http_client_builder = if let Some(tls) = ssl_key_log_file_enabled_tls {
+        http_client_builder.use_preconfigured_tls(tls)
+    } else {
+        http_client_builder.use_rustls_tls()
+    };
+
+    if let Some(identity) = identity {
+        // Configure TLS certificate, if available.
+        http_client_builder = http_client_builder.identity(identity);
+    }
+
+    http_client_builder
+        .build()
+        .expect("failed to build http client")
+}
+
+impl HttpClient {
+    pub fn new(enable_ssl_key_log_file: bool) -> anyhow::Result<Self> {
+        let identity = load_identity()?;
+        Ok(Self {
+            using_mtls: identity.is_some(),
+            inner: HttpClientInner::Reuse(init_reqwest_client(
+                identity,
+                enable_ssl_key_log_file.then(ssl_key_log_file_tls_configuration),
+            )),
+        })
+    }
+
+    /// Create an http client that never reuses the same client for two requests.
+    pub fn new_no_reuse(enable_ssl_key_log_file: bool) -> anyhow::Result<Self> {
+        let identity = load_identity()?;
+        Ok(Self {
+            using_mtls: identity.is_some(),
+            inner: HttpClientInner::NoReuse {
+                identity,
+                ssl_key_log_file_enabled_tls: enable_ssl_key_log_file
+                    .then(ssl_key_log_file_tls_configuration),
+            },
+        })
+    }
+
+    fn client(&self) -> Cow<'_, Client> {
+        match &self.inner {
+            HttpClientInner::Reuse(c) => Cow::Borrowed(c),
+            HttpClientInner::NoReuse {
+                identity,
+                ssl_key_log_file_enabled_tls,
+            } => Cow::Owned(init_reqwest_client(
+                identity.clone(),
+                ssl_key_log_file_enabled_tls.clone(),
+            )),
+        }
+    }
+
+    pub fn using_mtls(&self) -> bool {
+        self.using_mtls
+    }
+
+    pub fn get<U: IntoUrl>(&self, url: U) -> RequestBuilder {
+        self.client().get(url)
+    }
+
+    pub fn post<U: IntoUrl>(&self, url: U) -> RequestBuilder {
+        self.client().post(url)
+    }
+
+    pub fn put<U: IntoUrl>(&self, url: U) -> RequestBuilder {
+        self.client().post(url)
+    }
+
+    pub async fn get_hpke_config(
+        &self,
+        base_url: &Url,
+        certificate_file: Option<&Path>,
+    ) -> anyhow::Result<HpkeConfigList> {
+        let url = base_url.join("hpke_config")?;
+        let resp = self
+            .get(url.as_str())
+            .send()
+            .await
+            .with_context(|| "request failed")?;
+        if !resp.status().is_success() {
+            return Err(response_to_anyhow(resp).await);
+        }
+        let maybe_signature = resp.headers().get(http_headers::HPKE_SIGNATURE).cloned();
+        let hpke_config_bytes = resp.bytes().await.context("failed to read hpke config")?;
+        if let Some(cert_path) = certificate_file {
+            let cert = std::fs::read_to_string(cert_path).context("reading the certificate")?;
+            let Some(signature) = maybe_signature else {
+                anyhow::bail!("Aggregator did not sign its response");
+            };
+            let signature_bytes =
+                decode_base64url_vec(signature.as_bytes()).context("decoding the signature")?;
+            let (cert_pem, _bytes_read) =
+                Pem::read(Cursor::new(cert.as_bytes())).context("reading PEM certificate")?;
+            let cert = EndEntityCert::try_from(cert_pem.contents.as_ref())
+                .map_err(|e| anyhow!("{e:?}")) // webpki::Error does not implement std::error::Error
+                .context("parsing PEM certificate")?;
+
+            cert.verify_signature(
+                &ECDSA_P256_SHA256,
+                &hpke_config_bytes,
+                signature_bytes.as_ref(),
+            )
+            .map_err(|e| anyhow!("signature not verified: {}", e.to_string()))?;
+        }
+        Ok(HpkeConfigList::get_decoded(&hpke_config_bytes)?)
+    }
+}
diff --git a/crates/dapf/src/lib.rs b/crates/dapf/src/lib.rs
index 782846e..56c4847 100644
--- a/crates/dapf/src/lib.rs
+++ b/crates/dapf/src/lib.rs
@@ -2,73 +2,15 @@
 // SPDX-License-Identifier: BSD-3-Clause
 
 pub mod acceptance;
+pub mod http_client;
 mod test_durations;
 pub mod test_routes;
 
-use std::{io::Cursor, path::Path};
-
 use anyhow::{anyhow, Context};
-use daphne::{
-    messages::{decode_base64url_vec, HpkeConfigList},
-    DapVersion,
-};
-use daphne_service_utils::http_headers;
-use prio::codec::Decode;
-use reqwest::Client;
+use daphne::DapVersion;
 use url::Url;
-use webpki::{EndEntityCert, ECDSA_P256_SHA256};
-use x509_parser::pem::Pem;
-
-pub trait HttpClientExt {
-    fn get_hpke_config(
-        &self,
-        base_url: &Url,
-        certificate_file: Option<&Path>,
-    ) -> impl std::future::Future<Output = anyhow::Result<HpkeConfigList>> + Send;
-}
-
-impl HttpClientExt for Client {
-    async fn get_hpke_config(
-        &self,
-        base_url: &Url,
-        certificate_file: Option<&Path>,
-    ) -> anyhow::Result<HpkeConfigList> {
-        let url = base_url.join("hpke_config")?;
-
-        let resp = self
-            .get(url.as_str())
-            .send()
-            .await
-            .with_context(|| "request failed")?;
-        if !resp.status().is_success() {
-            return Err(response_to_anyhow(resp).await);
-        }
-        let maybe_signature = resp.headers().get(http_headers::HPKE_SIGNATURE).cloned();
-        let hpke_config_bytes = resp.bytes().await.context("failed to read hpke config")?;
-        if let Some(cert_path) = certificate_file {
-            let cert = std::fs::read_to_string(cert_path).context("reading the certificate")?;
-            let Some(signature) = maybe_signature else {
-                anyhow::bail!("Aggregator did not sign its response");
-            };
-            let signature_bytes =
-                decode_base64url_vec(signature.as_bytes()).context("decoding the signature")?;
-            let (cert_pem, _bytes_read) =
-                Pem::read(Cursor::new(cert.as_bytes())).context("reading PEM certificate")?;
-            let cert = EndEntityCert::try_from(cert_pem.contents.as_ref())
-                .map_err(|e| anyhow!("{e:?}")) // webpki::Error does not implement std::error::Error
-                .context("parsing PEM certificate")?;
 
-            cert.verify_signature(
-                &ECDSA_P256_SHA256,
-                &hpke_config_bytes,
-                signature_bytes.as_ref(),
-            )
-            .map_err(|e| anyhow!("signature not verified: {}", e.to_string()))?;
-        }
-
-        Ok(HpkeConfigList::get_decoded(&hpke_config_bytes)?)
-    }
-}
+pub use http_client::HttpClient;
 
 pub fn deduce_dap_version_from_url(url: &Url) -> anyhow::Result<DapVersion> {
     url.path_segments()
diff --git a/crates/dapf/src/main.rs b/crates/dapf/src/main.rs
index 28c04a3..977fade 100644
--- a/crates/dapf/src/main.rs
+++ b/crates/dapf/src/main.rs
@@ -5,7 +5,7 @@ use anyhow::{anyhow, Context, Result};
 use clap::{builder::PossibleValue, Parser, Subcommand, ValueEnum};
 use dapf::{
     acceptance::{load_testing, LoadControlParams, LoadControlStride, TestOptions},
-    deduce_dap_version_from_url, response_to_anyhow, HttpClientExt,
+    deduce_dap_version_from_url, response_to_anyhow, HttpClient,
 };
 use daphne::{
     constants::DapMediaType,
@@ -18,7 +18,6 @@ use daphne::{
 use daphne_service_utils::http_headers;
 use prio::codec::{ParameterizedDecode, ParameterizedEncode};
 use rand::{thread_rng, Rng};
-use reqwest::ClientBuilder;
 use std::{
     io::{stdin, Read},
     path::PathBuf,
@@ -121,6 +120,10 @@ struct Cli {
     action: Action,
     #[arg(env, long)]
     sentry_dsn: Option<sentry::types::Dsn>,
+    #[arg(long, env)]
+    no_reuse_http_client: bool,
+    #[arg(long)]
+    enable_ssl_key_log_file: bool,
 }
 
 #[derive(Debug, Subcommand)]
@@ -218,8 +221,6 @@ enum HelperAction {
     LoadTest {
         #[arg(env)]
         helper_url: Url,
-        #[arg(long, env)]
-        no_reuse_http_client: bool,
         #[command(flatten)]
         load_control: LoadControlParamsCli,
         #[command(subcommand)]
@@ -391,19 +392,21 @@ async fn main() -> Result<()> {
                 .from_env_lossy(),
         )
         .init();
-    // HTTP client should not handle redirects automatically.
-    let http_client = ClientBuilder::new()
-        .redirect(reqwest::redirect::Policy::none())
-        .build()
-        .with_context(|| "failed to create HTTP client")?;
+
+    let http_client = if cli.no_reuse_http_client {
+        HttpClient::new(cli.enable_ssl_key_log_file)?
+    } else {
+        HttpClient::new_no_reuse(cli.enable_ssl_key_log_file)?
+    };
 
     if std::env::var("REPLAY_REPORTS").unwrap_or_default() == "1" {
         daphne::testing::report_generator::replay_reports(true);
     }
+
     match cli.action {
         Action::Leader(leader) => handle_leader_actions(leader, http_client).await,
         Action::Hpke(hpke) => handle_hpke_actions(hpke, http_client).await,
-        Action::Helper(helper) => handle_helper_actions(helper).await,
+        Action::Helper(helper) => handle_helper_actions(helper, http_client).await,
         Action::TestRoutes(TestAction::AddHpkeConfig {
             aggregator_url,
             kem_alg,
@@ -424,7 +427,7 @@ async fn main() -> Result<()> {
 
 async fn handle_leader_actions(
     leader: LeaderAction,
-    http_client: reqwest::Client,
+    http_client: HttpClient,
 ) -> anyhow::Result<()> {
     let now = SystemTime::now()
         .duration_since(SystemTime::UNIX_EPOCH)?
@@ -608,7 +611,10 @@ async fn handle_leader_actions(
     }
 }
 
-async fn handle_helper_actions(helper: HelperAction) -> anyhow::Result<()> {
+async fn handle_helper_actions(
+    helper: HelperAction,
+    http_client: HttpClient,
+) -> anyhow::Result<()> {
     match helper {
         HelperAction::Aggregate {
             helper_url,
@@ -626,7 +632,7 @@ async fn handle_helper_actions(helper: HelperAction) -> anyhow::Result<()> {
                 helper_url,
                 vdaf_config.into_vdaf(),
                 hpke_signing_certificate_path,
-                true,
+                http_client,
                 load_control,
             )?;
 
@@ -643,13 +649,12 @@ async fn handle_helper_actions(helper: HelperAction) -> anyhow::Result<()> {
         }
         HelperAction::LoadTest {
             helper_url,
-            no_reuse_http_client,
             load_control,
             params: LoadTestParameters::Multiple,
         } => {
             load_testing::execute_multiple_combinations(
                 helper_url,
-                !no_reuse_http_client,
+                http_client,
                 load_control.into_params(usize::MAX, 1),
             )
             .await;
@@ -657,7 +662,6 @@ async fn handle_helper_actions(helper: HelperAction) -> anyhow::Result<()> {
         }
         HelperAction::LoadTest {
             helper_url,
-            no_reuse_http_client,
             load_control,
             params:
                 LoadTestParameters::Single {
@@ -671,7 +675,7 @@ async fn handle_helper_actions(helper: HelperAction) -> anyhow::Result<()> {
                 vdaf_config.into_vdaf(),
                 reports_per_batch,
                 reports_per_agg_job,
-                !no_reuse_http_client,
+                http_client,
                 load_control.into_params(reports_per_agg_job, reports_per_batch),
             )
             .await;
@@ -680,7 +684,7 @@ async fn handle_helper_actions(helper: HelperAction) -> anyhow::Result<()> {
     }
 }
 
-async fn handle_hpke_actions(hpke: HpkeAction, http_client: reqwest::Client) -> anyhow::Result<()> {
+async fn handle_hpke_actions(hpke: HpkeAction, http_client: HttpClient) -> anyhow::Result<()> {
     let mut rng = thread_rng();
     fn kv_key_of(dap_version: DapVersion) -> String {
         format!("hpke_receiver_config_set/{dap_version}")


Test patch:
diff --git a/crates/dapf/src/acceptance/load_testing.rs b/crates/dapf/src/acceptance/load_testing.rs
index f1e98af..c4bf4fe 100644
--- a/crates/dapf/src/acceptance/load_testing.rs
+++ b/crates/dapf/src/acceptance/load_testing.rs
@@ -10,6 +10,7 @@ use std::{
 use crate::{
     acceptance::{now, Test, TestOptions},
     test_durations::TestDurations,
+    HttpClient,
 };
 use anyhow::Context;
 use chrono::{DateTime, Utc};
@@ -335,7 +336,7 @@ async fn execute(t: &Test, test_config: &TestOptions) -> TestResults {
 
 pub async fn execute_multiple_combinations(
     helper_url: Url,
-    re_use_http_client: bool,
+    http_client: HttpClient,
     load_control: LoadControlParams,
 ) {
     // This vdaf config is later replaced on each of the runs
@@ -343,7 +344,7 @@ pub async fn execute_multiple_combinations(
         helper_url,
         VdafConfig::Prio2 { dimension: 44 },
         None,
-        re_use_http_client,
+        http_client,
         load_control,
     )
     .expect("env to be present");
@@ -400,19 +401,13 @@ pub async fn execute_single_combination_from_env(
     vdaf_config: VdafConfig,
     reports_per_batch: usize,
     reports_per_agg_job: usize,
-    re_use_http_client: bool,
+    http_client: HttpClient,
     load_control: LoadControlParams,
 ) {
     const VERSION: daphne::DapVersion = daphne::DapVersion::Latest;
 
-    let t = Test::from_env(
-        helper_url,
-        vdaf_config,
-        None,
-        re_use_http_client,
-        load_control,
-    )
-    .expect("env to be present");
+    let t = Test::from_env(helper_url, vdaf_config, None, http_client, load_control)
+        .expect("env to be present");
 
     let system_now = now();
 
diff --git a/crates/dapf/src/test_routes.rs b/crates/dapf/src/test_routes.rs
index b168c0a..9c2b5a8 100644
--- a/crates/dapf/src/test_routes.rs
+++ b/crates/dapf/src/test_routes.rs
@@ -7,13 +7,12 @@ use daphne::{
     messages::HpkeConfigList,
 };
 use rand::{thread_rng, Rng};
-use reqwest::Client;
 use url::Url;
 
-use crate::HttpClientExt;
+use crate::HttpClient;
 
 pub async fn add_hpke_config(
-    http_client: &Client,
+    http_client: &HttpClient,
     aggregator_url: &Url,
     kem_alg: HpkeKemId,
 ) -> anyhow::Result<()> {
@@ -53,7 +52,7 @@ pub async fn add_hpke_config(
 }
 
 pub async fn delete_all_storage(
-    http_client: &Client,
+    http_client: &HttpClient,
     aggregator_url: &Url,
     kem_alg: Option<HpkeKemId>,
 ) -> anyhow::Result<()> {