Update tungstenite to 0.24.0

Test: m
Change-Id: Id9a0e307c997e8410c5c9f8e0a5031673d3a2b20
diff --git a/crates/tungstenite/.android-checksum.json b/crates/tungstenite/.android-checksum.json
new file mode 100644
index 0000000..a2c824f
--- /dev/null
+++ b/crates/tungstenite/.android-checksum.json
@@ -0,0 +1 @@
+{"package":null,"files":{"src/protocol/frame/frame.rs":"785735f1358b10241ca631fbb488ad880ef9a1c0cd0db8eb41be42511cce955e","src/error.rs":"ba560f403dace05a43f361f76cd7d8401e9f7e5102defa2e0f6ac3686a4f9442","examples/srv_accept_unmasked_frames.rs":"95b45392010c89bb0de154bad23ec84cd45dac9197bf0255080086fcca5a5888","src/server.rs":"cef598fc1bfab158284a5518da8468067f901363fa3540a761be0058be97900f","src/protocol/frame/mod.rs":"16ee9055023cf8918b35238c1d3c10d82149e48c7b796ebba2ada2c64be91fce","MODULE_LICENSE_APACHE2":"0d6f8afa3940b7f06bebee651376d43bc8b0d5b437337be2696d30377451e93a","cargo_embargo.json":"ab8fe9ae28c2e1ae4815aa7c0dcf4e3043ddfb6eb647d025e0d1a3c7ec3a7ab4","src/protocol/message.rs":"b03d221b0fd36702ccab2eacec54537502e6848347a9a025776f0d69b16aa3d1","src/protocol/frame/mask.rs":"7c3ba13e21924a0bcaeac08858d685b4d3f77fb6240424b4f78614e928075b94","src/handshake/headers.rs":"4cd4ffd698b53f03f1ecb5389a9034d861c1ec4e0344b191730630a4a066ea0b","src/client.rs":"8c25bab275a8773af9b8ba078509ca2d33362010adb5197bed443cc237ef28fc","src/handshake/machine.rs":"bbca958a2c2e2ce66d5d4396f7db75a7ec2e26e03551ee228c404221c6b3ed9d","LICENSE-MIT":"b95585e7b5f8ae870f766d229e944b03a0b16ac46b6e0d2328c3ec6e6854a855","examples/autobahn-client.rs":"312d5fa595f9cfebe068e48f365f91097a5b7a32b96eb93b3885d8090ddd352a","src/handshake/server.rs":"101ff8268099b6caa154e83ff32ef72d28cec3035664ddf793ff83ec9e7cfbb1","src/handshake/mod.rs":"371474e1e0dbf2fdd411f370763ffbefb7f98638a76498c6a9cbbba7eab60f0e","LICENSE":"3c7cd2396b5b772507febd2615d3d5a55b80103845037df77c87ba6e64872f2c","README.md":"fd300344cd2672f34d1313ae163e787f621affb0e778a025e88a10b3eb464946","METADATA":"d1c589e52840b64acfd0550a3e0cc8a390f3dcaafae4b71a211512b3ecf4926b","src/stream.rs":"138ac055f480029d2272621d31326d1f32133f63bfda8e68d0e887e36e5a2640",".cargo-checksum.json":"1752b7d44ef10b3693a4ebe37517084ca7fba77b51cf55c76c6dc89236d8af38","LICENSE-APACHE":"3c7cd2396b5b772507febd2615d3d5a55b80103845037df77c87ba6e64872f2c","benches/write.rs":"a4a30aa69221ee7d4f34310a2ac0608935cedaa2ea8a747b8bff30cf6325e24b","src/util.rs":"edb9d908ca0ef207a8a9ecab79cdf1fc9f91cf3cb62787154823f77dd0d08469","examples/callback-error.rs":"c4cea677237534a0b92c08ba4373b385c1761bd8d41d40275ec70342cb3a9d88","src/lib.rs":"9a4e0a99d141eee29b250e3484cb930a78d454edf1b18aafad8a103fbd75d2d8","Cargo.toml":"15e568ff82eeefa39118e34166a22fc4ffce72f31bfed161030b7a061d5ce31b","src/buffer.rs":"29815269d88d4893708b8d0badf6699ed76c2270e4adbff0f87f05d0ff7b91a5","examples/server.rs":"5ec9ad244d281deb0bf29080d6343a6206c5ae6bb9e275d20da99a1e183369ba","examples/client.rs":"7d15ef2b3e112e1131863899af01384522fc37c83d889428105046bc5838747f","Android.bp":"60fd38495349b1ab40738af89d4889d0d385221699ad2978e021da756c600526","src/handshake/client.rs":"879425517c96efe9628e48454be1470e08922be2c9a1eb241cffbe402bb27367","src/protocol/mod.rs":"7f284681aa2095f02c6457d376f03a2951421166fa1b5e47da047a57932a8bdb","src/protocol/frame/coding.rs":"22e18e946fe8ea7dabee2f04a074513076be111197a24def06b056adb9ba7907","examples/autobahn-server.rs":"0680afb9eb37f268dd3adc58504900ec82c56e694e7e6e222af5b335f5f223d0","CHANGELOG.md":"f93ca5ef40a4d8fa295cb01b432c61ccae83f366b303ff6fb9b6f6c8cdbb88eb","benches/buffer.rs":"39cae616e4f10bb91e512d7040fd76733376cfe1cdd9bb47c08a35c92c0fb5fa","src/tls.rs":"25b0e9427f75b22384b641274aea94a14f15cd4570f5618dc2972c18561004c7","Cargo.lock":"8e1ad40f9fcccd27882f8f26c7ca5769172ec97e8a4bf32403cbf9d06e1d0dde"}}
\ No newline at end of file
diff --git a/crates/tungstenite/.cargo-checksum.json b/crates/tungstenite/.cargo-checksum.json
index 9c9ac07..1493c9a 100644
--- a/crates/tungstenite/.cargo-checksum.json
+++ b/crates/tungstenite/.cargo-checksum.json
@@ -1 +1 @@
-{"files":{"CHANGELOG.md":"983d5f14ef39ef3662e843dc9b6411c176a8d085c15c35740d043c7bb47dee0f","Cargo.lock":"4a39b4dc027e931a05182eb15728e3c1ccb12a7790325ece5470da88b38428b8","Cargo.toml":"58aa0d3b733e4bf0232c5bddf3d79988037359c4b2eae4875d16657a2492fd29","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"7fea0ee51a4ca5d5cea7464135fd55e8b09caf3a61da3d451ac8a22af95c033f","README.md":"0a8b44c900be104faf8bb8d24e419ca1569e32d7bfae4f1528bc27f9f01d4b33","benches/buffer.rs":"615d66b4e5d5f11758aa111f2c3274e82dba5afeca3863bf39138d906c67344c","benches/write.rs":"921c72b4f1b219873fd2c69baa15fcb064373d55d0a5a47f29fc7f03eebde767","examples/autobahn-client.rs":"9d525f68cab5cc1791aa8ba376bea77f27534f3e953f3a486bb4a515b9b3fbf4","examples/autobahn-server.rs":"4b50ff21113ca920a2d91a37f8f3452ecc64ee3dcf0d557905d3bcd1746a92e3","examples/callback-error.rs":"fe732374176dfe4e5d1f36a3fa09d6d6e3cc95885e920480ef5bcd94206835e0","examples/client.rs":"348a78efba691d502c5d2cb2c02f1704c513b2a752a2fa36e2e18d01f234a2bb","examples/server.rs":"676d6cc3b3042b106def38a5a5f65f2be9f43d6156f9164046b0a666ed06f048","examples/srv_accept_unmasked_frames.rs":"9a898510c622d2b2d3a28505d45b9187272186ae487fd74b827fe280c8f6a5f9","src/buffer.rs":"c346e4282b294b856d29a17ea078ebd2580b3142f531e1e10d545e4af0baba2b","src/client.rs":"4691e64343a38879367cafe45a999789fc143938e5e71a4d34e96d924df5ece3","src/error.rs":"4fa76e7d681a464da9e144b6fcc7022b00591607cac04107474b35e46ba50307","src/handshake/client.rs":"ee777c8e23f3503213d0fc5d0e35cee1c4f2112bfb2902543dda64e963b8257f","src/handshake/headers.rs":"0e6d3e15faa8b82bd2a239f5094335368e578acef2f17ee74825de606f529b75","src/handshake/machine.rs":"d8d07e8797ab93516154abc904cbc44dc72b49f6ce9601b4e559c7fc1ae065f5","src/handshake/mod.rs":"783b05cb7a45fcc4ff3d06eec5f17d87f7d1cc32db9dd836d1b8fcd2d9018436","src/handshake/server.rs":"000d888d2d5ba140a57db1e1520f844441b403fda61f7e674c4730e1fe15a202","src/lib.rs":"f5e1e6ae7e1af292f5d56011333f8dc28de18cd5a81d0da580a0c73b98ab7d5e","src/protocol/frame/coding.rs":"dfa740428a7ae63a308b0d22258354f5234690a105e10963075d4af02d8d5450","src/protocol/frame/frame.rs":"efebb2b48d17d7cecf090805ccb8c1930471210b74276c5c62ce941d8188a402","src/protocol/frame/mask.rs":"ab2d387f9e2dbfda29b26d3147facacaeb7b91de1ae5d07d742fb9b9d297f8b1","src/protocol/frame/mod.rs":"7ae23d5c389fb1ff789b7f2597ff390d7846dfd5d654bccf4ec3682ad1741055","src/protocol/message.rs":"446cfc9c28ac8cc91214699b62044d0a1ab1d8c62bee1f101758ae8560db5223","src/protocol/mod.rs":"e24aaa577263eeb890b5b0a3cf0ad023c1c8ccc01080abf441a3d8fd1cb88a47","src/server.rs":"f01a418588a7d924dcfc0cdc632aec7f483a4ab5409c1b5563b2205d97cf8a49","src/stream.rs":"af00ffb61ce504a83fbe88b2ceb5780824008cff4a876007e969ec1455a7b723","src/tls.rs":"8260cf1ac17f404d5c985f3defb3ca799324449c3a98ff438c6d2a7805335049","src/util.rs":"ada1383900811e7c367f20d02ebf87145b423c3b8fcee1d64329578d80064f8d"},"package":"9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1"}
\ No newline at end of file
+{"files":{"CHANGELOG.md":"ae6128d53192e8eec364869fc02c987044a4211b21298247ad989cbb981a568f","Cargo.lock":"6ac6e83fedb4c5b323970104e305218d630d595f867d57386ab59331462389c2","Cargo.toml":"0a41d92c418e779828de62e0171305eeedeee7405bdebb3d6750eeedd312b774","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"7fea0ee51a4ca5d5cea7464135fd55e8b09caf3a61da3d451ac8a22af95c033f","README.md":"0a8b44c900be104faf8bb8d24e419ca1569e32d7bfae4f1528bc27f9f01d4b33","benches/buffer.rs":"615d66b4e5d5f11758aa111f2c3274e82dba5afeca3863bf39138d906c67344c","benches/write.rs":"921c72b4f1b219873fd2c69baa15fcb064373d55d0a5a47f29fc7f03eebde767","examples/autobahn-client.rs":"7382d937bd54c2c33dfeed627f5bdbbffd6df5c742cf45508399ff51ff5f56e6","examples/autobahn-server.rs":"4b50ff21113ca920a2d91a37f8f3452ecc64ee3dcf0d557905d3bcd1746a92e3","examples/callback-error.rs":"fe732374176dfe4e5d1f36a3fa09d6d6e3cc95885e920480ef5bcd94206835e0","examples/client.rs":"5c6826b77827351bd5821962a8cf44dccebf127a253ce21fca0b5aaf4114683f","examples/server.rs":"4f00ab0ee18c67d60242800143f5a380078bffbb59440b9038813a0987478d66","examples/srv_accept_unmasked_frames.rs":"044332980954b9f7c4c81f7d6c6003b9feb1b90d147ce1899e75e8d16c82bb7e","src/buffer.rs":"c346e4282b294b856d29a17ea078ebd2580b3142f531e1e10d545e4af0baba2b","src/client.rs":"7d9344d4985d31fd6c5816c66d01d4084b4aa45ce40e622556f9797fe161c144","src/error.rs":"0c26d00dc0cf0da1a73b04604a0230388b2de2b5a9da53eff8ac15e1143dcbfd","src/handshake/client.rs":"e2a1693a111fd41d09e2bbcb16645c87dc72fdbc3f232ccbd54e9a7daf578c6b","src/handshake/headers.rs":"0e6d3e15faa8b82bd2a239f5094335368e578acef2f17ee74825de606f529b75","src/handshake/machine.rs":"54a82a2643682e2ae17a98e69dcfa8ad10761919ea42f696551970057a428420","src/handshake/mod.rs":"b60daed1cff1a6f1692c2a7104df2b924d86a378a9375580ad8ddaf65a9fb5e5","src/handshake/server.rs":"9602d3330583d2a226ff5d084cd7a154bde50a26fd13b1b83335c3e5465f51a0","src/lib.rs":"8de3905c5f1699b2f52f86d11f3275f1b30f009a9bfbac7b9b784dc628537fb0","src/protocol/frame/coding.rs":"88b62c0bbce91edc9aea625889cfcb15b7e7c9b3fae00a31cbdae5b6aae1dde6","src/protocol/frame/frame.rs":"d60af70e22755abbec31acaeaa0dc99d65e83f038dc8509da68f78077801675c","src/protocol/frame/mask.rs":"ab2d387f9e2dbfda29b26d3147facacaeb7b91de1ae5d07d742fb9b9d297f8b1","src/protocol/frame/mod.rs":"7ae23d5c389fb1ff789b7f2597ff390d7846dfd5d654bccf4ec3682ad1741055","src/protocol/message.rs":"ce85c659ea1c384ed954d543e9d97b9d2a6e86cf1a472eac0a2c0a2a3a2b9997","src/protocol/mod.rs":"e24aaa577263eeb890b5b0a3cf0ad023c1c8ccc01080abf441a3d8fd1cb88a47","src/server.rs":"f01a418588a7d924dcfc0cdc632aec7f483a4ab5409c1b5563b2205d97cf8a49","src/stream.rs":"af00ffb61ce504a83fbe88b2ceb5780824008cff4a876007e969ec1455a7b723","src/tls.rs":"8260cf1ac17f404d5c985f3defb3ca799324449c3a98ff438c6d2a7805335049","src/util.rs":"ada1383900811e7c367f20d02ebf87145b423c3b8fcee1d64329578d80064f8d"},"package":"18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a"}
\ No newline at end of file
diff --git a/crates/tungstenite/Android.bp b/crates/tungstenite/Android.bp
index 2e273b6..6597038 100644
--- a/crates/tungstenite/Android.bp
+++ b/crates/tungstenite/Android.bp
@@ -18,7 +18,7 @@
     host_supported: true,
     crate_name: "tungstenite",
     cargo_env_compat: true,
-    cargo_pkg_version: "0.21.0",
+    cargo_pkg_version: "0.24.0",
     crate_root: "src/lib.rs",
     edition: "2018",
     rustlibs: [
diff --git a/crates/tungstenite/CHANGELOG.md b/crates/tungstenite/CHANGELOG.md
index 5c0348e..83cb076 100644
--- a/crates/tungstenite/CHANGELOG.md
+++ b/crates/tungstenite/CHANGELOG.md
@@ -1,8 +1,25 @@
-# Unreleased
+# 0.24.0
+
+- Raised MSRV to 1.63 to match `tokio-tungstenite`.
+- Connecting to WSS URL without TLS features specified results in a better error.
+- Handshake will now flush after completion to be safe (works better with buffered streams).
+
+# 0.23.0
+
+- Disable default features for `rustls` giving the user more flexibility.
+
+# 0.22.0
+- Make `url` optional.
+- Add a builder for convenient headers and subprotocols construction.
+- Update `rustls` dependency.
+
+# 0.21.0
 - Fix read-predominant auto pong responses not flushing when hitting WouldBlock errors.
 - Improve `FrameHeader::format` write correctness.
-- Up minimum _rustls_ to `0.21.6`.
-- Update _webpki-roots_ to `0.26`.
+- Update `rustls` to `0.22`.
+- Update `webpki-roots` to `0.26`.
+- Update `rustls-native-certs` to `0.7`.
+- Update `http` to `1.0.0`.
 
 # 0.20.1
 - Fixes [CVE-2023-43669](https://github.com/snapview/tungstenite-rs/pull/379).
diff --git a/crates/tungstenite/Cargo.lock b/crates/tungstenite/Cargo.lock
index 7ec88dc..ce1cc85 100644
--- a/crates/tungstenite/Cargo.lock
+++ b/crates/tungstenite/Cargo.lock
@@ -4,9 +4,9 @@
 
 [[package]]
 name = "aho-corasick"
-version = "1.1.2"
+version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
+checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41"
 dependencies = [
  "memchr",
 ]
@@ -19,9 +19,9 @@
 
 [[package]]
 name = "anstyle"
-version = "1.0.4"
+version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87"
+checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd"
 
 [[package]]
 name = "autocfg"
@@ -31,9 +31,9 @@
 
 [[package]]
 name = "base64"
-version = "0.21.5"
+version = "0.22.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9"
+checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
 
 [[package]]
 name = "bitflags"
@@ -43,9 +43,9 @@
 
 [[package]]
 name = "bitflags"
-version = "2.4.1"
+version = "2.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
+checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42"
 
 [[package]]
 name = "block-buffer"
@@ -58,21 +58,21 @@
 
 [[package]]
 name = "bumpalo"
-version = "3.14.0"
+version = "3.13.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
+checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
 
 [[package]]
 name = "byteorder"
-version = "1.5.0"
+version = "1.4.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
 
 [[package]]
 name = "bytes"
-version = "1.5.0"
+version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
+checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be"
 
 [[package]]
 name = "cast"
@@ -82,12 +82,9 @@
 
 [[package]]
 name = "cc"
-version = "1.0.83"
+version = "1.0.98"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
-dependencies = [
- "libc",
-]
+checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f"
 
 [[package]]
 name = "cfg-if"
@@ -124,18 +121,18 @@
 
 [[package]]
 name = "clap"
-version = "4.4.11"
+version = "4.3.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bfaff671f6b22ca62406885ece523383b9b64022e341e53e009a62ebc47a45f2"
+checksum = "5fd304a20bff958a57f04c4e96a2e7594cc4490a0e809cbd48bb6437edaa452d"
 dependencies = [
  "clap_builder",
 ]
 
 [[package]]
 name = "clap_builder"
-version = "4.4.11"
+version = "4.3.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a216b506622bb1d316cd51328dce24e07bdff4a6128a47c7e7fad11878d5adbb"
+checksum = "01c6a3f08f1fe5662a35cfe393aec09c4df95f60ee93b7556505260f75eee9e1"
 dependencies = [
  "anstyle",
  "clap_lex",
@@ -143,15 +140,15 @@
 
 [[package]]
 name = "clap_lex"
-version = "0.6.0"
+version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1"
+checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b"
 
 [[package]]
 name = "core-foundation"
-version = "0.9.4"
+version = "0.9.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
+checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
 dependencies = [
  "core-foundation-sys",
  "libc",
@@ -159,15 +156,15 @@
 
 [[package]]
 name = "core-foundation-sys"
-version = "0.8.6"
+version = "0.8.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
+checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
 
 [[package]]
 name = "cpufeatures"
-version = "0.2.11"
+version = "0.2.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0"
+checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1"
 dependencies = [
  "libc",
 ]
@@ -209,6 +206,16 @@
 ]
 
 [[package]]
+name = "crossbeam-channel"
+version = "0.5.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200"
+dependencies = [
+ "cfg-if",
+ "crossbeam-utils",
+]
+
+[[package]]
 name = "crossbeam-deque"
 version = "0.8.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -253,9 +260,9 @@
 
 [[package]]
 name = "data-encoding"
-version = "2.5.0"
+version = "2.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5"
+checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308"
 
 [[package]]
 name = "digest"
@@ -275,9 +282,9 @@
 
 [[package]]
 name = "env_logger"
-version = "0.10.1"
+version = "0.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece"
+checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0"
 dependencies = [
  "humantime",
  "is-terminal",
@@ -288,19 +295,30 @@
 
 [[package]]
 name = "errno"
-version = "0.3.8"
+version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
+checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
 dependencies = [
+ "errno-dragonfly",
  "libc",
- "windows-sys 0.52.0",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "errno-dragonfly"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
+dependencies = [
+ "cc",
+ "libc",
 ]
 
 [[package]]
 name = "fastrand"
-version = "2.0.1"
+version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5"
+checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764"
 
 [[package]]
 name = "fnv"
@@ -325,9 +343,9 @@
 
 [[package]]
 name = "form_urlencoded"
-version = "1.2.1"
+version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
+checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652"
 dependencies = [
  "percent-encoding",
 ]
@@ -344,9 +362,9 @@
 
 [[package]]
 name = "getrandom"
-version = "0.2.11"
+version = "0.2.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f"
+checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
 dependencies = [
  "cfg-if",
  "libc",
@@ -361,15 +379,15 @@
 
 [[package]]
 name = "hermit-abi"
-version = "0.3.3"
+version = "0.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7"
+checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
 
 [[package]]
 name = "http"
-version = "1.0.0"
+version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b32afd38673a8016f7c9ae69e5af41a58f81b1d31689040f2f1959594ce194ea"
+checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258"
 dependencies = [
  "bytes",
  "fnv",
@@ -390,9 +408,9 @@
 
 [[package]]
 name = "idna"
-version = "0.5.0"
+version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
+checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c"
 dependencies = [
  "unicode-bidi",
  "unicode-normalization",
@@ -435,9 +453,9 @@
 
 [[package]]
 name = "js-sys"
-version = "0.3.66"
+version = "0.3.64"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca"
+checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a"
 dependencies = [
  "wasm-bindgen",
 ]
@@ -450,27 +468,27 @@
 
 [[package]]
 name = "libc"
-version = "0.2.150"
+version = "0.2.155"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
+checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
 
 [[package]]
 name = "linux-raw-sys"
-version = "0.4.12"
+version = "0.4.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456"
+checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0"
 
 [[package]]
 name = "log"
-version = "0.4.20"
+version = "0.4.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
+checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4"
 
 [[package]]
 name = "memchr"
-version = "2.6.4"
+version = "2.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
+checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
 
 [[package]]
 name = "memoffset"
@@ -501,14 +519,24 @@
 
 [[package]]
 name = "num-traits"
-version = "0.2.17"
+version = "0.2.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
+checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2"
 dependencies = [
  "autocfg",
 ]
 
 [[package]]
+name = "num_cpus"
+version = "1.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
+dependencies = [
+ "hermit-abi",
+ "libc",
+]
+
+[[package]]
 name = "once_cell"
 version = "1.18.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -522,11 +550,11 @@
 
 [[package]]
 name = "openssl"
-version = "0.10.61"
+version = "0.10.55"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6b8419dc8cc6d866deb801274bba2e6f8f6108c1bb7fcc10ee5ab864931dbb45"
+checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d"
 dependencies = [
- "bitflags 2.4.1",
+ "bitflags 1.3.2",
  "cfg-if",
  "foreign-types",
  "libc",
@@ -554,18 +582,18 @@
 
 [[package]]
 name = "openssl-src"
-version = "300.1.6+3.1.4"
+version = "111.26.0+1.1.1u"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "439fac53e092cd7442a3660c85dde4643ab3b5bd39040912388dcdabf6b88085"
+checksum = "efc62c9f12b22b8f5208c23a7200a442b2e5999f8bdf80233852122b5a4f6f37"
 dependencies = [
  "cc",
 ]
 
 [[package]]
 name = "openssl-sys"
-version = "0.9.97"
+version = "0.9.90"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3eaad34cdd97d81de97964fc7f29e2d104f483840d906ef56daa1912338460b"
+checksum = "374533b0e45f3a7ced10fcaeccca020e66656bc03dac384f852e4e5a7a8104a6"
 dependencies = [
  "cc",
  "libc",
@@ -576,9 +604,9 @@
 
 [[package]]
 name = "percent-encoding"
-version = "2.3.1"
+version = "2.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
+checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
 
 [[package]]
 name = "pkg-config"
@@ -622,18 +650,18 @@
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.70"
+version = "1.0.66"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b"
+checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
 dependencies = [
  "unicode-ident",
 ]
 
 [[package]]
 name = "quote"
-version = "1.0.33"
+version = "1.0.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
+checksum = "5fe8a65d69dd0808184ebb5f836ab526bb259db23c657efa38711b1072ee47f0"
 dependencies = [
  "proc-macro2",
 ]
@@ -670,9 +698,9 @@
 
 [[package]]
 name = "rayon"
-version = "1.8.0"
+version = "1.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1"
+checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b"
 dependencies = [
  "either",
  "rayon-core",
@@ -680,28 +708,30 @@
 
 [[package]]
 name = "rayon-core"
-version = "1.12.0"
+version = "1.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed"
+checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d"
 dependencies = [
+ "crossbeam-channel",
  "crossbeam-deque",
  "crossbeam-utils",
+ "num_cpus",
 ]
 
 [[package]]
 name = "redox_syscall"
-version = "0.4.1"
+version = "0.3.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
+checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
 dependencies = [
  "bitflags 1.3.2",
 ]
 
 [[package]]
 name = "regex"
-version = "1.10.2"
+version = "1.9.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
+checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -711,9 +741,9 @@
 
 [[package]]
 name = "regex-automata"
-version = "0.4.3"
+version = "0.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
+checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -722,45 +752,45 @@
 
 [[package]]
 name = "regex-syntax"
-version = "0.8.2"
+version = "0.7.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
+checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2"
 
 [[package]]
 name = "ring"
-version = "0.17.7"
+version = "0.17.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74"
+checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d"
 dependencies = [
  "cc",
+ "cfg-if",
  "getrandom",
  "libc",
  "spin",
  "untrusted",
- "windows-sys 0.48.0",
-]
-
-[[package]]
-name = "rustix"
-version = "0.38.26"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9470c4bf8246c8daf25f9598dca807fb6510347b1e1cfa55749113850c79d88a"
-dependencies = [
- "bitflags 2.4.1",
- "errno",
- "libc",
- "linux-raw-sys",
  "windows-sys 0.52.0",
 ]
 
 [[package]]
-name = "rustls"
-version = "0.22.0"
+name = "rustix"
+version = "0.38.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5bc238b76c51bbc449c55ffbc39d03772a057cc8cf783c49d4af4c2537b74a8b"
+checksum = "0a962918ea88d644592894bc6dc55acc6c0956488adcebbfb6e273506b7fd6e5"
 dependencies = [
- "log",
- "ring",
+ "bitflags 2.3.3",
+ "errno",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "rustls"
+version = "0.23.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "79adb16721f56eb2d843e67676896a61ce7a0fa622dc18d3e372477a029d2740"
+dependencies = [
+ "once_cell",
  "rustls-pki-types",
  "rustls-webpki",
  "subtle",
@@ -782,9 +812,9 @@
 
 [[package]]
 name = "rustls-pemfile"
-version = "2.0.0"
+version = "2.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "35e4980fa29e4c4b212ffb3db068a564cbf560e51d3944b7c88bd8bf5bec64f4"
+checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d"
 dependencies = [
  "base64",
  "rustls-pki-types",
@@ -792,15 +822,15 @@
 
 [[package]]
 name = "rustls-pki-types"
-version = "1.0.1"
+version = "1.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7673e0aa20ee4937c6aacfc12bb8341cfbf054cdd21df6bec5fd0629fe9339b"
+checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d"
 
 [[package]]
 name = "rustls-webpki"
-version = "0.102.0"
+version = "0.102.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "de2635c8bc2b88d367767c5de8ea1d8db9af3f6219eba28442242d9ab81d1b89"
+checksum = "ff448f7e92e913c4b7d4c6d8e4540a1724b319b4152b8aef6d4cf8339712b33e"
 dependencies = [
  "ring",
  "rustls-pki-types",
@@ -862,18 +892,18 @@
 
 [[package]]
 name = "serde"
-version = "1.0.193"
+version = "1.0.174"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
+checksum = "3b88756493a5bd5e5395d53baa70b194b05764ab85b59e43e4b8f4e1192fa9b1"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.193"
+version = "1.0.174"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
+checksum = "6e5c3a298c7f978e53536f95a63bdc4c4a64550582f31a0359a9afda6aede62e"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -882,9 +912,9 @@
 
 [[package]]
 name = "serde_json"
-version = "1.0.108"
+version = "1.0.103"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b"
+checksum = "d03b412469450d4404fe8499a268edd7f8b79fecb074b0d812ad64ca21f4031b"
 dependencies = [
  "itoa",
  "ryu",
@@ -893,9 +923,9 @@
 
 [[package]]
 name = "sha1"
-version = "0.10.6"
+version = "0.10.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
+checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3"
 dependencies = [
  "cfg-if",
  "cpufeatures",
@@ -904,12 +934,12 @@
 
 [[package]]
 name = "socket2"
-version = "0.5.5"
+version = "0.5.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9"
+checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c"
 dependencies = [
  "libc",
- "windows-sys 0.48.0",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
@@ -926,9 +956,9 @@
 
 [[package]]
 name = "syn"
-version = "2.0.39"
+version = "2.0.27"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a"
+checksum = "b60f673f44a8255b9c8c657daf66a596d435f2da81a555b06dc644d080ba45e0"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -937,9 +967,9 @@
 
 [[package]]
 name = "tempfile"
-version = "3.8.1"
+version = "3.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5"
+checksum = "5486094ee78b2e5038a6382ed7645bc084dc2ec433426ca4c3cb61e2007b8998"
 dependencies = [
  "cfg-if",
  "fastrand",
@@ -950,27 +980,27 @@
 
 [[package]]
 name = "termcolor"
-version = "1.4.0"
+version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449"
+checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
 dependencies = [
  "winapi-util",
 ]
 
 [[package]]
 name = "thiserror"
-version = "1.0.50"
+version = "1.0.44"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2"
+checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.50"
+version = "1.0.44"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8"
+checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1004,7 +1034,7 @@
 
 [[package]]
 name = "tungstenite"
-version = "0.21.0"
+version = "0.24.0"
 dependencies = [
  "byteorder",
  "bytes",
@@ -1030,21 +1060,21 @@
 
 [[package]]
 name = "typenum"
-version = "1.17.0"
+version = "1.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
+checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
 
 [[package]]
 name = "unicode-bidi"
-version = "0.3.14"
+version = "0.3.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416"
+checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
 
 [[package]]
 name = "unicode-ident"
-version = "1.0.12"
+version = "1.0.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c"
 
 [[package]]
 name = "unicode-normalization"
@@ -1063,9 +1093,9 @@
 
 [[package]]
 name = "url"
-version = "2.5.0"
+version = "2.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633"
+checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb"
 dependencies = [
  "form_urlencoded",
  "idna",
@@ -1092,9 +1122,9 @@
 
 [[package]]
 name = "walkdir"
-version = "2.4.0"
+version = "2.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee"
+checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698"
 dependencies = [
  "same-file",
  "winapi-util",
@@ -1108,9 +1138,9 @@
 
 [[package]]
 name = "wasm-bindgen"
-version = "0.2.89"
+version = "0.2.87"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e"
+checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342"
 dependencies = [
  "cfg-if",
  "wasm-bindgen-macro",
@@ -1118,9 +1148,9 @@
 
 [[package]]
 name = "wasm-bindgen-backend"
-version = "0.2.89"
+version = "0.2.87"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826"
+checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd"
 dependencies = [
  "bumpalo",
  "log",
@@ -1133,9 +1163,9 @@
 
 [[package]]
 name = "wasm-bindgen-macro"
-version = "0.2.89"
+version = "0.2.87"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2"
+checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d"
 dependencies = [
  "quote",
  "wasm-bindgen-macro-support",
@@ -1143,9 +1173,9 @@
 
 [[package]]
 name = "wasm-bindgen-macro-support"
-version = "0.2.89"
+version = "0.2.87"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283"
+checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1156,15 +1186,15 @@
 
 [[package]]
 name = "wasm-bindgen-shared"
-version = "0.2.89"
+version = "0.2.87"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f"
+checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
 
 [[package]]
 name = "web-sys"
-version = "0.3.66"
+version = "0.3.64"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f"
+checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b"
 dependencies = [
  "js-sys",
  "wasm-bindgen",
@@ -1172,9 +1202,9 @@
 
 [[package]]
 name = "webpki-roots"
-version = "0.26.0"
+version = "0.26.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0de2cfda980f21be5a7ed2eadb3e6fe074d56022bea2cdeb1a62eb220fc04188"
+checksum = "b3de34ae270483955a94f4b21bdaaeb83d508bb84a01435f393818edb0012009"
 dependencies = [
  "rustls-pki-types",
 ]
@@ -1197,9 +1227,9 @@
 
 [[package]]
 name = "winapi-util"
-version = "0.1.6"
+version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
+checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
 dependencies = [
  "winapi",
 ]
@@ -1216,7 +1246,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
 dependencies = [
- "windows-targets 0.48.5",
+ "windows-targets 0.48.1",
 ]
 
 [[package]]
@@ -1225,125 +1255,132 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
 dependencies = [
- "windows-targets 0.52.0",
+ "windows-targets 0.52.5",
 ]
 
 [[package]]
 name = "windows-targets"
-version = "0.48.5"
+version = "0.48.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
+checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f"
 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_aarch64_gnullvm 0.48.0",
+ "windows_aarch64_msvc 0.48.0",
+ "windows_i686_gnu 0.48.0",
+ "windows_i686_msvc 0.48.0",
+ "windows_x86_64_gnu 0.48.0",
+ "windows_x86_64_gnullvm 0.48.0",
+ "windows_x86_64_msvc 0.48.0",
 ]
 
 [[package]]
 name = "windows-targets"
-version = "0.52.0"
+version = "0.52.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
+checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
 dependencies = [
- "windows_aarch64_gnullvm 0.52.0",
- "windows_aarch64_msvc 0.52.0",
- "windows_i686_gnu 0.52.0",
- "windows_i686_msvc 0.52.0",
- "windows_x86_64_gnu 0.52.0",
- "windows_x86_64_gnullvm 0.52.0",
- "windows_x86_64_msvc 0.52.0",
+ "windows_aarch64_gnullvm 0.52.5",
+ "windows_aarch64_msvc 0.52.5",
+ "windows_i686_gnu 0.52.5",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc 0.52.5",
+ "windows_x86_64_gnu 0.52.5",
+ "windows_x86_64_gnullvm 0.52.5",
+ "windows_x86_64_msvc 0.52.5",
 ]
 
 [[package]]
 name = "windows_aarch64_gnullvm"
-version = "0.48.5"
+version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
+checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
 
 [[package]]
 name = "windows_aarch64_gnullvm"
-version = "0.52.0"
+version = "0.52.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
+checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
 
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.48.5"
+version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
+checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
 
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.52.0"
+version = "0.52.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
+checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.48.5"
+version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
+checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.52.0"
+version = "0.52.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
+checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.48.5"
+version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
+checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.52.0"
+version = "0.52.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
+checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.48.5"
+version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
+checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.52.0"
+version = "0.52.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
+checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
-version = "0.48.5"
+version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
+checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
-version = "0.52.0"
+version = "0.52.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
+checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
 
 [[package]]
 name = "windows_x86_64_msvc"
-version = "0.48.5"
+version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
+checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
 
 [[package]]
 name = "windows_x86_64_msvc"
-version = "0.52.0"
+version = "0.52.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
+checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
 
 [[package]]
 name = "zeroize"
-version = "1.7.0"
+version = "1.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d"
+checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
diff --git a/crates/tungstenite/Cargo.toml b/crates/tungstenite/Cargo.toml
index 3d8cca5..beee740 100644
--- a/crates/tungstenite/Cargo.toml
+++ b/crates/tungstenite/Cargo.toml
@@ -11,13 +11,14 @@
 
 [package]
 edition = "2018"
-rust-version = "1.51"
+rust-version = "1.63"
 name = "tungstenite"
-version = "0.21.0"
+version = "0.24.0"
 authors = [
     "Alexey Galakhov",
     "Daniel Abramov",
 ]
+build = false
 include = [
     "benches/**/*",
     "src/**/*",
@@ -26,9 +27,13 @@
     "README.md",
     "CHANGELOG.md",
 ]
+autobins = false
+autoexamples = false
+autotests = false
+autobenches = false
 description = "Lightweight stream-based WebSocket implementation"
 homepage = "https://github.com/snapview/tungstenite-rs"
-documentation = "https://docs.rs/tungstenite/0.21.0"
+documentation = "https://docs.rs/tungstenite/0.24.0"
 readme = "README.md"
 keywords = [
     "websocket",
@@ -45,36 +50,48 @@
 [package.metadata.docs.rs]
 all-features = true
 
-[[example]]
-name = "client"
-required-features = ["handshake"]
-
-[[example]]
-name = "server"
-required-features = ["handshake"]
+[lib]
+name = "tungstenite"
+path = "src/lib.rs"
 
 [[example]]
 name = "autobahn-client"
+path = "examples/autobahn-client.rs"
 required-features = ["handshake"]
 
 [[example]]
 name = "autobahn-server"
+path = "examples/autobahn-server.rs"
 required-features = ["handshake"]
 
 [[example]]
 name = "callback-error"
+path = "examples/callback-error.rs"
+required-features = ["handshake"]
+
+[[example]]
+name = "client"
+path = "examples/client.rs"
+required-features = ["handshake"]
+
+[[example]]
+name = "server"
+path = "examples/server.rs"
 required-features = ["handshake"]
 
 [[example]]
 name = "srv_accept_unmasked_frames"
+path = "examples/srv_accept_unmasked_frames.rs"
 required-features = ["handshake"]
 
 [[bench]]
 name = "buffer"
+path = "benches/buffer.rs"
 harness = false
 
 [[bench]]
 name = "write"
+path = "benches/write.rs"
 harness = false
 
 [dependencies.byteorder]
@@ -107,8 +124,10 @@
 version = "0.8.0"
 
 [dependencies.rustls]
-version = "0.22.0"
+version = "0.23.0"
+features = ["std"]
 optional = true
+default-features = false
 
 [dependencies.rustls-native-certs]
 version = "0.7.0"
@@ -162,7 +181,6 @@
     "http",
     "httparse",
     "sha1",
-    "url",
 ]
 native-tls = ["native-tls-crate"]
 native-tls-vendored = [
@@ -177,3 +195,4 @@
     "__rustls-tls",
     "webpki-roots",
 ]
+url = ["dep:url"]
diff --git a/crates/tungstenite/METADATA b/crates/tungstenite/METADATA
index 288a9f7..d92dd4d 100644
--- a/crates/tungstenite/METADATA
+++ b/crates/tungstenite/METADATA
@@ -1,17 +1,17 @@
 name: "tungstenite"
 description: "Lightweight stream-based WebSocket implementation"
 third_party {
-  version: "0.21.0"
+  version: "0.24.0"
   license_type: NOTICE
   last_upgrade_date {
     year: 2024
-    month: 2
-    day: 8
+    month: 12
+    day: 20
   }
   homepage: "https://crates.io/crates/tungstenite"
   identifier {
     type: "Archive"
-    value: "https://static.crates.io/crates/tungstenite/tungstenite-0.21.0.crate"
-    version: "0.21.0"
+    value: "https://static.crates.io/crates/tungstenite/tungstenite-0.24.0.crate"
+    version: "0.24.0"
   }
 }
diff --git a/crates/tungstenite/examples/autobahn-client.rs b/crates/tungstenite/examples/autobahn-client.rs
index ac7a7d1..577d5e7 100644
--- a/crates/tungstenite/examples/autobahn-client.rs
+++ b/crates/tungstenite/examples/autobahn-client.rs
@@ -1,29 +1,25 @@
 use log::*;
-use url::Url;
 
 use tungstenite::{connect, Error, Message, Result};
 
 const AGENT: &str = "Tungstenite";
 
 fn get_case_count() -> Result<u32> {
-    let (mut socket, _) = connect(Url::parse("ws://localhost:9001/getCaseCount").unwrap())?;
+    let (mut socket, _) = connect("ws://localhost:9001/getCaseCount")?;
     let msg = socket.read()?;
     socket.close(None)?;
     Ok(msg.into_text()?.parse::<u32>().unwrap())
 }
 
 fn update_reports() -> Result<()> {
-    let (mut socket, _) = connect(
-        Url::parse(&format!("ws://localhost:9001/updateReports?agent={}", AGENT)).unwrap(),
-    )?;
+    let (mut socket, _) = connect(&format!("ws://localhost:9001/updateReports?agent={AGENT}"))?;
     socket.close(None)?;
     Ok(())
 }
 
 fn run_test(case: u32) -> Result<()> {
     info!("Running test case {}", case);
-    let case_url =
-        Url::parse(&format!("ws://localhost:9001/runCase?case={}&agent={}", case, AGENT)).unwrap();
+    let case_url = &format!("ws://localhost:9001/runCase?case={case}&agent={AGENT}");
     let (mut socket, _) = connect(case_url)?;
     loop {
         match socket.read()? {
diff --git a/crates/tungstenite/examples/client.rs b/crates/tungstenite/examples/client.rs
index a24f316..5eeba76 100644
--- a/crates/tungstenite/examples/client.rs
+++ b/crates/tungstenite/examples/client.rs
@@ -1,23 +1,21 @@
 use tungstenite::{connect, Message};
-use url::Url;
 
 fn main() {
     env_logger::init();
 
-    let (mut socket, response) =
-        connect(Url::parse("ws://localhost:3012/socket").unwrap()).expect("Can't connect");
+    let (mut socket, response) = connect("ws://localhost:3012/socket").expect("Can't connect");
 
     println!("Connected to the server");
     println!("Response HTTP code: {}", response.status());
     println!("Response contains the following headers:");
     for (ref header, _value) in response.headers() {
-        println!("* {}", header);
+        println!("* {header}");
     }
 
     socket.send(Message::Text("Hello WebSocket".into())).unwrap();
     loop {
         let msg = socket.read().expect("Error reading message");
-        println!("Received: {}", msg);
+        println!("Received: {msg}");
     }
     // socket.close(None);
 }
diff --git a/crates/tungstenite/examples/server.rs b/crates/tungstenite/examples/server.rs
index 2183b96..14100a6 100644
--- a/crates/tungstenite/examples/server.rs
+++ b/crates/tungstenite/examples/server.rs
@@ -15,7 +15,7 @@
                 println!("The request's path is: {}", req.uri().path());
                 println!("The request's headers are:");
                 for (ref header, _value) in req.headers() {
-                    println!("* {}", header);
+                    println!("* {header}");
                 }
 
                 // Let's add an additional header to our response to the client.
diff --git a/crates/tungstenite/examples/srv_accept_unmasked_frames.rs b/crates/tungstenite/examples/srv_accept_unmasked_frames.rs
index b65e4f7..7c75721 100644
--- a/crates/tungstenite/examples/srv_accept_unmasked_frames.rs
+++ b/crates/tungstenite/examples/srv_accept_unmasked_frames.rs
@@ -15,7 +15,7 @@
                 println!("The request's path is: {}", req.uri().path());
                 println!("The request's headers are:");
                 for (ref header, _value) in req.headers() {
-                    println!("* {}", header);
+                    println!("* {header}");
                 }
 
                 // Let's add an additional header to our response to the client.
@@ -40,7 +40,7 @@
             loop {
                 let msg = websocket.read().unwrap();
                 if msg.is_binary() || msg.is_text() {
-                    println!("received message {}", msg);
+                    println!("received message {msg}");
                 }
             }
         });
diff --git a/crates/tungstenite/src/client.rs b/crates/tungstenite/src/client.rs
index 9b30037..5b4dd0f 100644
--- a/crates/tungstenite/src/client.rs
+++ b/crates/tungstenite/src/client.rs
@@ -1,16 +1,15 @@
 //! Methods to connect to a WebSocket as a client.
 
 use std::{
+    convert::TryFrom,
     io::{Read, Write},
     net::{SocketAddr, TcpStream, ToSocketAddrs},
     result::Result as StdResult,
 };
 
-use http::{request::Parts, Uri};
+use http::{request::Parts, HeaderName, Uri};
 use log::*;
 
-use url::Url;
-
 use crate::{
     handshake::client::{generate_key, Request, Response},
     protocol::WebSocketConfig,
@@ -53,6 +52,12 @@
     ) -> Result<(WebSocket<MaybeTlsStream<TcpStream>>, Response)> {
         let uri = request.uri();
         let mode = uri_mode(uri)?;
+
+        #[cfg(not(any(feature = "native-tls", feature = "__rustls-tls")))]
+        if let Mode::Tls = mode {
+            return Err(Error::Url(UrlError::TlsFeatureNotEnabled));
+        }
+
         let host = request.uri().host().ok_or(Error::Url(UrlError::NoHostName))?;
         let host = if host.starts_with('[') { &host[1..host.len() - 1] } else { host };
         let port = uri.port_u16().unwrap_or(match mode {
@@ -181,7 +186,7 @@
 
 /// Trait for converting various types into HTTP requests used for a client connection.
 ///
-/// This trait is implemented by default for string slices, strings, `url::Url`, `http::Uri` and
+/// This trait is implemented by default for string slices, strings, `http::Uri` and
 /// `http::Request<()>`. Note that the implementation for `http::Request<()>` is trivial and will
 /// simply take your request and pass it as is further without altering any headers or URLs, so
 /// be aware of this. If you just want to connect to the endpoint with a certain URL, better pass
@@ -241,13 +246,15 @@
     }
 }
 
-impl<'a> IntoClientRequest for &'a Url {
+#[cfg(feature = "url")]
+impl<'a> IntoClientRequest for &'a url::Url {
     fn into_client_request(self) -> Result<Request> {
         self.as_str().into_client_request()
     }
 }
 
-impl IntoClientRequest for Url {
+#[cfg(feature = "url")]
+impl IntoClientRequest for url::Url {
     fn into_client_request(self) -> Result<Request> {
         self.as_str().into_client_request()
     }
@@ -265,3 +272,73 @@
         Request::from_httparse(self)
     }
 }
+
+/// Builder for a custom [`IntoClientRequest`] with options to add
+/// custom additional headers and sub protocols.
+///
+/// # Example
+///
+/// ```rust no_run
+/// # use crate::*;
+/// use http::Uri;
+/// use tungstenite::{connect, ClientRequestBuilder};
+///
+/// let uri: Uri = "ws://localhost:3012/socket".parse().unwrap();
+/// let token = "my_jwt_token";
+/// let builder = ClientRequestBuilder::new(uri)
+///     .with_header("Authorization", format!("Bearer {token}"))
+///     .with_sub_protocol("my_sub_protocol");
+/// let socket = connect(builder).unwrap();
+/// ```
+#[derive(Debug, Clone)]
+pub struct ClientRequestBuilder {
+    uri: Uri,
+    /// Additional [`Request`] handshake headers
+    additional_headers: Vec<(String, String)>,
+    /// Handsake subprotocols
+    subprotocols: Vec<String>,
+}
+
+impl ClientRequestBuilder {
+    /// Initializes an empty request builder
+    #[must_use]
+    pub const fn new(uri: Uri) -> Self {
+        Self { uri, additional_headers: Vec::new(), subprotocols: Vec::new() }
+    }
+
+    /// Adds (`key`, `value`) as an additional header to the handshake request
+    pub fn with_header<K, V>(mut self, key: K, value: V) -> Self
+    where
+        K: Into<String>,
+        V: Into<String>,
+    {
+        self.additional_headers.push((key.into(), value.into()));
+        self
+    }
+
+    /// Adds `protocol` to the handshake request subprotocols (`Sec-WebSocket-Protocol`)
+    pub fn with_sub_protocol<P>(mut self, protocol: P) -> Self
+    where
+        P: Into<String>,
+    {
+        self.subprotocols.push(protocol.into());
+        self
+    }
+}
+
+impl IntoClientRequest for ClientRequestBuilder {
+    fn into_client_request(self) -> Result<Request> {
+        let mut request = self.uri.into_client_request()?;
+        let headers = request.headers_mut();
+        for (k, v) in self.additional_headers {
+            let key = HeaderName::try_from(k)?;
+            let value = v.parse()?;
+            headers.append(key, value);
+        }
+        if !self.subprotocols.is_empty() {
+            let protocols = self.subprotocols.join(", ").parse()?;
+            headers.append("Sec-WebSocket-Protocol", protocols);
+        }
+        Ok(request)
+    }
+}
diff --git a/crates/tungstenite/src/error.rs b/crates/tungstenite/src/error.rs
index faea80b..eaf7d24 100644
--- a/crates/tungstenite/src/error.rs
+++ b/crates/tungstenite/src/error.rs
@@ -149,6 +149,23 @@
     },
 }
 
+/// Indicates the specific type/cause of a subprotocol header error.
+#[derive(Error, Clone, PartialEq, Eq, Debug, Copy)]
+pub enum SubProtocolError {
+    /// The server sent a subprotocol to a client handshake request but none was requested
+    #[error("Server sent a subprotocol but none was requested")]
+    ServerSentSubProtocolNoneRequested,
+
+    /// The server sent an invalid subprotocol to a client handhshake request
+    #[error("Server sent an invalid subprotocol")]
+    InvalidSubProtocol,
+
+    /// The server sent no subprotocol to a client handshake request that requested one or more
+    /// subprotocols
+    #[error("Server sent no subprotocol")]
+    NoSubProtocol,
+}
+
 /// Indicates the specific type/cause of a protocol error.
 #[allow(missing_copy_implementations)]
 #[derive(Error, Debug, PartialEq, Eq, Clone)]
@@ -174,6 +191,9 @@
     /// The `Sec-WebSocket-Accept` header is either not present or does not specify the correct key value.
     #[error("Key mismatch in \"Sec-WebSocket-Accept\" header")]
     SecWebSocketAcceptKeyMismatch,
+    /// The `Sec-WebSocket-Protocol` header was invalid
+    #[error("SubProtocol error: {0}")]
+    SecWebSocketSubProtocolError(SubProtocolError),
     /// Garbage data encountered after client request.
     #[error("Junk after client request")]
     JunkAfterRequest,
diff --git a/crates/tungstenite/src/handshake/client.rs b/crates/tungstenite/src/handshake/client.rs
index 08cc7b2..ecc727c 100644
--- a/crates/tungstenite/src/handshake/client.rs
+++ b/crates/tungstenite/src/handshake/client.rs
@@ -18,7 +18,7 @@
     HandshakeRole, MidHandshake, ProcessingResult,
 };
 use crate::{
-    error::{Error, ProtocolError, Result, UrlError},
+    error::{Error, ProtocolError, Result, SubProtocolError, UrlError},
     protocol::{Role, WebSocket, WebSocketConfig},
 };
 
@@ -54,6 +54,8 @@
         // Check the URI scheme: only ws or wss are supported
         let _ = crate::client::uri_mode(request.uri())?;
 
+        let subprotocols = extract_subprotocols_from_request(&request)?;
+
         // Convert and verify the `http::Request` and turn it into the request as per RFC.
         // Also extract the key from it (it must be present in a correct request).
         let (request, key) = generate_request(request)?;
@@ -62,7 +64,11 @@
 
         let client = {
             let accept_key = derive_accept_key(key.as_ref());
-            ClientHandshake { verify_data: VerifyData { accept_key }, config, _marker: PhantomData }
+            ClientHandshake {
+                verify_data: VerifyData { accept_key, subprotocols },
+                config,
+                _marker: PhantomData,
+            }
         };
 
         trace!("Client handshake initiated.");
@@ -178,11 +184,22 @@
     Ok((req, key))
 }
 
+fn extract_subprotocols_from_request(request: &Request) -> Result<Option<Vec<String>>> {
+    if let Some(subprotocols) = request.headers().get("Sec-WebSocket-Protocol") {
+        Ok(Some(subprotocols.to_str()?.split(",").map(|s| s.to_string()).collect()))
+    } else {
+        Ok(None)
+    }
+}
+
 /// Information for handshake verification.
 #[derive(Debug)]
 struct VerifyData {
     /// Accepted server key.
     accept_key: String,
+
+    /// Accepted subprotocols
+    subprotocols: Option<Vec<String>>,
 }
 
 impl VerifyData {
@@ -238,7 +255,27 @@
         // not present in the client's handshake (the server has indicated a
         // subprotocol not requested by the client), the client MUST _Fail
         // the WebSocket Connection_. (RFC 6455)
-        // TODO
+        if headers.get("Sec-WebSocket-Protocol").is_none() && self.subprotocols.is_some() {
+            return Err(Error::Protocol(ProtocolError::SecWebSocketSubProtocolError(
+                SubProtocolError::NoSubProtocol,
+            )));
+        }
+
+        if headers.get("Sec-WebSocket-Protocol").is_some() && self.subprotocols.is_none() {
+            return Err(Error::Protocol(ProtocolError::SecWebSocketSubProtocolError(
+                SubProtocolError::ServerSentSubProtocolNoneRequested,
+            )));
+        }
+
+        if let Some(returned_subprotocol) = headers.get("Sec-WebSocket-Protocol") {
+            if let Some(accepted_subprotocols) = &self.subprotocols {
+                if !accepted_subprotocols.contains(&returned_subprotocol.to_str()?.to_string()) {
+                    return Err(Error::Protocol(ProtocolError::SecWebSocketSubProtocolError(
+                        SubProtocolError::InvalidSubProtocol,
+                    )));
+                }
+            }
+        }
 
         Ok(response)
     }
@@ -290,9 +327,9 @@
     #[test]
     fn random_keys() {
         let k1 = generate_key();
-        println!("Generated random key 1: {}", k1);
+        println!("Generated random key 1: {k1}");
         let k2 = generate_key();
-        println!("Generated random key 2: {}", k2);
+        println!("Generated random key 2: {k2}");
         assert_ne!(k1, k2);
         assert_eq!(k1.len(), k2.len());
         assert_eq!(k1.len(), 24);
@@ -312,9 +349,7 @@
             Upgrade: websocket\r\n\
             Sec-WebSocket-Version: 13\r\n\
             Sec-WebSocket-Key: {key}\r\n\
-            \r\n",
-            host = host,
-            key = key
+            \r\n"
         )
         .into_bytes()
     }
diff --git a/crates/tungstenite/src/handshake/machine.rs b/crates/tungstenite/src/handshake/machine.rs
index 2e3f2cb..fc3cb55 100644
--- a/crates/tungstenite/src/handshake/machine.rs
+++ b/crates/tungstenite/src/handshake/machine.rs
@@ -81,7 +81,10 @@
                             ..self
                         })
                     } else {
-                        RoundResult::StageFinished(StageResult::DoneWriting(self.stream))
+                        RoundResult::Incomplete(HandshakeMachine {
+                            state: HandshakeState::Flushing,
+                            ..self
+                        })
                     })
                 } else {
                     Ok(RoundResult::WouldBlock(HandshakeMachine {
@@ -90,6 +93,13 @@
                     }))
                 }
             }
+            HandshakeState::Flushing => Ok(match self.stream.flush().no_block()? {
+                Some(()) => RoundResult::StageFinished(StageResult::DoneWriting(self.stream)),
+                None => RoundResult::WouldBlock(HandshakeMachine {
+                    state: HandshakeState::Flushing,
+                    ..self
+                }),
+            }),
         }
     }
 }
@@ -128,6 +138,8 @@
     Reading(ReadBuffer, AttackCheck),
     /// Sending data to the peer.
     Writing(Cursor<Vec<u8>>),
+    /// Flushing data to ensure that all intermediately buffered contents reach their destination.
+    Flushing,
 }
 
 /// Attack mitigation. Contains counters needed to prevent DoS attacks
diff --git a/crates/tungstenite/src/handshake/mod.rs b/crates/tungstenite/src/handshake/mod.rs
index a8db9a9..765b137 100644
--- a/crates/tungstenite/src/handshake/mod.rs
+++ b/crates/tungstenite/src/handshake/mod.rs
@@ -64,7 +64,7 @@
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
             HandshakeError::Interrupted(_) => write!(f, "HandshakeError::Interrupted(...)"),
-            HandshakeError::Failure(ref e) => write!(f, "HandshakeError::Failure({:?})", e),
+            HandshakeError::Failure(ref e) => write!(f, "HandshakeError::Failure({e:?})"),
         }
     }
 }
@@ -73,7 +73,7 @@
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
             HandshakeError::Interrupted(_) => write!(f, "Interrupted handshake (WouldBlock)"),
-            HandshakeError::Failure(ref e) => write!(f, "{}", e),
+            HandshakeError::Failure(ref e) => write!(f, "{e}"),
         }
     }
 }
diff --git a/crates/tungstenite/src/handshake/server.rs b/crates/tungstenite/src/handshake/server.rs
index bc072ce..f0c82bb 100644
--- a/crates/tungstenite/src/handshake/server.rs
+++ b/crates/tungstenite/src/handshake/server.rs
@@ -86,10 +86,10 @@
 }
 
 /// Create a response for the request with a custom body.
-pub fn create_response_with_body<T>(
-    request: &HttpRequest<T>,
-    generate_body: impl FnOnce() -> T,
-) -> Result<HttpResponse<T>> {
+pub fn create_response_with_body<T1, T2>(
+    request: &HttpRequest<T1>,
+    generate_body: impl FnOnce() -> T2,
+) -> Result<HttpResponse<T2>> {
     Ok(create_parts(request)?.body(generate_body())?)
 }
 
diff --git a/crates/tungstenite/src/lib.rs b/crates/tungstenite/src/lib.rs
index 4fdf0a6..8c593cd 100644
--- a/crates/tungstenite/src/lib.rs
+++ b/crates/tungstenite/src/lib.rs
@@ -39,7 +39,7 @@
 
 #[cfg(feature = "handshake")]
 pub use crate::{
-    client::{client, connect},
+    client::{client, connect, ClientRequestBuilder},
     handshake::{client::ClientHandshake, server::ServerHandshake, HandshakeError},
     server::{accept, accept_hdr, accept_hdr_with_config, accept_with_config},
 };
diff --git a/crates/tungstenite/src/protocol/frame/coding.rs b/crates/tungstenite/src/protocol/frame/coding.rs
index 827b7ca..a1d56bb 100644
--- a/crates/tungstenite/src/protocol/frame/coding.rs
+++ b/crates/tungstenite/src/protocol/frame/coding.rs
@@ -46,7 +46,7 @@
             Data::Continue => write!(f, "CONTINUE"),
             Data::Text => write!(f, "TEXT"),
             Data::Binary => write!(f, "BINARY"),
-            Data::Reserved(x) => write!(f, "RESERVED_DATA_{}", x),
+            Data::Reserved(x) => write!(f, "RESERVED_DATA_{x}"),
         }
     }
 }
@@ -57,7 +57,7 @@
             Control::Close => write!(f, "CLOSE"),
             Control::Ping => write!(f, "PING"),
             Control::Pong => write!(f, "PONG"),
-            Control::Reserved(x) => write!(f, "RESERVED_CONTROL_{}", x),
+            Control::Reserved(x) => write!(f, "RESERVED_CONTROL_{x}"),
         }
     }
 }
@@ -197,7 +197,7 @@
 impl fmt::Display for CloseCode {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         let code: u16 = self.into();
-        write!(f, "{}", code)
+        write!(f, "{code}")
     }
 }
 
diff --git a/crates/tungstenite/src/protocol/frame/frame.rs b/crates/tungstenite/src/protocol/frame/frame.rs
index 6b797a9..e53df95 100644
--- a/crates/tungstenite/src/protocol/frame/frame.rs
+++ b/crates/tungstenite/src/protocol/frame/frame.rs
@@ -480,7 +480,7 @@
     #[test]
     fn display() {
         let f = Frame::message("hi there".into(), OpCode::Data(Data::Text), true);
-        let view = format!("{}", f);
+        let view = format!("{f}");
         assert!(view.contains("payload:"));
     }
 }
diff --git a/crates/tungstenite/src/protocol/message.rs b/crates/tungstenite/src/protocol/message.rs
index 2b2ed0b..9d408ba 100644
--- a/crates/tungstenite/src/protocol/message.rs
+++ b/crates/tungstenite/src/protocol/message.rs
@@ -316,7 +316,7 @@
 impl fmt::Display for Message {
     fn fmt(&self, f: &mut fmt::Formatter) -> StdResult<(), fmt::Error> {
         if let Ok(string) = self.to_text() {
-            write!(f, "{}", string)
+            write!(f, "{string}")
         } else {
             write!(f, "Binary Data<length={}>", self.len())
         }
diff --git a/pseudo_crate/Cargo.lock b/pseudo_crate/Cargo.lock
index 8b5def0..f6e4d51 100644
--- a/pseudo_crate/Cargo.lock
+++ b/pseudo_crate/Cargo.lock
@@ -5498,9 +5498,9 @@
 
 [[package]]
 name = "tungstenite"
-version = "0.21.0"
+version = "0.24.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1"
+checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a"
 dependencies = [
  "byteorder",
  "bytes",
@@ -5511,7 +5511,6 @@
  "rand",
  "sha1",
  "thiserror 1.0.49",
- "url",
  "utf-8",
 ]
 
diff --git a/pseudo_crate/Cargo.toml b/pseudo_crate/Cargo.toml
index 6484aad..5e11549 100644
--- a/pseudo_crate/Cargo.toml
+++ b/pseudo_crate/Cargo.toml
@@ -347,7 +347,7 @@
 tracing-core = "=0.1.32"
 tracing-subscriber = "=0.3.18"
 try-lock = "=0.2.5"
-tungstenite = "=0.21.0"
+tungstenite = "=0.24.0"
 twox-hash = "=1.6.3"
 ucd-trie = "=0.1.6"
 ucs2 = "=0.3.3"