async-tungstenite-0.28.0/.cargo_vcs_info.json0000644000000001360000000000100146070ustar { "git": { "sha1": "ce583237c11e42473933e60ecb207c4ded44eb70" }, "path_in_vcs": "" }async-tungstenite-0.28.0/CHANGELOG.md000064400000000000000000000216611046102023000152160ustar 00000000000000# Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [0.28.0] - 2024-09-04 ### Changed - Update to tungstenite 0.24. - Update to rustls-native-certs 0.8. - Update MRSV to 1.63. ## [0.27.0] - 2024-07-17 ### Changed - Update glib / gio dependencies to 0.20. ## [0.26.2] - 2024-06-17 ### Fixed - Work around bug related to `futures_task::ArcWake`, which causes busy looping because of spurious waker "changes" caused by creating the same waker with different vtables. ## [0.26.1] - 2024-06-06 ### Added - New `url` feature that maps to the corresponding feature from `tungstenite` and allows connecting directly to `ws` / `wss` URLs. ## [0.26.0] - 2024-06-02 ### Changed - Update to tungstenite 0.23. - Don't include default features for various dependencies. ## [0.25.1] - 2024-04-03 ### Fixed - Fix tokio support for async-tls. ## [0.25.0] - 2024-02-09 ### Changed - Update to glib/gio 0.19. - Update to async-tls 0.13. ## [0.24.0] - 2023-12-08 ### Changed - Update MSRV from 1.70 to 1.61. - Update to tungstenite 0.21. - Update to webpki-roots 0.26. - Update tokio-rustls to 0.25 and rustls-native-certs to 0.7. - Update example to hyper 1.0. ## [0.23.0] - 2023-08-08 ### Changed - Update to tungstenite 0.20. - Update to webpki-roots 0.25. - Update to glib/gio 0.18. - Update MSRV to 1.70. ### Fixed - Gracefully handle invalid native root certificates - Do not flush on every `poll_ready()` call. ## [0.22.2] - 2023-05-20 ### Added - New `tokio-rustls-manual-roots` feature for dropping the dependency on webpki-roots. ## [0.22.1] - 2023-05-08 ### Fixed - Fix `poll_flush` on a closed connection. ### Changed - Add MSRV to Cargo.toml and check it with the CI. ## [0.22.0] - 2023-04-27 ### Changed - Update to tokio-rustls 0.24 ## [0.21.0] - 2023-04-12 ### Changed - Update to tungstenite 0.19 - Update to async-native-tls 0.5 and webpki-roots 0.23 ### Changed - `gio::accept_async()` API for the gio integration similar to the existing API for tokio and async-std - Added an echo server example using gio ## [0.20.0] - 2023-02-10 ### Changed - Update to gio/glib 0.17. - Update to async-tls 0.12 and env-logger 0.10. ## [0.19.0] - 2022-12-11 ### Changed - Update to tungstenite 0.18 and make the "handshake" feature optional but enabled by default. ## [0.18.0] - 2022-10-24 ### Changed - Update to gio/glib 0.16. ## [0.17.2] - 2022-03-23 ### Fixed - The `Stream` implementation on `WebSocketStream` now implements `FusedStream` and will always return `None` after an error was returned or the stream was closed cleanly. - Fix autobahn testsuite. ## [0.17.1] - 2022-03-01 ### Fixed - Fix `poll_close` returning WouldBlock error kind. - Fix a couple of minor clippy warnings. ## [0.17.0] - 2022-02-17 ### Changed - Update to tungstenite 0.17. - Update to gio/glib 0.15. - Update to async-native-tls 0.4. ## [0.16.1] - 2021-12-06 ### Fixed - Fix connecting to URLs containing plain IPv6 addresses in brackets. ## [0.16.0] - 2021-11-06 ### Changed - Update to tungstenite 0.16, rusttls 0.20, tokio-rustls 0.23, etc. ## [0.15.0] - 2021-09-09 ### Fixed - Reduce crate package size. - Fix and clean up autobahn tests. ### Changed - Update to tungstenite 0.15. ## [0.14.0] - 2021-07-05 ### Changed - Remove `tokio-rustls` feature and replace with `tokio-rustls-webpki-roots` and `tokio-rustls-native-certs` features that allow selecting the certificate checking backend. - Add `verbose-logging` feature that enables more verbose logging via the `log` crate, which was enabled by default before. - Update `gio-runtime` feature to glib/gio 0.14. ### Added - Make `client_async_tls_with_connector_and_config()` a public function to allow creating a WebSocket connection from a `Stream`. ## [0.13.1] - 2021-03-23 ### Fixed - The connect API using the `tokio-openssl` TLS implementation was broken in previous versions as no TLS connection was established before trying to establish the WebSocket connection. As such, connections always failed. Technically this is a breaking change when using this feature but in practice this a) wouldn't have worked anyway and b) it's unlikely someone uses the API in a way that would stop compiling now. ## [0.13.0] - 2021-02-13 ### Changed - Updated to tungstenite 0.13 ## [0.12.0] - 2021-01-09 ### Changed - Updated tungstenite to version 0.12 - Migrated from pin-project to pin-project-lite - `TokioAdapter` is now created via `TokioAdapter::new` ## [0.11.0] - 2020-12-30 ### Changed - Updated tokio to version 1.0 - Updated async-tls to version 0.11 ## [0.10.0] - 2020-10-22 ### Changed - Updated tokio to version 0.3 ## [0.9.3] - 2020-10-19 ### Fixed - Configure the server trust anchors for tokio-rustls ## [0.9.2] - 2020-10-17 ### Added - Implemented the `tokio::client_async_tls*` functions for `async-tls` and `tokio-rustls` ### Changed - Updated pin-project to version 1 ## Older releases No changelog is available for older versions as of yet. [Unreleased]: https://github.com/sdroege/async-tungstenite/compare/0.27.0...HEAD [0.27.9]: https://github.com/sdroege/async-tungstenite/compare/0.27.0...0.26.2 [0.26.2]: https://github.com/sdroege/async-tungstenite/compare/0.26.2...0.26.1 [0.26.1]: https://github.com/sdroege/async-tungstenite/compare/0.26.1...0.26.0 [0.26.0]: https://github.com/sdroege/async-tungstenite/compare/0.26.0...0.25.1 [0.25.1]: https://github.com/sdroege/async-tungstenite/compare/0.25.1...0.25.0 [0.25.0]: https://github.com/sdroege/async-tungstenite/compare/0.25.0...0.24.0 [0.24.0]: https://github.com/sdroege/async-tungstenite/compare/0.24.0...0.23.0 [0.23.0]: https://github.com/sdroege/async-tungstenite/compare/0.23.0...0.22.2 [0.22.2]: https://github.com/sdroege/async-tungstenite/compare/0.22.2...0.22.1 [0.22.1]: https://github.com/sdroege/async-tungstenite/compare/0.22.1...0.22.0 [0.22.0]: https://github.com/sdroege/async-tungstenite/compare/0.22.0...0.21.0 [0.21.0]: https://github.com/sdroege/async-tungstenite/compare/0.21.0...0.20.0 [0.20.0]: https://github.com/sdroege/async-tungstenite/compare/0.20.0...0.19.0 [0.19.0]: https://github.com/sdroege/async-tungstenite/compare/0.19.0...0.18.0 [0.18.0]: https://github.com/sdroege/async-tungstenite/compare/0.18.0...0.17.2 [0.17.2]: https://github.com/sdroege/async-tungstenite/compare/0.17.2...0.17.1 [0.17.1]: https://github.com/sdroege/async-tungstenite/compare/0.17.1...0.17.0 [0.17.0]: https://github.com/sdroege/async-tungstenite/compare/0.17.0...0.16.1 [0.16.1]: https://github.com/sdroege/async-tungstenite/compare/0.16.1...0.16.0 [0.16.0]: https://github.com/sdroege/async-tungstenite/compare/0.16.0...0.15.0 [0.15.0]: https://github.com/sdroege/async-tungstenite/compare/0.15.0...0.14.0 [0.14.0]: https://github.com/sdroege/async-tungstenite/compare/0.14.0...0.13.1 [0.13.1]: https://github.com/sdroege/async-tungstenite/compare/0.13.1...0.13.0 [0.13.0]: https://github.com/sdroege/async-tungstenite/compare/0.13.0...0.12.0 [0.12.0]: https://github.com/sdroege/async-tungstenite/compare/0.12.0...0.11.0 [0.11.0]: https://github.com/sdroege/async-tungstenite/compare/0.11.0...0.10.0 [0.10.0]: https://github.com/sdroege/async-tungstenite/compare/0.10.0...0.9.3 [0.9.3]: https://github.com/sdroege/async-tungstenite/compare/0.9.3...0.9.2 [0.9.2]: https://github.com/sdroege/async-tungstenite/compare/0.9.2...0.9.1 async-tungstenite-0.28.0/Cargo.lock0000644000001600310000000000100125630ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "addr2line" version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" dependencies = [ "gimli", ] [[package]] name = "adler" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aho-corasick" version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] [[package]] name = "async-attributes" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" dependencies = [ "quote", "syn 1.0.109", ] [[package]] name = "async-channel" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" dependencies = [ "concurrent-queue", "event-listener 2.5.3", "futures-core", ] [[package]] name = "async-channel" version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" dependencies = [ "concurrent-queue", "event-listener-strategy", "futures-core", "pin-project-lite", ] [[package]] name = "async-executor" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7ebdfa2ebdab6b1760375fa7d6f382b9f486eac35fc994625a00e89280bdbb7" dependencies = [ "async-task", "concurrent-queue", "fastrand 2.1.1", "futures-lite 2.3.0", "slab", ] [[package]] name = "async-global-executor" version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" dependencies = [ "async-channel 2.3.1", "async-executor", "async-io 2.3.4", "async-lock 3.4.0", "blocking", "futures-lite 2.3.0", "once_cell", ] [[package]] name = "async-io" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" dependencies = [ "async-lock 2.8.0", "autocfg", "cfg-if", "concurrent-queue", "futures-lite 1.13.0", "log", "parking", "polling 2.8.0", "rustix 0.37.27", "slab", "socket2 0.4.10", "waker-fn", ] [[package]] name = "async-io" version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "444b0228950ee6501b3568d3c93bf1176a1fdbc3b758dcd9475046d30f4dc7e8" dependencies = [ "async-lock 3.4.0", "cfg-if", "concurrent-queue", "futures-io", "futures-lite 2.3.0", "parking", "polling 3.7.3", "rustix 0.38.35", "slab", "tracing", "windows-sys 0.59.0", ] [[package]] name = "async-lock" version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" dependencies = [ "event-listener 2.5.3", ] [[package]] name = "async-lock" version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" dependencies = [ "event-listener 5.3.1", "event-listener-strategy", "pin-project-lite", ] [[package]] name = "async-native-tls" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9343dc5acf07e79ff82d0c37899f079db3534d99f189a1837c8e549c99405bec" dependencies = [ "futures-util", "native-tls", "thiserror", "url", ] [[package]] name = "async-process" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea6438ba0a08d81529c69b36700fa2f95837bfe3e776ab39cde9c14d9149da88" dependencies = [ "async-io 1.13.0", "async-lock 2.8.0", "async-signal", "blocking", "cfg-if", "event-listener 3.1.0", "futures-lite 1.13.0", "rustix 0.38.35", "windows-sys 0.48.0", ] [[package]] name = "async-signal" version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3" dependencies = [ "async-io 2.3.4", "async-lock 3.4.0", "atomic-waker", "cfg-if", "futures-core", "futures-io", "rustix 0.38.35", "signal-hook-registry", "slab", "windows-sys 0.59.0", ] [[package]] name = "async-std" version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" dependencies = [ "async-attributes", "async-channel 1.9.0", "async-global-executor", "async-io 1.13.0", "async-lock 2.8.0", "async-process", "crossbeam-utils", "futures-channel", "futures-core", "futures-io", "futures-lite 1.13.0", "gloo-timers", "kv-log-macro", "log", "memchr", "once_cell", "pin-project-lite", "pin-utils", "slab", "wasm-bindgen-futures", ] [[package]] name = "async-task" version = "4.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "async-tls" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2ae3c9eba89d472a0e4fe1dea433df78fbbe63d2b764addaf2ba3a6bde89a5e" dependencies = [ "futures-core", "futures-io", "rustls 0.21.12", "rustls-pemfile 1.0.4", "webpki-roots 0.22.6", ] [[package]] name = "async-tungstenite" version = "0.28.0" dependencies = [ "async-native-tls", "async-std", "async-tls", "env_logger", "futures", "futures-channel", "futures-io", "futures-util", "gio", "glib", "http-body-util", "hyper", "hyper-util", "log", "native-tls", "openssl", "pin-project-lite", "rustls-native-certs", "rustls-pki-types", "tokio", "tokio-native-tls", "tokio-openssl", "tokio-rustls", "tungstenite", "url", "webpki-roots 0.26.5", ] [[package]] name = "atomic-waker" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "backtrace" version = "0.3.73" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" dependencies = [ "addr2line", "cc", "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", ] [[package]] name = "base64" version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "base64" version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "block-buffer" version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ "generic-array", ] [[package]] name = "blocking" version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" dependencies = [ "async-channel 2.3.1", "async-task", "futures-io", "futures-lite 2.3.0", "piper", ] [[package]] name = "bumpalo" version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "byteorder" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" [[package]] name = "cc" version = "1.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57b6a275aa2903740dc87da01c62040406b8812552e97129a63ea8850a17c6e6" dependencies = [ "shlex", ] [[package]] name = "cfg-expr" version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "345c78335be0624ed29012dc10c49102196c6882c12dde65d9f35b02da2aada8" dependencies = [ "smallvec", "target-lexicon", ] [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "concurrent-queue" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" dependencies = [ "crossbeam-utils", ] [[package]] name = "core-foundation" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ "core-foundation-sys", "libc", ] [[package]] name = "core-foundation-sys" version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" dependencies = [ "libc", ] [[package]] name = "crossbeam-utils" version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crypto-common" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", "typenum", ] [[package]] name = "data-encoding" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" [[package]] name = "digest" version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "crypto-common", ] [[package]] name = "env_logger" version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" dependencies = [ "humantime", "is-terminal", "log", "regex", "termcolor", ] [[package]] name = "equivalent" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ "libc", "windows-sys 0.52.0", ] [[package]] name = "event-listener" version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "event-listener" version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d93877bcde0eb80ca09131a08d23f0a5c18a620b01db137dba666d18cd9b30c2" dependencies = [ "concurrent-queue", "parking", "pin-project-lite", ] [[package]] name = "event-listener" version = "5.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" dependencies = [ "concurrent-queue", "parking", "pin-project-lite", ] [[package]] name = "event-listener-strategy" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" dependencies = [ "event-listener 5.3.1", "pin-project-lite", ] [[package]] name = "fastrand" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" dependencies = [ "instant", ] [[package]] name = "fastrand" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "foreign-types" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" dependencies = [ "foreign-types-shared", ] [[package]] name = "foreign-types-shared" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] [[package]] name = "futures" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" dependencies = [ "futures-channel", "futures-core", "futures-executor", "futures-io", "futures-sink", "futures-task", "futures-util", ] [[package]] name = "futures-channel" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" dependencies = [ "futures-core", "futures-sink", ] [[package]] name = "futures-core" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" [[package]] name = "futures-executor" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" dependencies = [ "futures-core", "futures-task", "futures-util", ] [[package]] name = "futures-io" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" [[package]] name = "futures-lite" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" dependencies = [ "fastrand 1.9.0", "futures-core", "futures-io", "memchr", "parking", "pin-project-lite", "waker-fn", ] [[package]] name = "futures-lite" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" dependencies = [ "fastrand 2.1.1", "futures-core", "futures-io", "parking", "pin-project-lite", ] [[package]] name = "futures-macro" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", "syn 2.0.77", ] [[package]] name = "futures-sink" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" [[package]] name = "futures-task" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-util" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-channel", "futures-core", "futures-io", "futures-macro", "futures-sink", "futures-task", "memchr", "pin-project-lite", "pin-utils", "slab", ] [[package]] name = "generic-array" version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", ] [[package]] name = "getrandom" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", "wasi", ] [[package]] name = "gimli" version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" [[package]] name = "gio" version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcacaa37401cad0a95aadd266bc39c72a131d454fc012f6dfd217f891d76cc52" dependencies = [ "futures-channel", "futures-core", "futures-io", "futures-util", "gio-sys", "glib", "libc", "pin-project-lite", "smallvec", ] [[package]] name = "gio-sys" version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5237611e97e9b86ab5768adc3eef853ae713ea797aa3835404acdfacffc9fb38" dependencies = [ "glib-sys", "gobject-sys", "libc", "system-deps", "windows-sys 0.52.0", ] [[package]] name = "glib" version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c1ea829497810f8e87f5ee6d05c4879af641704add879e6b6080607cceeefe4" dependencies = [ "bitflags 2.6.0", "futures-channel", "futures-core", "futures-executor", "futures-task", "futures-util", "gio-sys", "glib-macros", "glib-sys", "gobject-sys", "libc", "memchr", "smallvec", ] [[package]] name = "glib-macros" version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "951aa19c5e89555c0ca5e94ee874b24b2594ece8412b387bd84ee3266b8a3ea0" dependencies = [ "heck", "proc-macro-crate", "proc-macro2", "quote", "syn 2.0.77", ] [[package]] name = "glib-sys" version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92eee4531c1c9abba945d19378b205031b5890e1f99c319ba0503b6e0c06a163" dependencies = [ "libc", "system-deps", ] [[package]] name = "gloo-timers" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" dependencies = [ "futures-channel", "futures-core", "js-sys", "wasm-bindgen", ] [[package]] name = "gobject-sys" version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa3d1dcd8a1eb2e7c22be3d5e792b14b186f3524f79b25631730f9a8c169d49a" dependencies = [ "glib-sys", "libc", "system-deps", ] [[package]] name = "hashbrown" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "heck" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "hermit-abi" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" [[package]] name = "http" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" dependencies = [ "bytes", "fnv", "itoa", ] [[package]] name = "http-body" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", "http", ] [[package]] name = "http-body-util" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", "futures-util", "http", "http-body", "pin-project-lite", ] [[package]] name = "httparse" version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" [[package]] name = "httpdate" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "humantime" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" dependencies = [ "bytes", "futures-channel", "futures-util", "http", "http-body", "httparse", "httpdate", "itoa", "pin-project-lite", "smallvec", "tokio", ] [[package]] name = "hyper-util" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" dependencies = [ "bytes", "futures-util", "http", "http-body", "hyper", "pin-project-lite", "tokio", ] [[package]] name = "idna" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", ] [[package]] name = "indexmap" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" dependencies = [ "equivalent", "hashbrown", ] [[package]] name = "instant" version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" dependencies = [ "cfg-if", ] [[package]] name = "io-lifetimes" version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ "hermit-abi 0.3.9", "libc", "windows-sys 0.48.0", ] [[package]] name = "is-terminal" version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" dependencies = [ "hermit-abi 0.4.0", "libc", "windows-sys 0.52.0", ] [[package]] name = "itoa" version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "js-sys" version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" dependencies = [ "wasm-bindgen", ] [[package]] name = "kv-log-macro" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" dependencies = [ "log", ] [[package]] name = "libc" version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" [[package]] name = "linux-raw-sys" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "linux-raw-sys" version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "lock_api" version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", ] [[package]] name = "log" version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" dependencies = [ "value-bag", ] [[package]] name = "memchr" version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "miniz_oxide" version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" dependencies = [ "adler", ] [[package]] name = "mio" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ "hermit-abi 0.3.9", "libc", "wasi", "windows-sys 0.52.0", ] [[package]] name = "native-tls" version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" dependencies = [ "libc", "log", "openssl", "openssl-probe", "openssl-sys", "schannel", "security-framework", "security-framework-sys", "tempfile", ] [[package]] name = "object" version = "0.36.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" dependencies = [ "memchr", ] [[package]] name = "once_cell" version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "openssl" version = "0.10.66" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" dependencies = [ "bitflags 2.6.0", "cfg-if", "foreign-types", "libc", "once_cell", "openssl-macros", "openssl-sys", ] [[package]] name = "openssl-macros" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", "syn 2.0.77", ] [[package]] name = "openssl-probe" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" version = "0.9.103" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" dependencies = [ "cc", "libc", "pkg-config", "vcpkg", ] [[package]] name = "parking" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" [[package]] name = "parking_lot" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", ] [[package]] name = "parking_lot_core" version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", "windows-targets 0.52.6", ] [[package]] name = "percent-encoding" version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pin-project-lite" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "piper" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" dependencies = [ "atomic-waker", "fastrand 2.1.1", "futures-io", ] [[package]] name = "pkg-config" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "polling" version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" dependencies = [ "autocfg", "bitflags 1.3.2", "cfg-if", "concurrent-queue", "libc", "log", "pin-project-lite", "windows-sys 0.48.0", ] [[package]] name = "polling" version = "3.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc2790cd301dec6cd3b7a025e4815cf825724a51c98dccfe6a3e55f05ffb6511" dependencies = [ "cfg-if", "concurrent-queue", "hermit-abi 0.4.0", "pin-project-lite", "rustix 0.38.35", "tracing", "windows-sys 0.59.0", ] [[package]] name = "ppv-lite86" version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" dependencies = [ "zerocopy", ] [[package]] name = "proc-macro-crate" version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ "toml_edit", ] [[package]] name = "proc-macro2" version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] [[package]] name = "rand" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", "rand_core", ] [[package]] name = "rand_chacha" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", "rand_core", ] [[package]] name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ "getrandom", ] [[package]] name = "redox_syscall" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" dependencies = [ "bitflags 2.6.0", ] [[package]] name = "regex" version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", "regex-automata", "regex-syntax", ] [[package]] name = "regex-automata" version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", "regex-syntax", ] [[package]] name = "regex-syntax" version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "ring" version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", "cfg-if", "getrandom", "libc", "spin", "untrusted", "windows-sys 0.52.0", ] [[package]] name = "rustc-demangle" version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustix" version = "0.37.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" dependencies = [ "bitflags 1.3.2", "errno", "io-lifetimes", "libc", "linux-raw-sys 0.3.8", "windows-sys 0.48.0", ] [[package]] name = "rustix" version = "0.38.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a85d50532239da68e9addb745ba38ff4612a242c1c7ceea689c4bc7c2f43c36f" dependencies = [ "bitflags 2.6.0", "errno", "libc", "linux-raw-sys 0.4.14", "windows-sys 0.52.0", ] [[package]] name = "rustls" version = "0.21.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", "ring", "rustls-webpki 0.101.7", "sct", ] [[package]] name = "rustls" version = "0.23.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044" dependencies = [ "once_cell", "rustls-pki-types", "rustls-webpki 0.102.7", "subtle", "zeroize", ] [[package]] name = "rustls-native-certs" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcaf18a4f2be7326cd874a5fa579fae794320a0f388d365dca7e480e55f83f8a" dependencies = [ "openssl-probe", "rustls-pemfile 2.1.3", "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" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" dependencies = [ "base64 0.22.1", "rustls-pki-types", ] [[package]] name = "rustls-pki-types" version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" [[package]] name = "rustls-webpki" version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ "ring", "untrusted", ] [[package]] name = "rustls-webpki" version = "0.102.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84678086bd54edf2b415183ed7a94d0efb049f1b646a33e22a36f3794be6ae56" dependencies = [ "ring", "rustls-pki-types", "untrusted", ] [[package]] name = "schannel" version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" dependencies = [ "windows-sys 0.52.0", ] [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sct" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ "ring", "untrusted", ] [[package]] name = "security-framework" version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ "bitflags 2.6.0", "core-foundation", "core-foundation-sys", "libc", "security-framework-sys", ] [[package]] name = "security-framework-sys" version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf" dependencies = [ "core-foundation-sys", "libc", ] [[package]] name = "serde" version = "1.0.209" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.209" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170" dependencies = [ "proc-macro2", "quote", "syn 2.0.77", ] [[package]] name = "serde_spanned" version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" dependencies = [ "serde", ] [[package]] name = "sha1" version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", "cpufeatures", "digest", ] [[package]] name = "shlex" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" dependencies = [ "libc", ] [[package]] name = "slab" version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] [[package]] name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" dependencies = [ "libc", "winapi", ] [[package]] name = "socket2" version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" dependencies = [ "libc", "windows-sys 0.52.0", ] [[package]] name = "spin" version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" [[package]] name = "subtle" version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "syn" version = "2.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "system-deps" version = "7.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "070a0a5e7da2d24be457809c4b3baa57a835fd2829ad8b86f9a049052fe71031" dependencies = [ "cfg-expr", "heck", "pkg-config", "toml", "version-compare", ] [[package]] name = "target-lexicon" version = "0.12.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tempfile" version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" dependencies = [ "cfg-if", "fastrand 2.1.1", "once_cell", "rustix 0.38.35", "windows-sys 0.59.0", ] [[package]] name = "termcolor" version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] [[package]] name = "thiserror" version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", "syn 2.0.77", ] [[package]] name = "tinyvec" version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" dependencies = [ "tinyvec_macros", ] [[package]] name = "tinyvec_macros" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" dependencies = [ "backtrace", "bytes", "libc", "mio", "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2 0.5.7", "tokio-macros", "windows-sys 0.52.0", ] [[package]] name = "tokio-macros" version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", "syn 2.0.77", ] [[package]] name = "tokio-native-tls" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" dependencies = [ "native-tls", "tokio", ] [[package]] name = "tokio-openssl" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ffab79df67727f6acf57f1ff743091873c24c579b1e2ce4d8f53e47ded4d63d" dependencies = [ "futures-util", "openssl", "openssl-sys", "tokio", ] [[package]] name = "tokio-rustls" version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ "rustls 0.23.12", "rustls-pki-types", "tokio", ] [[package]] name = "toml" version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" dependencies = [ "serde", "serde_spanned", "toml_datetime", "toml_edit", ] [[package]] name = "toml_datetime" version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" dependencies = [ "serde", ] [[package]] name = "toml_edit" version = "0.22.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" dependencies = [ "indexmap", "serde", "serde_spanned", "toml_datetime", "winnow", ] [[package]] name = "tracing" version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ "pin-project-lite", "tracing-core", ] [[package]] name = "tracing-core" version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" [[package]] name = "tungstenite" version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a" dependencies = [ "byteorder", "bytes", "data-encoding", "http", "httparse", "log", "native-tls", "rand", "rustls 0.23.12", "rustls-pki-types", "sha1", "thiserror", "url", "utf-8", ] [[package]] name = "typenum" version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicode-bidi" version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" dependencies = [ "tinyvec", ] [[package]] name = "untrusted" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" dependencies = [ "form_urlencoded", "idna", "percent-encoding", ] [[package]] name = "utf-8" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" [[package]] name = "value-bag" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a84c137d37ab0142f0f2ddfe332651fdbf252e7b7dbb4e67b6c1f1b2e925101" [[package]] name = "vcpkg" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version-compare" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" [[package]] name = "version_check" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "waker-fn" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" dependencies = [ "cfg-if", "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", "syn 2.0.77", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" dependencies = [ "cfg-if", "js-sys", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" dependencies = [ "quote", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", "syn 2.0.77", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] name = "web-sys" version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" dependencies = [ "js-sys", "wasm-bindgen", ] [[package]] name = "webpki" version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed63aea5ce73d0ff405984102c42de94fc55a6b75765d621c65262469b3c9b53" dependencies = [ "ring", "untrusted", ] [[package]] name = "webpki-roots" version = "0.22.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" dependencies = [ "webpki", ] [[package]] name = "webpki-roots" version = "0.26.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bd24728e5af82c6c4ec1b66ac4844bdf8156257fccda846ec58b42cd0cdbe6a" dependencies = [ "rustls-pki-types", ] [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ "windows-sys 0.59.0", ] [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[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", ] [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ "windows-targets 0.52.6", ] [[package]] name = "windows-sys" 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", ] [[package]] name = "windows-targets" 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_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", ] [[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" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" 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" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" dependencies = [ "memchr", ] [[package]] name = "zerocopy" version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", "syn 2.0.77", ] [[package]] name = "zeroize" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" async-tungstenite-0.28.0/Cargo.toml0000644000000135650000000000100126170ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" rust-version = "1.63" name = "async-tungstenite" version = "0.28.0" authors = ["Sebastian Dröge "] build = false include = [ "examples/**/*", "src/**/*", "LICENSE", "README.md", "CHANGELOG.md", ] autobins = false autoexamples = false autotests = false autobenches = false description = "Async binding for Tungstenite, the Lightweight stream-based WebSocket implementation" homepage = "https://github.com/sdroege/async-tungstenite" documentation = "https://docs.rs/async-tungstenite" readme = "README.md" keywords = [ "websocket", "io", "web", "tokio", "async-std", ] categories = [ "web-programming::websocket", "network-programming", "asynchronous", "concurrency", ] license = "MIT" repository = "https://github.com/sdroege/async-tungstenite" [package.metadata.docs.rs] features = [ "async-std-runtime", "tokio-runtime", "gio-runtime", "async-tls", "async-native-tls", "tokio-native-tls", ] [lib] name = "async_tungstenite" path = "src/lib.rs" [[example]] name = "async-std-echo" path = "examples/async-std-echo.rs" required-features = ["async-std-runtime"] [[example]] name = "autobahn-client" path = "examples/autobahn-client.rs" required-features = ["async-std-runtime"] [[example]] name = "autobahn-server" path = "examples/autobahn-server.rs" required-features = ["async-std-runtime"] [[example]] name = "client" path = "examples/client.rs" required-features = ["async-std-runtime"] [[example]] name = "echo-server" path = "examples/echo-server.rs" required-features = ["async-std-runtime"] [[example]] name = "gio-echo" path = "examples/gio-echo.rs" required-features = ["gio-runtime"] [[example]] name = "gio-echo-server" path = "examples/gio-echo-server.rs" required-features = ["gio-runtime"] [[example]] name = "interval-server" path = "examples/interval-server.rs" required-features = ["async-std-runtime"] [[example]] name = "server" path = "examples/server.rs" required-features = ["async-std-runtime"] [[example]] name = "server-custom-accept" path = "examples/server-custom-accept.rs" required-features = ["tokio-runtime"] [[example]] name = "server-headers" path = "examples/server-headers.rs" required-features = [ "async-std-runtime", "handshake", ] [[example]] name = "tokio-echo" path = "examples/tokio-echo.rs" required-features = ["tokio-runtime"] [dependencies.async-std] version = "1.0" optional = true [dependencies.futures-io] version = "0.3" features = ["std"] default-features = false [dependencies.futures-util] version = "0.3" features = [ "sink", "std", ] default-features = false [dependencies.gio] version = "0.20" optional = true [dependencies.glib] version = "0.20" optional = true [dependencies.log] version = "0.4" [dependencies.openssl] version = "0.10" optional = true [dependencies.pin-project-lite] version = "0.2" [dependencies.real-async-native-tls] version = "0.5.0" optional = true package = "async-native-tls" [dependencies.real-async-tls] version = "0.13" features = ["client"] optional = true default-features = false package = "async-tls" [dependencies.real-native-tls] version = "0.2" optional = true package = "native-tls" [dependencies.real-tokio-native-tls] version = "0.3" optional = true package = "tokio-native-tls" [dependencies.real-tokio-openssl] version = "0.6" optional = true package = "tokio-openssl" [dependencies.real-tokio-rustls] version = "0.26" optional = true default-features = false package = "tokio-rustls" [dependencies.rustls-native-certs] version = "0.8" optional = true [dependencies.rustls-pki-types] version = "1.0.1" optional = true [dependencies.tokio] version = "1.0" features = ["net"] optional = true default-features = false [dependencies.tungstenite] version = "0.24" default-features = false [dependencies.webpki-roots] version = "0.26" optional = true [dev-dependencies.async-std] version = "1.0" features = [ "attributes", "unstable", ] [dev-dependencies.env_logger] version = "0.10" [dev-dependencies.futures] version = "0.3" [dev-dependencies.futures-channel] version = "0.3" [dev-dependencies.http-body-util] version = "0.1" [dev-dependencies.hyper] version = "1.0" features = [ "http1", "server", ] default-features = false [dev-dependencies.hyper-util] version = "0.1" features = ["tokio"] [dev-dependencies.tokio] version = "1.0" features = ["full"] [dev-dependencies.tungstenite] version = "0.24" features = ["url"] [dev-dependencies.url] version = "2.0.0" [features] __rustls-tls = [ "tokio-runtime", "real-tokio-rustls", "rustls-pki-types", "tungstenite/__rustls-tls", ] async-native-tls = [ "async-std-runtime", "real-async-native-tls", "tungstenite/native-tls", ] async-std-runtime = [ "async-std", "handshake", ] async-tls = [ "real-async-tls", "handshake", ] default = ["handshake"] gio-runtime = [ "gio", "glib", "handshake", ] handshake = ["tungstenite/handshake"] tokio-native-tls = [ "tokio-runtime", "real-tokio-native-tls", "real-native-tls", "tungstenite/native-tls", ] tokio-openssl = [ "tokio-runtime", "real-tokio-openssl", "openssl", ] tokio-runtime = [ "tokio", "handshake", ] tokio-rustls-manual-roots = ["__rustls-tls"] tokio-rustls-native-certs = [ "__rustls-tls", "rustls-native-certs", ] tokio-rustls-webpki-roots = [ "__rustls-tls", "webpki-roots", ] url = ["tungstenite/url"] verbose-logging = [] async-tungstenite-0.28.0/Cargo.toml.orig000064400000000000000000000106111046102023000162650ustar 00000000000000[package] name = "async-tungstenite" description = "Async binding for Tungstenite, the Lightweight stream-based WebSocket implementation" categories = ["web-programming::websocket", "network-programming", "asynchronous", "concurrency"] keywords = ["websocket", "io", "web", "tokio", "async-std"] authors = ["Sebastian Dröge "] license = "MIT" homepage = "https://github.com/sdroege/async-tungstenite" repository = "https://github.com/sdroege/async-tungstenite" documentation = "https://docs.rs/async-tungstenite" version = "0.28.0" edition = "2018" readme = "README.md" include = ["examples/**/*", "src/**/*", "LICENSE", "README.md", "CHANGELOG.md"] rust-version = "1.63" [features] default = ["handshake"] handshake = ["tungstenite/handshake"] async-std-runtime = ["async-std", "handshake"] tokio-runtime = ["tokio", "handshake"] gio-runtime = ["gio", "glib", "handshake"] async-tls = ["real-async-tls", "handshake"] async-native-tls = ["async-std-runtime", "real-async-native-tls", "tungstenite/native-tls"] tokio-native-tls = ["tokio-runtime", "real-tokio-native-tls", "real-native-tls", "tungstenite/native-tls"] tokio-rustls-manual-roots = ["__rustls-tls"] tokio-rustls-webpki-roots = ["__rustls-tls", "webpki-roots"] tokio-rustls-native-certs = ["__rustls-tls", "rustls-native-certs"] tokio-openssl = ["tokio-runtime", "real-tokio-openssl", "openssl"] verbose-logging = [] url = ["tungstenite/url"] __rustls-tls = ["tokio-runtime", "real-tokio-rustls", "rustls-pki-types", "tungstenite/__rustls-tls"] [package.metadata.docs.rs] features = ["async-std-runtime", "tokio-runtime", "gio-runtime", "async-tls", "async-native-tls", "tokio-native-tls"] [dependencies] log = "0.4" futures-util = { version = "0.3", default-features = false, features = ["sink", "std"] } futures-io = { version = "0.3", default-features = false, features = ["std"] } pin-project-lite = "0.2" [dependencies.tungstenite] version = "0.24" default-features = false [dependencies.async-std] optional = true version = "1.0" [dependencies.real-tokio-openssl] optional = true version = "0.6" package = "tokio-openssl" [dependencies.openssl] optional = true version = "0.10" [dependencies.real-async-tls] optional = true version = "0.13" package = "async-tls" default-features = false features = ["client"] [dependencies.real-async-native-tls] optional = true version = "0.5.0" package = "async-native-tls" [dependencies.real-native-tls] optional = true version = "0.2" package = "native-tls" [dependencies.tokio] optional = true version = "1.0" features = ["net"] default-features = false [dependencies.real-tokio-native-tls] optional = true version = "0.3" package = "tokio-native-tls" [dependencies.real-tokio-rustls] optional = true version = "0.26" package = "tokio-rustls" default-features = false [dependencies.rustls-pki-types] optional = true version = "1.0.1" [dependencies.rustls-native-certs] optional = true version = "0.8" [dependencies.webpki-roots] optional = true version = "0.26" [dependencies.gio] optional = true version = "0.20" [dependencies.glib] optional = true version = "0.20" [dev-dependencies] futures = "0.3" url = "2.0.0" env_logger = "0.10" async-std = { version = "1.0", features = ["attributes", "unstable"] } tokio = { version = "1.0", features = ["full"] } futures-channel = "0.3" hyper = { version = "1.0", default-features = false, features = ["http1", "server"] } hyper-util = { version = "0.1", features = ["tokio"] } http-body-util = "0.1" [dev-dependencies.tungstenite] version = "0.24" features = ["url"] [[example]] name = "autobahn-client" required-features = ["async-std-runtime"] [[example]] name = "async-std-echo" required-features = ["async-std-runtime"] [[example]] name = "client" required-features = ["async-std-runtime"] [[example]] name = "autobahn-server" required-features = ["async-std-runtime"] [[example]] name = "server" required-features = ["async-std-runtime"] [[example]] name = "echo-server" required-features = ["async-std-runtime"] [[example]] name = "server-headers" required-features = ["async-std-runtime", "handshake"] [[example]] name = "interval-server" required-features = ["async-std-runtime"] [[example]] name = "gio-echo" required-features = ["gio-runtime"] [[example]] name = "gio-echo-server" required-features = ["gio-runtime"] [[example]] name = "tokio-echo" required-features = ["tokio-runtime"] [[example]] name = "server-custom-accept" required-features = ["tokio-runtime"] async-tungstenite-0.28.0/LICENSE000064400000000000000000000021511046102023000144030ustar 00000000000000Copyright (c) 2017 Daniel Abramov Copyright (c) 2017 Alexey Galakhov Copyright (c) 2019 Sebastian Dröge Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. async-tungstenite-0.28.0/README.md000064400000000000000000000115331046102023000146610ustar 00000000000000# async-tungstenite Asynchronous WebSockets for [async-std](https://async.rs), [tokio](https://tokio.rs), [gio](https://gtk-rs.org) and any `std` `Future`s runtime. [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE) [![Crates.io](https://img.shields.io/crates/v/async-tungstenite.svg?maxAge=2592000)](https://crates.io/crates/async-tungstenite) [![Build Status](https://github.com/sdroege/async-tungstenite/workflows/CI/badge.svg)](https://github.com/sdroege/async-tungstenite/actions?query=workflow%3ACI) [Documentation](https://docs.rs/async-tungstenite) ## Usage Add this in your `Cargo.toml`: ```toml [dependencies] async-tungstenite = "*" ``` Take a look at the `examples/` directory for client and server examples. You may also want to get familiar with [async-std](https://async.rs/) or [tokio](https://tokio.rs) if you don't have any experience with it. ## What is async-tungstenite? This crate is based on [tungstenite](https://crates.io/crates/tungstenite) Rust WebSocket library and provides async bindings and wrappers for it, so you can use it with non-blocking/asynchronous `TcpStream`s from and couple it together with other crates from the async stack. In addition, optional integration with various other crates can be enabled via feature flags * `async-tls`: Enables the `async_tls` module, which provides integration with the [async-tls](https://crates.io/crates/async-tls) TLS stack and can be used independent of any async runtime. * `async-std-runtime`: Enables the `async_std` module, which provides integration with the [async-std](https://async.rs) runtime. * `async-native-tls`: Enables the additional functions in the `async_std` module to implement TLS via [async-native-tls](https://crates.io/crates/async-native-tls). * `tokio-runtime`: Enables the `tokio` module, which provides integration with the [tokio](https://tokio.rs) runtime. * `tokio-native-tls`: Enables the additional functions in the `tokio` module to implement TLS via [tokio-native-tls](https://crates.io/crates/tokio-native-tls). * `tokio-rustls-native-certs`: Enables the additional functions in the `tokio` module to implement TLS via [tokio-rustls](https://crates.io/crates/tokio-rustls) and uses native system certificates found with [rustls-native-certs](https://github.com/rustls/rustls-native-certs). * `tokio-rustls-webpki-roots`: Enables the additional functions in the `tokio` module to implement TLS via [tokio-rustls](https://crates.io/crates/tokio-rustls) and uses the certificates [webpki-roots](https://github.com/rustls/webpki-roots) provides. * `gio-runtime`: Enables the `gio` module, which provides integration with the [gio](https://gtk-rs.org) runtime. ## Messages vs Streaming WebSocket provides a message-oriented protocol, and this crate supports sending and receiving data in messages; protocols built on WebSocket are allowed to make message boundaries semantically significant. However, some users of WebSocket may want to treat the socket as a continuous stream of bytes. If you know the sending end does not place significance on message boundaries, and you want to process a stream of bytes without regard to those boundaries, try [`ws_stream_tungstenite`](https://crates.io/crates/ws_stream_tungstenite), which builds upon this crate. ## Is it performant? In essence, `async-tungstenite` is a wrapper for `tungstenite`, so the performance is capped by the performance of `tungstenite`. `tungstenite` has a decent performance (it has been used in production for real-time communication software, video conferencing, etc), but it's definitely not the fastest WebSocket library in the world at the moment of writing this note. If performance is of a paramount importance for you (especially if you send **large messages**), then you might want to check other libraries that have been designed to be performant or you could file a PR against `tungstenite` to improve the performance! We are aware of changes that both `tungstenite` and `async-tungstenite` need in order to fill the gap of ~30% performance difference between `tungstenite` and more performant libraries like `fastwebsockets`, but we have not worked on that yet as it was not required for the use case that original authors designed the library for. In the course of past years we have merged several performance improvements submitted by the awesome community of Rust users who helped to improve the library! For a quick summary of the pending performance problems/improvements, see [the comment](https://github.com/snapview/tungstenite-rs/issues/352#issuecomment-1537488614). ## tokio-tungstenite Originally this crate was created as a fork of [tokio-tungstenite](https://github.com/snapview/tokio-tungstenite) and ported to the traits of the [`futures`](https://crates.io/crates/futures) crate. Integration into async-std, tokio and gio was added on top of that. async-tungstenite-0.28.0/examples/README.md000064400000000000000000000013111046102023000164700ustar 00000000000000Examples * [autobahn-client.rs](https://github.com/sdroege/async-tungstenite/blob/main/examples/autobahn-client.rs) * [autobahn-server.rs](https://github.com/sdroege/async-tungstenite/blob/main/examples/autobahn-server.rs) * [client.rs](https://github.com/sdroege/async-tungstenite/blob/main/examples/client.rs) * [echo-server.rs](https://github.com/sdroege/async-tungstenite/blob/main/examples/echo-server.rs) * [server.rs](https://github.com/sdroege/async-tungstenite/blob/main/examples/server.rs) * [server-headers.rs](https://github.com/sdroege/async-tungstenite/blob/main/examples/server-headers.rs) * [interval-server.rs](https://github.com/sdroege/async-tungstenite/blob/main/examples/interval-server.rs) async-tungstenite-0.28.0/examples/async-std-echo.rs000064400000000000000000000016771046102023000204170ustar 00000000000000use async_tungstenite::{async_std::connect_async, tungstenite::Message}; use futures::prelude::*; use async_std::task; async fn run() -> Result<(), Box> { #[cfg(any(feature = "async-tls", feature = "async-native-tls"))] let url = "wss://echo.websocket.events/.ws"; #[cfg(not(any(feature = "async-tls", feature = "async-native-tls")))] let url = "ws://echo.websocket.events/.ws"; println!("Connecting: \"{}\"", url); let (mut ws_stream, _) = connect_async(url).await?; let msg = ws_stream.next().await.ok_or("didn't receive anything")??; println!("Received: {:?}", msg); let text = "Hello, World!"; println!("Sending: \"{}\"", text); ws_stream.send(Message::text(text)).await?; let msg = ws_stream.next().await.ok_or("didn't receive anything")??; println!("Received: {:?}", msg); Ok(()) } fn main() -> Result<(), Box> { task::block_on(run()) } async-tungstenite-0.28.0/examples/autobahn-client.rs000064400000000000000000000031661046102023000206460ustar 00000000000000use async_tungstenite::{async_std::connect_async, tungstenite::Error, tungstenite::Result}; use futures::prelude::*; use log::*; const AGENT: &str = "Tungstenite"; async fn get_case_count() -> Result { let (mut socket, _) = connect_async("ws://localhost:9001/getCaseCount").await?; let msg = socket.next().await.expect("Can't fetch case count")?; socket.close(None).await?; Ok(msg .into_text()? .parse::() .expect("Can't parse case count")) } async fn update_reports() -> Result<()> { let (mut socket, _) = connect_async(&format!( "ws://localhost:9001/updateReports?agent={}", AGENT )) .await?; socket.close(None).await?; Ok(()) } async fn run_test(case: u32) -> Result<()> { info!("Running test case {}", case); let case_url = &format!("ws://localhost:9001/runCase?case={}&agent={}", case, AGENT); let (mut ws_stream, _) = connect_async(case_url).await?; while let Some(msg) = ws_stream.next().await { let msg = msg?; if msg.is_text() || msg.is_binary() { ws_stream.send(msg).await?; } } Ok(()) } async fn run() { env_logger::init(); let total = get_case_count().await.expect("Error getting case count"); for case in 1..=total { if let Err(e) = run_test(case).await { match e { Error::ConnectionClosed | Error::Protocol(_) | Error::Utf8 => (), err => error!("Testcase failed: {}", err), } } } update_reports().await.expect("Error updating reports"); } fn main() { async_std::task::block_on(run()); } async-tungstenite-0.28.0/examples/autobahn-server.rs000064400000000000000000000026131046102023000206720ustar 00000000000000use async_std::net::{SocketAddr, TcpListener, TcpStream}; use async_tungstenite::{ accept_async, tungstenite::{Error, Result}, }; use futures::prelude::*; use log::*; async fn accept_connection(peer: SocketAddr, stream: TcpStream) { if let Err(e) = handle_connection(peer, stream).await { match e { Error::ConnectionClosed | Error::Protocol(_) | Error::Utf8 => (), err => error!("Error processing connection: {}", err), } } } async fn handle_connection(peer: SocketAddr, stream: TcpStream) -> Result<()> { let mut ws_stream = accept_async(stream).await.expect("Failed to accept"); info!("New WebSocket connection: {}", peer); while let Some(msg) = ws_stream.next().await { let msg = msg?; if msg.is_text() || msg.is_binary() { ws_stream.send(msg).await?; } } Ok(()) } async fn run() { env_logger::init(); let addr = "127.0.0.1:9002"; let listener = TcpListener::bind(&addr).await.expect("Can't listen"); info!("Listening on: {}", addr); while let Ok((stream, _)) = listener.accept().await { let peer = stream .peer_addr() .expect("connected streams should have a peer address"); info!("Peer address: {}", peer); async_std::task::spawn(accept_connection(peer, stream)); } } fn main() { async_std::task::block_on(run()); } async-tungstenite-0.28.0/examples/client.rs000064400000000000000000000040361046102023000170440ustar 00000000000000//! A simple example of hooking up stdin/stdout to a WebSocket stream. //! //! This example will connect to a server specified in the argument list and //! then forward all data read on stdin to the server, printing out all data //! received on stdout. //! //! Note that this is not currently optimized for performance, especially around //! buffer management. Rather it's intended to show an example of working with a //! client. //! //! You can use this example together with the `server` example. use std::env; use futures::{future, pin_mut, StreamExt}; use async_std::io; use async_std::prelude::*; use async_std::task; use async_tungstenite::async_std::connect_async; use async_tungstenite::tungstenite::protocol::Message; async fn run() { let connect_addr = env::args() .nth(1) .unwrap_or_else(|| panic!("this program requires at least one argument")); let (stdin_tx, stdin_rx) = futures::channel::mpsc::unbounded(); task::spawn(read_stdin(stdin_tx)); let (ws_stream, _) = connect_async(&connect_addr) .await .expect("Failed to connect"); println!("WebSocket handshake has been successfully completed"); let (write, read) = ws_stream.split(); let stdin_to_ws = stdin_rx.map(Ok).forward(write); let ws_to_stdout = { read.for_each(|message| async { let data = message.unwrap().into_data(); async_std::io::stdout().write_all(&data).await.unwrap(); }) }; pin_mut!(stdin_to_ws, ws_to_stdout); future::select(stdin_to_ws, ws_to_stdout).await; } // Our helper method which will read data from stdin and send it along the // sender provided. async fn read_stdin(tx: futures::channel::mpsc::UnboundedSender) { let mut stdin = io::stdin(); loop { let mut buf = vec![0; 1024]; let n = match stdin.read(&mut buf).await { Err(_) | Ok(0) => break, Ok(n) => n, }; buf.truncate(n); tx.unbounded_send(Message::binary(buf)).unwrap(); } } fn main() { task::block_on(run()) } async-tungstenite-0.28.0/examples/echo-server.rs000064400000000000000000000032071046102023000200070ustar 00000000000000//! A simple echo server. //! //! You can test this out by running: //! //! cargo run --features="async-std-runtime" --example echo-server 127.0.0.1:12345 //! //! And then in another window run: //! //! cargo run --features="async-std-runtime" --example client ws://127.0.0.1:12345/ use std::{env, io::Error}; use async_std::net::{TcpListener, TcpStream}; use async_std::task; use futures::prelude::*; use log::info; async fn run() -> Result<(), Error> { let _ = env_logger::try_init(); let addr = env::args() .nth(1) .unwrap_or_else(|| "127.0.0.1:8080".to_string()); // Create the event loop and TCP listener we'll accept connections on. let try_socket = TcpListener::bind(&addr).await; let listener = try_socket.expect("Failed to bind"); info!("Listening on: {}", addr); while let Ok((stream, _)) = listener.accept().await { task::spawn(accept_connection(stream)); } Ok(()) } async fn accept_connection(stream: TcpStream) { let addr = stream .peer_addr() .expect("connected streams should have a peer address"); info!("Peer address: {}", addr); let ws_stream = async_tungstenite::accept_async(stream) .await .expect("Error during the websocket handshake occurred"); info!("New WebSocket connection: {}", addr); let (write, read) = ws_stream.split(); // We should not forward messages other than text or binary. read.try_filter(|msg| future::ready(msg.is_text() || msg.is_binary())) .forward(write) .await .expect("Failed to forward messages") } fn main() -> Result<(), Error> { task::block_on(run()) } async-tungstenite-0.28.0/examples/gio-echo-server.rs000064400000000000000000000032211046102023000205570ustar 00000000000000use std::{env, net::SocketAddr}; use async_tungstenite::{gio::accept_async, tungstenite::Result}; use futures::prelude::*; use gio::{ prelude::*, InetSocketAddress, SocketConnection, SocketListener, SocketProtocol, SocketType, }; async fn accept_connection(stream: SocketConnection) -> Result<()> { let addr = stream .socket() .remote_address() .expect("SocketConnection should have a remote address"); println!("Peer address: {}", addr.to_string()); let mut ws_stream = accept_async(stream) .await .expect("Error during the websocket handshake occurred"); while let Some(msg) = ws_stream.next().await { let msg = msg?; if msg.is_text() || msg.is_binary() { ws_stream.send(msg).await?; } } Ok(()) } fn main() -> Result<(), Box> { let _ = env_logger::try_init(); let addr = env::args() .nth(1) .unwrap_or_else(|| "127.0.0.1:8080".to_string()); let sockaddr: SocketAddr = addr.parse()?; let inetaddr: InetSocketAddress = sockaddr.into(); let listener = SocketListener::new(); listener.add_address( &inetaddr, SocketType::Stream, SocketProtocol::Tcp, glib::Object::NONE, )?; println!("Listening on: {}", inetaddr.to_string()); let main_loop = glib::MainLoop::new(None, false); main_loop.context().block_on(async move { while let Ok((stream, _)) = listener.accept_future().await { glib::MainContext::default().spawn_local(async move { accept_connection(stream).await.unwrap(); }); } }); Ok(()) } async-tungstenite-0.28.0/examples/gio-echo.rs000064400000000000000000000014061046102023000172560ustar 00000000000000use async_tungstenite::{gio::connect_async, tungstenite::Message}; use futures::prelude::*; async fn run() -> Result<(), Box> { let url = "wss://echo.websocket.org"; let (mut ws_stream, _) = connect_async(url).await?; let text = "Hello, World!"; println!("Sending: \"{}\"", text); ws_stream.send(Message::text(text)).await?; let msg = ws_stream.next().await.ok_or("didn't receive anything")??; println!("Received: {:?}", msg); ws_stream.close(None).await.expect("error sending close"); Ok(()) } fn main() -> Result<(), Box> { // Get the default main context and run our async function on it let main_context = glib::MainContext::default(); main_context.block_on(run()) } async-tungstenite-0.28.0/examples/interval-server.rs000064400000000000000000000052031046102023000207130ustar 00000000000000use async_std::net::{TcpListener, TcpStream}; use async_std::task; use async_tungstenite::{ accept_async, tungstenite::{Error, Message, Result}, }; use futures::future::{select, Either}; use futures::prelude::*; use log::*; use std::net::SocketAddr; use std::time::Duration; async fn accept_connection(peer: SocketAddr, stream: TcpStream) { if let Err(e) = handle_connection(peer, stream).await { match e { Error::ConnectionClosed | Error::Protocol(_) | Error::Utf8 => (), err => error!("Error processing connection: {}", err), } } } async fn handle_connection(peer: SocketAddr, stream: TcpStream) -> Result<()> { let ws_stream = accept_async(stream).await.expect("Failed to accept"); info!("New WebSocket connection: {}", peer); let (mut ws_sender, mut ws_receiver) = ws_stream.split(); let mut interval = async_std::stream::interval(Duration::from_millis(1000)); // Echo incoming WebSocket messages and send a message periodically every second. let mut msg_fut = ws_receiver.next(); let mut tick_fut = interval.next(); loop { match select(msg_fut, tick_fut).await { Either::Left((msg, tick_fut_continue)) => { match msg { Some(msg) => { let msg = msg?; if msg.is_text() || msg.is_binary() { ws_sender.send(msg).await?; } else if msg.is_close() { break; } tick_fut = tick_fut_continue; // Continue waiting for tick. msg_fut = ws_receiver.next(); // Receive next WebSocket message. } None => break, // WebSocket stream terminated. }; } Either::Right((_, msg_fut_continue)) => { ws_sender.send(Message::Text("tick".to_owned())).await?; msg_fut = msg_fut_continue; // Continue receiving the WebSocket message. tick_fut = interval.next(); // Wait for next tick. } } } Ok(()) } async fn run() { env_logger::init(); let addr = "127.0.0.1:9002"; let listener = TcpListener::bind(&addr).await.expect("Can't listen"); info!("Listening on: {}", addr); while let Ok((stream, _)) = listener.accept().await { let peer = stream .peer_addr() .expect("connected streams should have a peer address"); info!("Peer address: {}", peer); task::spawn(accept_connection(peer, stream)); } } fn main() { task::block_on(run()); } async-tungstenite-0.28.0/examples/server-custom-accept.rs000064400000000000000000000143731046102023000216460ustar 00000000000000//! A chat server that broadcasts a message to all connections. //! //! This is a simple line-based server which accepts WebSocket connections, //! reads lines from those connections, and broadcasts the lines to all other //! connected clients. //! //! You can test this out by running: //! //! cargo run --example server 127.0.0.1:12345 //! //! And then in another window run: //! //! cargo run --example client ws://127.0.0.1:12345/socket //! //! You can run the second command in multiple windows and then chat between the //! two, seeing the messages from the other client as they're received. For all //! connected clients they'll all join the same room and see everyone else's //! messages. use std::{ collections::HashMap, convert::Infallible, env, net::SocketAddr, sync::{Arc, Mutex}, }; use hyper::{ body::Incoming, header::{ HeaderValue, CONNECTION, SEC_WEBSOCKET_ACCEPT, SEC_WEBSOCKET_KEY, SEC_WEBSOCKET_VERSION, UPGRADE, }, server::conn::http1, service::service_fn, upgrade::Upgraded, Method, Request, Response, StatusCode, Version, }; use hyper_util::rt::TokioIo; use tokio::net::TcpListener; use futures_channel::mpsc::{unbounded, UnboundedSender}; use futures_util::{future, pin_mut, stream::TryStreamExt, StreamExt}; use async_tungstenite::{tokio::TokioAdapter, WebSocketStream}; use tungstenite::{ handshake::derive_accept_key, protocol::{Message, Role}, }; type Tx = UnboundedSender; type PeerMap = Arc>>; type Body = http_body_util::Full; async fn handle_connection( peer_map: PeerMap, ws_stream: WebSocketStream>>, addr: SocketAddr, ) { println!("WebSocket connection established: {}", addr); // Insert the write part of this peer to the peer map. let (tx, rx) = unbounded(); peer_map.lock().unwrap().insert(addr, tx); let (outgoing, incoming) = ws_stream.split(); let broadcast_incoming = incoming.try_for_each(|msg| { println!( "Received a message from {}: {}", addr, msg.to_text().unwrap() ); let peers = peer_map.lock().unwrap(); // We want to broadcast the message to everyone except ourselves. let broadcast_recipients = peers .iter() .filter(|(peer_addr, _)| peer_addr != &&addr) .map(|(_, ws_sink)| ws_sink); for recp in broadcast_recipients { recp.unbounded_send(msg.clone()).unwrap(); } future::ok(()) }); let receive_from_others = rx.map(Ok).forward(outgoing); pin_mut!(broadcast_incoming, receive_from_others); future::select(broadcast_incoming, receive_from_others).await; println!("{} disconnected", &addr); peer_map.lock().unwrap().remove(&addr); } async fn handle_request( peer_map: PeerMap, mut req: Request, addr: SocketAddr, ) -> Result, Infallible> { println!("Received a new, potentially ws handshake"); println!("The request's path is: {}", req.uri().path()); println!("The request's headers are:"); for (ref header, _value) in req.headers() { println!("* {}", header); } let upgrade = HeaderValue::from_static("Upgrade"); let websocket = HeaderValue::from_static("websocket"); let headers = req.headers(); let key = headers.get(SEC_WEBSOCKET_KEY); let derived = key.map(|k| derive_accept_key(k.as_bytes())); if req.method() != Method::GET || req.version() < Version::HTTP_11 || !headers .get(CONNECTION) .and_then(|h| h.to_str().ok()) .map(|h| { h.split(|c| c == ' ' || c == ',') .any(|p| p.eq_ignore_ascii_case(upgrade.to_str().unwrap())) }) .unwrap_or(false) || !headers .get(UPGRADE) .and_then(|h| h.to_str().ok()) .map(|h| h.eq_ignore_ascii_case("websocket")) .unwrap_or(false) || !headers .get(SEC_WEBSOCKET_VERSION) .map(|h| h == "13") .unwrap_or(false) || key.is_none() || req.uri() != "/socket" { return Ok(Response::new(Body::from("Hello World!"))); } let ver = req.version(); tokio::task::spawn(async move { match hyper::upgrade::on(&mut req).await { Ok(upgraded) => { handle_connection( peer_map, WebSocketStream::from_raw_socket( TokioAdapter::new(TokioIo::new(upgraded)), Role::Server, None, ) .await, addr, ) .await; } Err(e) => println!("upgrade error: {}", e), } }); let mut res = Response::new(Body::default()); *res.status_mut() = StatusCode::SWITCHING_PROTOCOLS; *res.version_mut() = ver; res.headers_mut().append(CONNECTION, upgrade); res.headers_mut().append(UPGRADE, websocket); res.headers_mut() .append(SEC_WEBSOCKET_ACCEPT, derived.unwrap().parse().unwrap()); // Let's add an additional header to our response to the client. res.headers_mut() .append("MyCustomHeader", ":)".parse().unwrap()); res.headers_mut() .append("SOME_TUNGSTENITE_HEADER", "header_value".parse().unwrap()); Ok(res) } #[tokio::main] async fn main() -> Result<(), Box> { let state = PeerMap::new(Mutex::new(HashMap::new())); let addr = env::args() .nth(1) .unwrap_or_else(|| "127.0.0.1:8080".to_string()) .parse::()?; let listener = TcpListener::bind(addr).await?; loop { let (stream, addr) = listener.accept().await?; let state = state.clone(); tokio::spawn(async move { let io = TokioIo::new(stream); let service = service_fn(move |req| handle_request(state.clone(), req, addr)); let conn = http1::Builder::new() .serve_connection(io, service) .with_upgrades(); if let Err(err) = conn.await { eprintln!("failed to serve connection: {err:?}"); } }); } } async-tungstenite-0.28.0/examples/server-headers.rs000064400000000000000000000046131046102023000205060ustar 00000000000000//! Read/Write headers on server example //! //! Run with logs: //! Linux: //! ```sh //! RUST_LOG=debug cargo run --example server-headers //! ``` //! Windows //! ```sh //! cmd /c "set RUST_LOG=debug && cargo run --example server-headers" //! ``` use async_std::{ net::{TcpListener, TcpStream}, task, }; use async_tungstenite::{ accept_hdr_async, tungstenite::{ connect, handshake::server::{Request, Response}, Message, }, }; use url::Url; #[macro_use] extern crate log; use futures_util::{SinkExt, StreamExt}; #[async_std::main] async fn main() { env_logger::builder().format_timestamp(None).init(); task::spawn(async move { server().await; }); client(); } async fn server() { let server = TcpListener::bind("127.0.0.1:8080").await.unwrap(); while let Ok((stream, _)) = server.accept().await { task::spawn(accept_connection(stream)); } } async fn accept_connection(stream: TcpStream) { let callback = |req: &Request, mut response: Response| { debug!("Received a new ws handshake"); debug!("The request's path is: {}", req.uri().path()); debug!("The request's headers are:"); for (ref header, _value) in req.headers() { debug!("* {}: {:?}", header, _value); } let headers = response.headers_mut(); headers.append("MyCustomHeader", ":)".parse().unwrap()); Ok(response) }; let mut ws_stream = accept_hdr_async(stream, callback) .await .expect("Error during the websocket handshake occurred"); while let Some(msg) = ws_stream.next().await { let msg = msg.unwrap(); if msg.is_text() || msg.is_binary() { debug!("Server on message: {:?}", &msg); ws_stream.send(msg).await.unwrap(); } } } fn client() { let (mut socket, response) = connect(Url::parse("ws://localhost:8080/socket").unwrap()).expect("Can't connect"); debug!("Connected to the server"); debug!("Response HTTP code: {}", response.status()); debug!("Response contains the following headers:"); for (ref header, _value) in response.headers() { debug!("* {}: {:?}", header, _value); } socket .send(Message::Text("Hello WebSocket".into())) .unwrap(); loop { let msg = socket.read().expect("Error reading message"); debug!("Received: {}", msg); } } async-tungstenite-0.28.0/examples/server.rs000064400000000000000000000070241046102023000170740ustar 00000000000000//! A chat server that broadcasts a message to all connections. //! //! This is a simple line-based server which accepts WebSocket connections, //! reads lines from those connections, and broadcasts the lines to all other //! connected clients. //! //! You can test this out by running: //! //! cargo run --features="async-std-runtime" --example server 127.0.0.1:12345 //! //! And then in another window run: //! //! cargo run --features="async-std-runtime" --example client ws://127.0.0.1:12345/ //! //! You can run the second command in multiple windows and then chat between the //! two, seeing the messages from the other client as they're received. For all //! connected clients they'll all join the same room and see everyone else's //! messages. use std::{ collections::HashMap, env, io::Error as IoError, net::SocketAddr, sync::{Arc, Mutex}, }; use futures::prelude::*; use futures::{ channel::mpsc::{unbounded, UnboundedSender}, future, pin_mut, }; use async_std::net::{TcpListener, TcpStream}; use async_std::task; use async_tungstenite::tungstenite::protocol::Message; type Tx = UnboundedSender; type PeerMap = Arc>>; async fn handle_connection(peer_map: PeerMap, raw_stream: TcpStream, addr: SocketAddr) { println!("Incoming TCP connection from: {}", addr); let ws_stream = async_tungstenite::accept_async(raw_stream) .await .expect("Error during the websocket handshake occurred"); println!("WebSocket connection established: {}", addr); // Insert the write part of this peer to the peer map. let (tx, rx) = unbounded(); peer_map.lock().unwrap().insert(addr, tx); let (outgoing, incoming) = ws_stream.split(); let broadcast_incoming = incoming .try_filter(|msg| { // Broadcasting a Close message from one client // will close the other clients. future::ready(!msg.is_close()) }) .try_for_each(|msg| { println!( "Received a message from {}: {}", addr, msg.to_text().unwrap() ); let peers = peer_map.lock().unwrap(); // We want to broadcast the message to everyone except ourselves. let broadcast_recipients = peers .iter() .filter(|(peer_addr, _)| peer_addr != &&addr) .map(|(_, ws_sink)| ws_sink); for recp in broadcast_recipients { recp.unbounded_send(msg.clone()).unwrap(); } future::ok(()) }); let receive_from_others = rx.map(Ok).forward(outgoing); pin_mut!(broadcast_incoming, receive_from_others); future::select(broadcast_incoming, receive_from_others).await; println!("{} disconnected", &addr); peer_map.lock().unwrap().remove(&addr); } async fn run() -> Result<(), IoError> { let addr = env::args() .nth(1) .unwrap_or_else(|| "127.0.0.1:8080".to_string()); let state = PeerMap::new(Mutex::new(HashMap::new())); // Create the event loop and TCP listener we'll accept connections on. let try_socket = TcpListener::bind(&addr).await; let listener = try_socket.expect("Failed to bind"); println!("Listening on: {}", addr); // Let's spawn the handling of each connection in a separate task. while let Ok((stream, addr)) = listener.accept().await { task::spawn(handle_connection(state.clone(), stream, addr)); } Ok(()) } fn main() -> Result<(), IoError> { task::block_on(run()) } async-tungstenite-0.28.0/examples/tokio-echo.rs000064400000000000000000000016341046102023000176300ustar 00000000000000use async_tungstenite::{tokio::connect_async, tungstenite::Message}; use futures::prelude::*; async fn run() -> Result<(), Box> { #[cfg(any( feature = "async-tls", feature = "tokio-native-tls", feature = "tokio-openssl" ))] let url = "wss://echo.websocket.org"; #[cfg(not(any( feature = "async-tls", feature = "tokio-native-tls", feature = "tokio-openssl" )))] let url = "ws://echo.websocket.org"; let (mut ws_stream, _) = connect_async(url).await?; let text = "Hello, World!"; println!("Sending: \"{}\"", text); ws_stream.send(Message::text(text)).await?; let msg = ws_stream.next().await.ok_or("didn't receive anything")??; println!("Received: {:?}", msg); Ok(()) } fn main() -> Result<(), Box> { let rt = tokio::runtime::Runtime::new()?; rt.block_on(run()) } async-tungstenite-0.28.0/src/async_std.rs000064400000000000000000000236071046102023000165330ustar 00000000000000//! `async-std` integration. use tungstenite::client::IntoClientRequest; use tungstenite::handshake::client::{Request, Response}; use tungstenite::protocol::WebSocketConfig; use tungstenite::Error; use async_std::net::TcpStream; use super::{domain, port, WebSocketStream}; #[cfg(feature = "async-native-tls")] use futures_io::{AsyncRead, AsyncWrite}; #[cfg(feature = "async-native-tls")] pub(crate) mod async_native_tls { use async_native_tls::TlsConnector as AsyncTlsConnector; use async_native_tls::TlsStream; use real_async_native_tls as async_native_tls; use tungstenite::client::uri_mode; use tungstenite::handshake::client::Request; use tungstenite::stream::Mode; use tungstenite::Error; use futures_io::{AsyncRead, AsyncWrite}; use crate::stream::Stream as StreamSwitcher; use crate::{ client_async_with_config, domain, IntoClientRequest, Response, WebSocketConfig, WebSocketStream, }; /// A stream that might be protected with TLS. pub type MaybeTlsStream = StreamSwitcher>; pub type AutoStream = MaybeTlsStream; pub type Connector = AsyncTlsConnector; async fn wrap_stream( socket: S, domain: String, connector: Option, mode: Mode, ) -> Result, Error> where S: 'static + AsyncRead + AsyncWrite + Unpin, { match mode { Mode::Plain => Ok(StreamSwitcher::Plain(socket)), Mode::Tls => { let stream = { let connector = if let Some(connector) = connector { connector } else { AsyncTlsConnector::new() }; connector .connect(&domain, socket) .await .map_err(|err| Error::Tls(err.into()))? }; Ok(StreamSwitcher::Tls(stream)) } } } /// Creates a WebSocket handshake from a request and a stream, /// upgrading the stream to TLS if required and using the given /// connector and WebSocket configuration. pub async fn client_async_tls_with_connector_and_config( request: R, stream: S, connector: Option, config: Option, ) -> Result<(WebSocketStream>, Response), Error> where R: IntoClientRequest + Unpin, S: 'static + AsyncRead + AsyncWrite + Unpin, AutoStream: Unpin, { let request: Request = request.into_client_request()?; let domain = domain(&request)?; // Make sure we check domain and mode first. URL must be valid. let mode = uri_mode(request.uri())?; let stream = wrap_stream(stream, domain, connector, mode).await?; client_async_with_config(request, stream, config).await } } #[cfg(not(any(feature = "async-tls", feature = "async-native-tls")))] pub(crate) mod dummy_tls { use futures_io::{AsyncRead, AsyncWrite}; use tungstenite::client::{uri_mode, IntoClientRequest}; use tungstenite::handshake::client::Request; use tungstenite::stream::Mode; use tungstenite::Error; use crate::{client_async_with_config, domain, Response, WebSocketConfig, WebSocketStream}; pub type AutoStream = S; type Connector = (); async fn wrap_stream( socket: S, _domain: String, _connector: Option<()>, mode: Mode, ) -> Result, Error> where S: 'static + AsyncRead + AsyncWrite + Unpin, { match mode { Mode::Plain => Ok(socket), Mode::Tls => Err(Error::Url( tungstenite::error::UrlError::TlsFeatureNotEnabled, )), } } /// Creates a WebSocket handshake from a request and a stream, /// upgrading the stream to TLS if required and using the given /// connector and WebSocket configuration. pub async fn client_async_tls_with_connector_and_config( request: R, stream: S, connector: Option, config: Option, ) -> Result<(WebSocketStream>, Response), Error> where R: IntoClientRequest + Unpin, S: 'static + AsyncRead + AsyncWrite + Unpin, AutoStream: Unpin, { let request: Request = request.into_client_request()?; let domain = domain(&request)?; // Make sure we check domain and mode first. URL must be valid. let mode = uri_mode(request.uri())?; let stream = wrap_stream(stream, domain, connector, mode).await?; client_async_with_config(request, stream, config).await } } #[cfg(not(any(feature = "async-tls", feature = "async-native-tls")))] pub use self::dummy_tls::client_async_tls_with_connector_and_config; #[cfg(not(any(feature = "async-tls", feature = "async-native-tls")))] use self::dummy_tls::AutoStream; #[cfg(all(feature = "async-tls", not(feature = "async-native-tls")))] pub use crate::async_tls::client_async_tls_with_connector_and_config; #[cfg(all(feature = "async-tls", not(feature = "async-native-tls")))] use crate::async_tls::AutoStream; #[cfg(all(feature = "async-tls", not(feature = "async-native-tls")))] type Connector = real_async_tls::TlsConnector; #[cfg(feature = "async-native-tls")] pub use self::async_native_tls::client_async_tls_with_connector_and_config; #[cfg(feature = "async-native-tls")] use self::async_native_tls::{AutoStream, Connector}; /// Type alias for the stream type of the `client_async()` functions. pub type ClientStream = AutoStream; #[cfg(feature = "async-native-tls")] /// Creates a WebSocket handshake from a request and a stream, /// upgrading the stream to TLS if required. pub async fn client_async_tls( request: R, stream: S, ) -> Result<(WebSocketStream>, Response), Error> where R: IntoClientRequest + Unpin, S: 'static + AsyncRead + AsyncWrite + Unpin, AutoStream: Unpin, { client_async_tls_with_connector_and_config(request, stream, None, None).await } #[cfg(feature = "async-native-tls")] /// Creates a WebSocket handshake from a request and a stream, /// upgrading the stream to TLS if required and using the given /// WebSocket configuration. pub async fn client_async_tls_with_config( request: R, stream: S, config: Option, ) -> Result<(WebSocketStream>, Response), Error> where R: IntoClientRequest + Unpin, S: 'static + AsyncRead + AsyncWrite + Unpin, AutoStream: Unpin, { client_async_tls_with_connector_and_config(request, stream, None, config).await } #[cfg(feature = "async-native-tls")] /// Creates a WebSocket handshake from a request and a stream, /// upgrading the stream to TLS if required and using the given /// connector. pub async fn client_async_tls_with_connector( request: R, stream: S, connector: Option, ) -> Result<(WebSocketStream>, Response), Error> where R: IntoClientRequest + Unpin, S: 'static + AsyncRead + AsyncWrite + Unpin, AutoStream: Unpin, { client_async_tls_with_connector_and_config(request, stream, connector, None).await } /// Type alias for the stream type of the `connect_async()` functions. pub type ConnectStream = ClientStream; /// Connect to a given URL. /// /// Accepts any request that implements [`IntoClientRequest`], which is often just `&str`, but can /// be a variety of types such as `httparse::Request` or [`tungstenite::http::Request`] for more /// complex uses. /// /// ```no_run /// # use tungstenite::client::IntoClientRequest; /// /// # async fn test() { /// use tungstenite::http::{Method, Request}; /// use async_tungstenite::async_std::connect_async; /// /// let mut request = "wss://api.example.com".into_client_request().unwrap(); /// request.headers_mut().insert("api-key", "42".parse().unwrap()); /// /// let (stream, response) = connect_async(request).await.unwrap(); /// # } /// ``` pub async fn connect_async( request: R, ) -> Result<(WebSocketStream, Response), Error> where R: IntoClientRequest + Unpin, { connect_async_with_config(request, None).await } /// Connect to a given URL with a given WebSocket configuration. pub async fn connect_async_with_config( request: R, config: Option, ) -> Result<(WebSocketStream, Response), Error> where R: IntoClientRequest + Unpin, { let request: Request = request.into_client_request()?; let domain = domain(&request)?; let port = port(&request)?; let try_socket = TcpStream::connect((domain.as_str(), port)).await; let socket = try_socket.map_err(Error::Io)?; client_async_tls_with_connector_and_config(request, socket, None, config).await } #[cfg(any(feature = "async-tls", feature = "async-native-tls"))] /// Connect to a given URL using the provided TLS connector. pub async fn connect_async_with_tls_connector( request: R, connector: Option, ) -> Result<(WebSocketStream, Response), Error> where R: IntoClientRequest + Unpin, { connect_async_with_tls_connector_and_config(request, connector, None).await } #[cfg(any(feature = "async-tls", feature = "async-native-tls"))] /// Connect to a given URL using the provided TLS connector. pub async fn connect_async_with_tls_connector_and_config( request: R, connector: Option, config: Option, ) -> Result<(WebSocketStream, Response), Error> where R: IntoClientRequest + Unpin, { let request: Request = request.into_client_request()?; let domain = domain(&request)?; let port = port(&request)?; let try_socket = TcpStream::connect((domain.as_str(), port)).await; let socket = try_socket.map_err(Error::Io)?; client_async_tls_with_connector_and_config(request, socket, connector, config).await } async-tungstenite-0.28.0/src/async_tls.rs000064400000000000000000000071511046102023000165370ustar 00000000000000//! `async-tls` integration. use tungstenite::client::{uri_mode, IntoClientRequest}; use tungstenite::handshake::client::{Request, Response}; use tungstenite::protocol::WebSocketConfig; use tungstenite::Error; use futures_io::{AsyncRead, AsyncWrite}; use super::{client_async_with_config, WebSocketStream}; use async_tls::client::TlsStream; use async_tls::TlsConnector as AsyncTlsConnector; use real_async_tls as async_tls; use tungstenite::stream::Mode; use crate::domain; use crate::stream::Stream as StreamSwitcher; type MaybeTlsStream = StreamSwitcher>; pub(crate) type AutoStream = MaybeTlsStream; async fn wrap_stream( socket: S, domain: String, connector: Option, mode: Mode, ) -> Result, Error> where S: 'static + AsyncRead + AsyncWrite + Unpin, { match mode { Mode::Plain => Ok(StreamSwitcher::Plain(socket)), Mode::Tls => { let stream = { let connector = connector.unwrap_or_else(AsyncTlsConnector::new); connector.connect(&domain, socket).await? }; Ok(StreamSwitcher::Tls(stream)) } } } /// Type alias for the stream type of the `client_async()` functions. pub type ClientStream = AutoStream; /// Creates a WebSocket handshake from a request and a stream, /// upgrading the stream to TLS if required. pub async fn client_async_tls( request: R, stream: S, ) -> Result<(WebSocketStream>, Response), Error> where R: IntoClientRequest + Unpin, S: 'static + AsyncRead + AsyncWrite + Unpin, AutoStream: Unpin, { client_async_tls_with_connector_and_config(request, stream, None, None).await } /// Creates a WebSocket handshake from a request and a stream, /// upgrading the stream to TLS if required and using the given /// WebSocket configuration. pub async fn client_async_tls_with_config( request: R, stream: S, config: Option, ) -> Result<(WebSocketStream>, Response), Error> where R: IntoClientRequest + Unpin, S: 'static + AsyncRead + AsyncWrite + Unpin, AutoStream: Unpin, { client_async_tls_with_connector_and_config(request, stream, None, config).await } /// Creates a WebSocket handshake from a request and a stream, /// upgrading the stream to TLS if required and using the given /// connector. pub async fn client_async_tls_with_connector( request: R, stream: S, connector: Option, ) -> Result<(WebSocketStream>, Response), Error> where R: IntoClientRequest + Unpin, S: 'static + AsyncRead + AsyncWrite + Unpin, AutoStream: Unpin, { client_async_tls_with_connector_and_config(request, stream, connector, None).await } /// Creates a WebSocket handshake from a request and a stream, /// upgrading the stream to TLS if required and using the given /// connector and WebSocket configuration. pub async fn client_async_tls_with_connector_and_config( request: R, stream: S, connector: Option, config: Option, ) -> Result<(WebSocketStream>, Response), Error> where R: IntoClientRequest + Unpin, S: 'static + AsyncRead + AsyncWrite + Unpin, AutoStream: Unpin, { let request: Request = request.into_client_request()?; let domain = domain(&request)?; // Make sure we check domain and mode first. URL must be valid. let mode = uri_mode(request.uri())?; let stream = wrap_stream(stream, domain, connector, mode).await?; client_async_with_config(request, stream, config).await } async-tungstenite-0.28.0/src/compat.rs000064400000000000000000000164061046102023000160260ustar 00000000000000#[allow(unused_imports)] use log::*; use std::io::{Read, Write}; use std::pin::Pin; use std::task::{Context, Poll}; use futures_io::{AsyncRead, AsyncWrite}; use futures_util::task; use std::sync::Arc; use tungstenite::Error as WsError; pub(crate) enum ContextWaker { Read, Write, } #[derive(Debug)] pub(crate) struct AllowStd { inner: S, // We have the problem that external read operations (i.e. the Stream impl) // can trigger both read (AsyncRead) and write (AsyncWrite) operations on // the underyling stream. At the same time write operations (i.e. the Sink // impl) can trigger write operations (AsyncWrite) too. // Both the Stream and the Sink can be used on two different tasks, but it // is required that AsyncRead and AsyncWrite are only ever used by a single // task (or better: with a single waker) at a time. // // Doing otherwise would cause only the latest waker to be remembered, so // in our case either the Stream or the Sink impl would potentially wait // forever to be woken up because only the other one would've been woken // up. // // To solve this we implement a waker proxy that has two slots (one for // read, one for write) to store wakers. One waker proxy is always passed // to the AsyncRead, the other to AsyncWrite so that they will only ever // have to store a single waker, but internally we dispatch any wakeups to // up to two actual wakers (one from the Sink impl and one from the Stream // impl). // // write_waker_proxy is always used for AsyncWrite, read_waker_proxy for // AsyncRead. The read_waker slots of both are used for the Stream impl // (and handshaking), the write_waker slots for the Sink impl. write_waker_proxy: Arc, read_waker_proxy: Arc, } // Internal trait used only in the Handshake module for registering // the waker for the context used during handshaking. We're using the // read waker slot for this, but any would do. // // Don't ever use this from multiple tasks at the same time! pub(crate) trait SetWaker { fn set_waker(&self, waker: &task::Waker); } impl SetWaker for AllowStd { fn set_waker(&self, waker: &task::Waker) { self.set_waker(ContextWaker::Read, waker); } } impl AllowStd { pub(crate) fn new(inner: S, waker: &task::Waker) -> Self { let res = Self { inner, write_waker_proxy: Default::default(), read_waker_proxy: Default::default(), }; // Register the handshake waker as read waker for both proxies, // see also the SetWaker trait. res.write_waker_proxy.read_waker.register(waker); res.read_waker_proxy.read_waker.register(waker); res } // Set the read or write waker for our proxies. // // Read: this is only supposed to be called by read (or handshake) operations, i.e. the Stream // impl on the WebSocketStream. // Reading can also cause writes to happen, e.g. in case of Message::Ping handling. // // Write: this is only supposde to be called by write operations, i.e. the Sink impl on the // WebSocketStream. pub(crate) fn set_waker(&self, kind: ContextWaker, waker: &task::Waker) { match kind { ContextWaker::Read => { self.write_waker_proxy.read_waker.register(waker); self.read_waker_proxy.read_waker.register(waker); } ContextWaker::Write => { self.write_waker_proxy.write_waker.register(waker); self.read_waker_proxy.write_waker.register(waker); } } } } // Proxy Waker that we pass to the internal AsyncRead/Write of the // stream underlying the websocket. We have two slots here for the // actual wakers to allow external read operations to trigger both // reads and writes, and the same for writes. #[derive(Debug, Default)] struct WakerProxy { read_waker: task::AtomicWaker, write_waker: task::AtomicWaker, } impl std::task::Wake for WakerProxy { fn wake(self: Arc) { self.wake_by_ref() } fn wake_by_ref(self: &Arc) { self.read_waker.wake(); self.write_waker.wake(); } } impl AllowStd where S: Unpin, { fn with_context(&mut self, kind: ContextWaker, f: F) -> Poll> where F: FnOnce(&mut Context<'_>, Pin<&mut S>) -> Poll>, { #[cfg(feature = "verbose-logging")] trace!("{}:{} AllowStd.with_context", file!(), line!()); let waker = match kind { ContextWaker::Read => task::Waker::from(self.read_waker_proxy.clone()), ContextWaker::Write => task::Waker::from(self.write_waker_proxy.clone()), }; let mut context = task::Context::from_waker(&waker); f(&mut context, Pin::new(&mut self.inner)) } pub(crate) fn get_mut(&mut self) -> &mut S { &mut self.inner } pub(crate) fn get_ref(&self) -> &S { &self.inner } } impl Read for AllowStd where S: AsyncRead + Unpin, { fn read(&mut self, buf: &mut [u8]) -> std::io::Result { #[cfg(feature = "verbose-logging")] trace!("{}:{} Read.read", file!(), line!()); match self.with_context(ContextWaker::Read, |ctx, stream| { #[cfg(feature = "verbose-logging")] trace!( "{}:{} Read.with_context read -> poll_read", file!(), line!() ); stream.poll_read(ctx, buf) }) { Poll::Ready(r) => r, Poll::Pending => Err(std::io::Error::from(std::io::ErrorKind::WouldBlock)), } } } impl Write for AllowStd where S: AsyncWrite + Unpin, { fn write(&mut self, buf: &[u8]) -> std::io::Result { #[cfg(feature = "verbose-logging")] trace!("{}:{} Write.write", file!(), line!()); match self.with_context(ContextWaker::Write, |ctx, stream| { #[cfg(feature = "verbose-logging")] trace!( "{}:{} Write.with_context write -> poll_write", file!(), line!() ); stream.poll_write(ctx, buf) }) { Poll::Ready(r) => r, Poll::Pending => Err(std::io::Error::from(std::io::ErrorKind::WouldBlock)), } } fn flush(&mut self) -> std::io::Result<()> { #[cfg(feature = "verbose-logging")] trace!("{}:{} Write.flush", file!(), line!()); match self.with_context(ContextWaker::Write, |ctx, stream| { #[cfg(feature = "verbose-logging")] trace!( "{}:{} Write.with_context flush -> poll_flush", file!(), line!() ); stream.poll_flush(ctx) }) { Poll::Ready(r) => r, Poll::Pending => Err(std::io::Error::from(std::io::ErrorKind::WouldBlock)), } } } pub(crate) fn cvt(r: Result) -> Poll> { match r { Ok(v) => Poll::Ready(Ok(v)), Err(WsError::Io(ref e)) if e.kind() == std::io::ErrorKind::WouldBlock => { #[cfg(feature = "verbose-logging")] trace!("WouldBlock"); Poll::Pending } Err(e) => Poll::Ready(Err(e)), } } async-tungstenite-0.28.0/src/gio.rs000064400000000000000000000161471046102023000153230ustar 00000000000000//! `gio` integration. use tungstenite::Error; use std::io; use gio::prelude::*; use futures_io::{AsyncRead, AsyncWrite}; use tungstenite::client::{uri_mode, IntoClientRequest}; use tungstenite::handshake::client::Request; use tungstenite::handshake::server::{Callback, NoCallback}; use tungstenite::stream::Mode; use crate::{client_async_with_config, domain, port, Response, WebSocketConfig, WebSocketStream}; /// Type alias for the stream type of the `connect_async()` functions. pub type ConnectStream = IOStreamAsyncReadWrite; /// Connect to a given URL. /// /// Accepts any request that implements [`IntoClientRequest`], which is often just `&str`, but can /// be a variety of types such as `httparse::Request` or [`tungstenite::http::Request`] for more /// complex uses. /// /// ```no_run /// # use tungstenite::client::IntoClientRequest; /// /// # async fn test() { /// use tungstenite::http::{Method, Request}; /// use async_tungstenite::gio::connect_async; /// /// let mut request = "wss://api.example.com".into_client_request().unwrap(); /// request.headers_mut().insert("api-key", "42".parse().unwrap()); /// /// let (stream, response) = connect_async(request).await.unwrap(); /// # } /// ``` pub async fn connect_async( request: R, ) -> Result<(WebSocketStream, Response), Error> where R: IntoClientRequest + Unpin, { connect_async_with_config(request, None).await } /// Connect to a given URL with a given WebSocket configuration. pub async fn connect_async_with_config( request: R, config: Option, ) -> Result<(WebSocketStream, Response), Error> where R: IntoClientRequest + Unpin, { let request: Request = request.into_client_request()?; let domain = domain(&request)?; let port = port(&request)?; let client = gio::SocketClient::new(); // Make sure we check domain and mode first. URL must be valid. let mode = uri_mode(request.uri())?; if let Mode::Tls = mode { client.set_tls(true); } else { client.set_tls(false); } let connectable = gio::NetworkAddress::new(domain.as_str(), port); let socket = client .connect_future(&connectable) .await .map_err(to_std_io_error)?; let socket = IOStreamAsyncReadWrite::new(socket) .map_err(|_| io::Error::new(io::ErrorKind::Other, "Unsupported gio::IOStream"))?; client_async_with_config(request, socket, config).await } /// Accepts a new WebSocket connection with the provided stream. /// /// This function will internally call `server::accept` to create a /// handshake representation and returns a future representing the /// resolution of the WebSocket handshake. The returned future will resolve /// to either `WebSocketStream` or `Error` depending if it's successful /// or not. /// /// This is typically used after a socket has been accepted from a /// `TcpListener`. That socket is then passed to this function to perform /// the server half of the accepting a client's websocket connection. pub async fn accept_async(stream: S) -> Result>, Error> where S: IsA + Unpin, { accept_hdr_async(stream, NoCallback).await } /// The same as `accept_async()` but the one can specify a websocket configuration. /// Please refer to `accept_async()` for more details. pub async fn accept_async_with_config( stream: S, config: Option, ) -> Result>, Error> where S: IsA + Unpin, { accept_hdr_async_with_config(stream, NoCallback, config).await } /// Accepts a new WebSocket connection with the provided stream. /// /// This function does the same as `accept_async()` but accepts an extra callback /// for header processing. The callback receives headers of the incoming /// requests and is able to add extra headers to the reply. pub async fn accept_hdr_async( stream: S, callback: C, ) -> Result>, Error> where S: IsA + Unpin, C: Callback + Unpin, { accept_hdr_async_with_config(stream, callback, None).await } /// The same as `accept_hdr_async()` but the one can specify a websocket configuration. /// Please refer to `accept_hdr_async()` for more details. pub async fn accept_hdr_async_with_config( stream: S, callback: C, config: Option, ) -> Result>, Error> where S: IsA + Unpin, C: Callback + Unpin, { let stream = IOStreamAsyncReadWrite::new(stream) .map_err(|_| io::Error::new(io::ErrorKind::Other, "Unsupported gio::IOStream"))?; crate::accept_hdr_async_with_config(stream, callback, config).await } /// Adapter for `gio::IOStream` to provide `AsyncRead` and `AsyncWrite`. #[derive(Debug)] pub struct IOStreamAsyncReadWrite> { #[allow(dead_code)] io_stream: T, read: gio::InputStreamAsyncRead, write: gio::OutputStreamAsyncWrite, } unsafe impl> Send for IOStreamAsyncReadWrite {} impl> IOStreamAsyncReadWrite { /// Create a new `gio::IOStream` adapter fn new(stream: T) -> Result, T> { let write = stream .output_stream() .dynamic_cast::() .ok() .and_then(|s| s.into_async_write().ok()); let read = stream .input_stream() .dynamic_cast::() .ok() .and_then(|s| s.into_async_read().ok()); let (read, write) = match (read, write) { (Some(read), Some(write)) => (read, write), _ => return Err(stream), }; Ok(IOStreamAsyncReadWrite { io_stream: stream, read, write, }) } } use std::pin::Pin; use std::task::{Context, Poll}; impl + Unpin> AsyncRead for IOStreamAsyncReadWrite { fn poll_read( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8], ) -> Poll> { Pin::new(&mut Pin::get_mut(self).read).poll_read(cx, buf) } } impl + Unpin> AsyncWrite for IOStreamAsyncReadWrite { fn poll_write( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8], ) -> Poll> { Pin::new(&mut Pin::get_mut(self).write).poll_write(cx, buf) } fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { Pin::new(&mut Pin::get_mut(self).write).poll_close(cx) } fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { Pin::new(&mut Pin::get_mut(self).write).poll_flush(cx) } } fn to_std_io_error(error: glib::Error) -> io::Error { match error.kind::() { Some(io_error_enum) => io::Error::new(io_error_enum.into(), error), None => io::Error::new(io::ErrorKind::Other, error), } } async-tungstenite-0.28.0/src/handshake.rs000064400000000000000000000131731046102023000164670ustar 00000000000000use crate::compat::AllowStd; #[cfg(feature = "handshake")] use crate::compat::SetWaker; use crate::WebSocketStream; use futures_io::{AsyncRead, AsyncWrite}; #[allow(unused_imports)] use log::*; use std::future::Future; use std::io::{Read, Write}; use std::pin::Pin; use std::task::{Context, Poll}; use tungstenite::WebSocket; #[cfg(feature = "handshake")] use tungstenite::{ handshake::{ client::Response, server::Callback, HandshakeError as Error, HandshakeRole, MidHandshake as WsHandshake, }, ClientHandshake, ServerHandshake, }; pub(crate) async fn without_handshake(stream: S, f: F) -> WebSocketStream where F: FnOnce(AllowStd) -> WebSocket> + Unpin, S: AsyncRead + AsyncWrite + Unpin, { let start = SkippedHandshakeFuture(Some(SkippedHandshakeFutureInner { f, stream })); let ws = start.await; WebSocketStream::new(ws) } struct SkippedHandshakeFuture(Option>); struct SkippedHandshakeFutureInner { f: F, stream: S, } impl Future for SkippedHandshakeFuture where F: FnOnce(AllowStd) -> WebSocket> + Unpin, S: Unpin, AllowStd: Read + Write, { type Output = WebSocket>; fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll { let inner = self .get_mut() .0 .take() .expect("future polled after completion"); #[cfg(feature = "verbose-logging")] trace!("Setting context when skipping handshake"); let stream = AllowStd::new(inner.stream, ctx.waker()); Poll::Ready((inner.f)(stream)) } } #[cfg(feature = "handshake")] struct MidHandshake(Option>); #[cfg(feature = "handshake")] enum StartedHandshake { Done(Role::FinalResult), Mid(WsHandshake), } #[cfg(feature = "handshake")] struct StartedHandshakeFuture(Option>); #[cfg(feature = "handshake")] struct StartedHandshakeFutureInner { f: F, stream: S, } #[cfg(feature = "handshake")] async fn handshake(stream: S, f: F) -> Result> where Role: HandshakeRole + Unpin, Role::InternalStream: SetWaker + Unpin, F: FnOnce(AllowStd) -> Result> + Unpin, S: AsyncRead + AsyncWrite + Unpin, { let start = StartedHandshakeFuture(Some(StartedHandshakeFutureInner { f, stream })); match start.await? { StartedHandshake::Done(r) => Ok(r), StartedHandshake::Mid(s) => { let res: Result> = MidHandshake::(Some(s)).await; res } } } #[cfg(feature = "handshake")] pub(crate) async fn client_handshake( stream: S, f: F, ) -> Result<(WebSocketStream, Response), Error>>> where F: FnOnce( AllowStd, ) -> Result< > as HandshakeRole>::FinalResult, Error>>, > + Unpin, S: AsyncRead + AsyncWrite + Unpin, { let result = handshake(stream, f).await?; let (s, r) = result; Ok((WebSocketStream::new(s), r)) } #[cfg(feature = "handshake")] pub(crate) async fn server_handshake( stream: S, f: F, ) -> Result, Error, C>>> where C: Callback + Unpin, F: FnOnce( AllowStd, ) -> Result< , C> as HandshakeRole>::FinalResult, Error, C>>, > + Unpin, S: AsyncRead + AsyncWrite + Unpin, { let s: WebSocket> = handshake(stream, f).await?; Ok(WebSocketStream::new(s)) } #[cfg(feature = "handshake")] impl Future for StartedHandshakeFuture where Role: HandshakeRole, Role::InternalStream: SetWaker, F: FnOnce(AllowStd) -> Result> + Unpin, S: Unpin, AllowStd: Read + Write, { type Output = Result, Error>; fn poll(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll { let inner = self.0.take().expect("future polled after completion"); #[cfg(feature = "verbose-logging")] trace!("Setting ctx when starting handshake"); let stream = AllowStd::new(inner.stream, ctx.waker()); match (inner.f)(stream) { Ok(r) => Poll::Ready(Ok(StartedHandshake::Done(r))), Err(Error::Interrupted(mid)) => Poll::Ready(Ok(StartedHandshake::Mid(mid))), Err(Error::Failure(e)) => Poll::Ready(Err(Error::Failure(e))), } } } #[cfg(feature = "handshake")] impl Future for MidHandshake where Role: HandshakeRole + Unpin, Role::InternalStream: SetWaker + Unpin, { type Output = Result>; fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let mut s = self .as_mut() .0 .take() .expect("future polled after completion"); let machine = s.get_mut(); #[cfg(feature = "verbose-logging")] trace!("Setting context in handshake"); machine.get_mut().set_waker(cx.waker()); match s.handshake() { Ok(stream) => Poll::Ready(Ok(stream)), Err(Error::Failure(e)) => Poll::Ready(Err(Error::Failure(e))), Err(Error::Interrupted(mid)) => { self.0 = Some(mid); Poll::Pending } } } } async-tungstenite-0.28.0/src/lib.rs000064400000000000000000000425431046102023000153120ustar 00000000000000//! Async WebSockets. //! //! This crate is based on [tungstenite](https://crates.io/crates/tungstenite) //! Rust WebSocket library and provides async bindings and wrappers for it, so you //! can use it with non-blocking/asynchronous `TcpStream`s from and couple it //! together with other crates from the async stack. In addition, optional //! integration with various other crates can be enabled via feature flags //! //! * `async-tls`: Enables the `async_tls` module, which provides integration //! with the [async-tls](https://crates.io/crates/async-tls) TLS stack and can //! be used independent of any async runtime. //! * `async-std-runtime`: Enables the `async_std` module, which provides //! integration with the [async-std](https://async.rs) runtime. //! * `async-native-tls`: Enables the additional functions in the `async_std` //! module to implement TLS via //! [async-native-tls](https://crates.io/crates/async-native-tls). //! * `tokio-runtime`: Enables the `tokio` module, which provides integration //! with the [tokio](https://tokio.rs) runtime. //! * `tokio-native-tls`: Enables the additional functions in the `tokio` module to //! implement TLS via [tokio-native-tls](https://crates.io/crates/tokio-native-tls). //! * `tokio-rustls-native-certs`: Enables the additional functions in the `tokio` //! module to implement TLS via [tokio-rustls](https://crates.io/crates/tokio-rustls) //! and uses native system certificates found with //! [rustls-native-certs](https://github.com/rustls/rustls-native-certs). //! * `tokio-rustls-webpki-roots`: Enables the additional functions in the `tokio` //! module to implement TLS via [tokio-rustls](https://crates.io/crates/tokio-rustls) //! and uses the certificates [webpki-roots](https://github.com/rustls/webpki-roots) //! provides. //! * `tokio-openssl`: Enables the additional functions in the `tokio` module to //! implement TLS via [tokio-openssl](https://crates.io/crates/tokio-openssl). //! * `gio-runtime`: Enables the `gio` module, which provides integration with //! the [gio](https://www.gtk-rs.org) runtime. //! //! Each WebSocket stream implements the required `Stream` and `Sink` traits, //! making the socket a stream of WebSocket messages coming in and going out. #![deny( missing_docs, unused_must_use, unused_mut, unused_imports, unused_import_braces )] pub use tungstenite; mod compat; mod handshake; #[cfg(any( feature = "async-tls", feature = "async-native-tls", feature = "tokio-native-tls", feature = "tokio-rustls-manual-roots", feature = "tokio-rustls-native-certs", feature = "tokio-rustls-webpki-roots", feature = "tokio-openssl", ))] pub mod stream; use std::io::{Read, Write}; use compat::{cvt, AllowStd, ContextWaker}; use futures_io::{AsyncRead, AsyncWrite}; use futures_util::{ sink::{Sink, SinkExt}, stream::{FusedStream, Stream}, }; use log::*; use std::pin::Pin; use std::task::{Context, Poll}; #[cfg(feature = "handshake")] use tungstenite::{ client::IntoClientRequest, handshake::{ client::{ClientHandshake, Response}, server::{Callback, NoCallback}, HandshakeError, }, }; use tungstenite::{ error::Error as WsError, protocol::{Message, Role, WebSocket, WebSocketConfig}, }; #[cfg(feature = "async-std-runtime")] pub mod async_std; #[cfg(feature = "async-tls")] pub mod async_tls; #[cfg(feature = "gio-runtime")] pub mod gio; #[cfg(feature = "tokio-runtime")] pub mod tokio; use tungstenite::protocol::CloseFrame; /// Creates a WebSocket handshake from a request and a stream. /// For convenience, the user may call this with a url string, a URL, /// or a `Request`. Calling with `Request` allows the user to add /// a WebSocket protocol or other custom headers. /// /// Internally, this custom creates a handshake representation and returns /// a future representing the resolution of the WebSocket handshake. The /// returned future will resolve to either `WebSocketStream` or `Error` /// depending on whether the handshake is successful. /// /// This is typically used for clients who have already established, for /// example, a TCP connection to the remote server. #[cfg(feature = "handshake")] pub async fn client_async<'a, R, S>( request: R, stream: S, ) -> Result<(WebSocketStream, Response), WsError> where R: IntoClientRequest + Unpin, S: AsyncRead + AsyncWrite + Unpin, { client_async_with_config(request, stream, None).await } /// The same as `client_async()` but the one can specify a websocket configuration. /// Please refer to `client_async()` for more details. #[cfg(feature = "handshake")] pub async fn client_async_with_config<'a, R, S>( request: R, stream: S, config: Option, ) -> Result<(WebSocketStream, Response), WsError> where R: IntoClientRequest + Unpin, S: AsyncRead + AsyncWrite + Unpin, { let f = handshake::client_handshake(stream, move |allow_std| { let request = request.into_client_request()?; let cli_handshake = ClientHandshake::start(allow_std, request, config)?; cli_handshake.handshake() }); f.await.map_err(|e| match e { HandshakeError::Failure(e) => e, e => WsError::Io(std::io::Error::new( std::io::ErrorKind::Other, e.to_string(), )), }) } /// Accepts a new WebSocket connection with the provided stream. /// /// This function will internally call `server::accept` to create a /// handshake representation and returns a future representing the /// resolution of the WebSocket handshake. The returned future will resolve /// to either `WebSocketStream` or `Error` depending if it's successful /// or not. /// /// This is typically used after a socket has been accepted from a /// `TcpListener`. That socket is then passed to this function to perform /// the server half of the accepting a client's websocket connection. #[cfg(feature = "handshake")] pub async fn accept_async(stream: S) -> Result, WsError> where S: AsyncRead + AsyncWrite + Unpin, { accept_hdr_async(stream, NoCallback).await } /// The same as `accept_async()` but the one can specify a websocket configuration. /// Please refer to `accept_async()` for more details. #[cfg(feature = "handshake")] pub async fn accept_async_with_config( stream: S, config: Option, ) -> Result, WsError> where S: AsyncRead + AsyncWrite + Unpin, { accept_hdr_async_with_config(stream, NoCallback, config).await } /// Accepts a new WebSocket connection with the provided stream. /// /// This function does the same as `accept_async()` but accepts an extra callback /// for header processing. The callback receives headers of the incoming /// requests and is able to add extra headers to the reply. #[cfg(feature = "handshake")] pub async fn accept_hdr_async(stream: S, callback: C) -> Result, WsError> where S: AsyncRead + AsyncWrite + Unpin, C: Callback + Unpin, { accept_hdr_async_with_config(stream, callback, None).await } /// The same as `accept_hdr_async()` but the one can specify a websocket configuration. /// Please refer to `accept_hdr_async()` for more details. #[cfg(feature = "handshake")] pub async fn accept_hdr_async_with_config( stream: S, callback: C, config: Option, ) -> Result, WsError> where S: AsyncRead + AsyncWrite + Unpin, C: Callback + Unpin, { let f = handshake::server_handshake(stream, move |allow_std| { tungstenite::accept_hdr_with_config(allow_std, callback, config) }); f.await.map_err(|e| match e { HandshakeError::Failure(e) => e, e => WsError::Io(std::io::Error::new( std::io::ErrorKind::Other, e.to_string(), )), }) } /// A wrapper around an underlying raw stream which implements the WebSocket /// protocol. /// /// A `WebSocketStream` represents a handshake that has been completed /// successfully and both the server and the client are ready for receiving /// and sending data. Message from a `WebSocketStream` are accessible /// through the respective `Stream` and `Sink`. Check more information about /// them in `futures-rs` crate documentation or have a look on the examples /// and unit tests for this crate. #[derive(Debug)] pub struct WebSocketStream { inner: WebSocket>, closing: bool, ended: bool, /// Tungstenite is probably ready to receive more data. /// /// `false` once start_send hits `WouldBlock` errors. /// `true` initially and after `flush`ing. ready: bool, } impl WebSocketStream { /// Convert a raw socket into a WebSocketStream without performing a /// handshake. pub async fn from_raw_socket(stream: S, role: Role, config: Option) -> Self where S: AsyncRead + AsyncWrite + Unpin, { handshake::without_handshake(stream, move |allow_std| { WebSocket::from_raw_socket(allow_std, role, config) }) .await } /// Convert a raw socket into a WebSocketStream without performing a /// handshake. pub async fn from_partially_read( stream: S, part: Vec, role: Role, config: Option, ) -> Self where S: AsyncRead + AsyncWrite + Unpin, { handshake::without_handshake(stream, move |allow_std| { WebSocket::from_partially_read(allow_std, part, role, config) }) .await } pub(crate) fn new(ws: WebSocket>) -> Self { Self { inner: ws, closing: false, ended: false, ready: true, } } fn with_context(&mut self, ctx: Option<(ContextWaker, &mut Context<'_>)>, f: F) -> R where S: Unpin, F: FnOnce(&mut WebSocket>) -> R, AllowStd: Read + Write, { #[cfg(feature = "verbose-logging")] trace!("{}:{} WebSocketStream.with_context", file!(), line!()); if let Some((kind, ctx)) = ctx { self.inner.get_mut().set_waker(kind, ctx.waker()); } f(&mut self.inner) } /// Returns a shared reference to the inner stream. pub fn get_ref(&self) -> &S where S: AsyncRead + AsyncWrite + Unpin, { self.inner.get_ref().get_ref() } /// Returns a mutable reference to the inner stream. pub fn get_mut(&mut self) -> &mut S where S: AsyncRead + AsyncWrite + Unpin, { self.inner.get_mut().get_mut() } /// Returns a reference to the configuration of the tungstenite stream. pub fn get_config(&self) -> &WebSocketConfig { self.inner.get_config() } /// Close the underlying web socket pub async fn close(&mut self, msg: Option>) -> Result<(), WsError> where S: AsyncRead + AsyncWrite + Unpin, { let msg = msg.map(|msg| msg.into_owned()); self.send(Message::Close(msg)).await } } impl Stream for WebSocketStream where T: AsyncRead + AsyncWrite + Unpin, { type Item = Result; fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { #[cfg(feature = "verbose-logging")] trace!("{}:{} Stream.poll_next", file!(), line!()); // The connection has been closed or a critical error has occurred. // We have already returned the error to the user, the `Stream` is unusable, // so we assume that the stream has been "fused". if self.ended { return Poll::Ready(None); } match futures_util::ready!(self.with_context(Some((ContextWaker::Read, cx)), |s| { #[cfg(feature = "verbose-logging")] trace!( "{}:{} Stream.with_context poll_next -> read()", file!(), line!() ); cvt(s.read()) })) { Ok(v) => Poll::Ready(Some(Ok(v))), Err(e) => { self.ended = true; if matches!(e, WsError::AlreadyClosed | WsError::ConnectionClosed) { Poll::Ready(None) } else { Poll::Ready(Some(Err(e))) } } } } } impl FusedStream for WebSocketStream where T: AsyncRead + AsyncWrite + Unpin, { fn is_terminated(&self) -> bool { self.ended } } impl Sink for WebSocketStream where T: AsyncRead + AsyncWrite + Unpin, { type Error = WsError; fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { if self.ready { Poll::Ready(Ok(())) } else { // Currently blocked so try to flush the blockage away (*self) .with_context(Some((ContextWaker::Write, cx)), |s| cvt(s.flush())) .map(|r| { self.ready = true; r }) } } fn start_send(mut self: Pin<&mut Self>, item: Message) -> Result<(), Self::Error> { match (*self).with_context(None, |s| s.write(item)) { Ok(()) => { self.ready = true; Ok(()) } Err(WsError::Io(err)) if err.kind() == std::io::ErrorKind::WouldBlock => { // the message was accepted and queued so not an error // but `poll_ready` will now start trying to flush the block self.ready = false; Ok(()) } Err(e) => { self.ready = true; debug!("websocket start_send error: {}", e); Err(e) } } } fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { (*self) .with_context(Some((ContextWaker::Write, cx)), |s| cvt(s.flush())) .map(|r| { self.ready = true; match r { // WebSocket connection has just been closed. Flushing completed, not an error. Err(WsError::ConnectionClosed) => Ok(()), other => other, } }) } fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { self.ready = true; let res = if self.closing { // After queueing it, we call `flush` to drive the close handshake to completion. (*self).with_context(Some((ContextWaker::Write, cx)), |s| s.flush()) } else { (*self).with_context(Some((ContextWaker::Write, cx)), |s| s.close(None)) }; match res { Ok(()) => Poll::Ready(Ok(())), Err(WsError::ConnectionClosed) => Poll::Ready(Ok(())), Err(WsError::Io(err)) if err.kind() == std::io::ErrorKind::WouldBlock => { trace!("WouldBlock"); self.closing = true; Poll::Pending } Err(err) => { debug!("websocket close error: {}", err); Poll::Ready(Err(err)) } } } } #[cfg(any( feature = "async-tls", feature = "async-std-runtime", feature = "tokio-runtime", feature = "gio-runtime" ))] /// Get a domain from an URL. #[inline] pub(crate) fn domain( request: &tungstenite::handshake::client::Request, ) -> Result { request .uri() .host() .map(|host| { // If host is an IPv6 address, it might be surrounded by brackets. These brackets are // *not* part of a valid IP, so they must be stripped out. // // The URI from the request is guaranteed to be valid, so we don't need a separate // check for the closing bracket. let host = if host.starts_with('[') { &host[1..host.len() - 1] } else { host }; host.to_owned() }) .ok_or(tungstenite::Error::Url( tungstenite::error::UrlError::NoHostName, )) } #[cfg(any( feature = "async-std-runtime", feature = "tokio-runtime", feature = "gio-runtime" ))] /// Get the port from an URL. #[inline] pub(crate) fn port( request: &tungstenite::handshake::client::Request, ) -> Result { request .uri() .port_u16() .or_else(|| match request.uri().scheme_str() { Some("wss") => Some(443), Some("ws") => Some(80), _ => None, }) .ok_or(tungstenite::Error::Url( tungstenite::error::UrlError::UnsupportedUrlScheme, )) } #[cfg(test)] mod tests { #[cfg(any( feature = "async-tls", feature = "async-std-runtime", feature = "tokio-runtime", feature = "gio-runtime" ))] #[test] fn domain_strips_ipv6_brackets() { use tungstenite::client::IntoClientRequest; let request = "ws://[::1]:80".into_client_request().unwrap(); assert_eq!(crate::domain(&request).unwrap(), "::1"); } #[cfg(feature = "handshake")] #[test] fn requests_cannot_contain_invalid_uris() { use tungstenite::client::IntoClientRequest; assert!("ws://[".into_client_request().is_err()); assert!("ws://[blabla/bla".into_client_request().is_err()); assert!("ws://[::1/bla".into_client_request().is_err()); } } async-tungstenite-0.28.0/src/stream.rs000064400000000000000000000036461046102023000160400ustar 00000000000000//! Convenience wrapper for streams to switch between plain TCP and TLS at runtime. //! //! There is no dependency on actual TLS implementations. Everything like //! `native_tls` or `openssl` will work as long as there is a TLS stream supporting standard //! `AsyncRead + AsyncWrite` traits. use std::pin::Pin; use std::task::{Context, Poll}; use futures_io::{AsyncRead, AsyncWrite}; /// Stream, either plain TCP or TLS. #[derive(Debug)] pub enum Stream { /// Unencrypted socket stream. Plain(S), /// Encrypted socket stream. Tls(T), } impl AsyncRead for Stream { fn poll_read( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8], ) -> Poll> { match self.get_mut() { Stream::Plain(ref mut s) => Pin::new(s).poll_read(cx, buf), Stream::Tls(ref mut s) => Pin::new(s).poll_read(cx, buf), } } } impl AsyncWrite for Stream { fn poll_write( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8], ) -> Poll> { match self.get_mut() { Stream::Plain(ref mut s) => Pin::new(s).poll_write(cx, buf), Stream::Tls(ref mut s) => Pin::new(s).poll_write(cx, buf), } } fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { match self.get_mut() { Stream::Plain(ref mut s) => Pin::new(s).poll_flush(cx), Stream::Tls(ref mut s) => Pin::new(s).poll_flush(cx), } } fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { match self.get_mut() { Stream::Plain(ref mut s) => Pin::new(s).poll_close(cx), Stream::Tls(ref mut s) => Pin::new(s).poll_close(cx), } } } async-tungstenite-0.28.0/src/tokio/async_tls.rs000064400000000000000000000021631046102023000176620ustar 00000000000000use real_async_tls::client::TlsStream; use real_async_tls::TlsConnector; use tungstenite::client::IntoClientRequest; use tungstenite::Error; use crate::stream::Stream as StreamSwitcher; use crate::{Response, WebSocketConfig, WebSocketStream}; use super::TokioAdapter; pub type MaybeTlsStream = StreamSwitcher>; pub type AutoStream = MaybeTlsStream>; pub type Connector = TlsConnector; /// Creates a WebSocket handshake from a request and a stream, /// upgrading the stream to TLS if required and using the given /// connector and WebSocket configuration. pub async fn client_async_tls_with_connector_and_config( request: R, stream: S, connector: Option, config: Option, ) -> Result<(WebSocketStream>, Response), Error> where R: IntoClientRequest + Unpin, S: 'static + tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin, AutoStream: Unpin, { crate::async_tls::client_async_tls_with_connector_and_config( request, TokioAdapter::new(stream), connector, config, ) .await } async-tungstenite-0.28.0/src/tokio/dummy_tls.rs000064400000000000000000000031331046102023000176760ustar 00000000000000use tungstenite::client::{uri_mode, IntoClientRequest}; use tungstenite::handshake::client::Request; use tungstenite::stream::Mode; use tungstenite::Error; use super::TokioAdapter; use crate::{client_async_with_config, domain, Response, WebSocketConfig, WebSocketStream}; pub type AutoStream = TokioAdapter; type Connector = (); async fn wrap_stream( socket: S, _domain: String, _connector: Option<()>, mode: Mode, ) -> Result, Error> where S: 'static + tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin, { match mode { Mode::Plain => Ok(TokioAdapter::new(socket)), Mode::Tls => Err(Error::Url( tungstenite::error::UrlError::TlsFeatureNotEnabled, )), } } /// Creates a WebSocket handshake from a request and a stream, /// upgrading the stream to TLS if required and using the given /// connector and WebSocket configuration. pub async fn client_async_tls_with_connector_and_config( request: R, stream: S, connector: Option, config: Option, ) -> Result<(WebSocketStream>, Response), Error> where R: IntoClientRequest + Unpin, S: 'static + tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin, AutoStream: Unpin, { let request: Request = request.into_client_request()?; let domain = domain(&request)?; // Make sure we check domain and mode first. URL must be valid. let mode = uri_mode(request.uri())?; let stream = wrap_stream(stream, domain, connector, mode).await?; client_async_with_config(request, stream, config).await } async-tungstenite-0.28.0/src/tokio/native_tls.rs000064400000000000000000000047351046102023000200420ustar 00000000000000use real_tokio_native_tls::TlsConnector as AsyncTlsConnector; use real_tokio_native_tls::TlsStream; use tungstenite::client::{uri_mode, IntoClientRequest}; use tungstenite::handshake::client::Request; use tungstenite::stream::Mode; use tungstenite::Error; use crate::stream::Stream as StreamSwitcher; use crate::{client_async_with_config, domain, Response, WebSocketConfig, WebSocketStream}; use super::TokioAdapter; /// A stream that might be protected with TLS. pub type MaybeTlsStream = StreamSwitcher, TokioAdapter>>; pub type AutoStream = MaybeTlsStream; pub type Connector = AsyncTlsConnector; async fn wrap_stream( socket: S, domain: String, connector: Option, mode: Mode, ) -> Result, Error> where S: 'static + tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin, { match mode { Mode::Plain => Ok(StreamSwitcher::Plain(TokioAdapter::new(socket))), Mode::Tls => { let stream = { let connector = if let Some(connector) = connector { connector } else { let connector = real_native_tls::TlsConnector::builder() .build() .map_err(|err| Error::Tls(err.into()))?; AsyncTlsConnector::from(connector) }; connector .connect(&domain, socket) .await .map_err(|err| Error::Tls(err.into()))? }; Ok(StreamSwitcher::Tls(TokioAdapter::new(stream))) } } } /// Creates a WebSocket handshake from a request and a stream, /// upgrading the stream to TLS if required and using the given /// connector and WebSocket configuration. pub async fn client_async_tls_with_connector_and_config( request: R, stream: S, connector: Option, config: Option, ) -> Result<(WebSocketStream>, Response), Error> where R: IntoClientRequest + Unpin, S: 'static + tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin, AutoStream: Unpin, { let request: Request = request.into_client_request()?; let domain = domain(&request)?; // Make sure we check domain and mode first. URL must be valid. let mode = uri_mode(request.uri())?; let stream = wrap_stream(stream, domain, connector, mode).await?; client_async_with_config(request, stream, config).await } async-tungstenite-0.28.0/src/tokio/openssl.rs000064400000000000000000000062531046102023000173520ustar 00000000000000use openssl::ssl::{ConnectConfiguration, SslConnector, SslMethod}; use real_tokio_openssl::SslStream as TlsStream; use tungstenite::client::{uri_mode, IntoClientRequest}; use tungstenite::handshake::client::Request; use tungstenite::stream::Mode; use tungstenite::Error; use crate::stream::Stream as StreamSwitcher; use crate::{client_async_with_config, domain, Response, WebSocketConfig, WebSocketStream}; use super::TokioAdapter; /// A stream that might be protected with TLS. pub type MaybeTlsStream = StreamSwitcher, TokioAdapter>>>>; pub type AutoStream = MaybeTlsStream; pub type Connector = ConnectConfiguration; async fn wrap_stream( socket: S, domain: String, connector: Option, mode: Mode, ) -> Result, Error> where S: 'static + tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin + std::fmt::Debug + Send + Sync, { match mode { Mode::Plain => Ok(StreamSwitcher::Plain(TokioAdapter::new(socket))), Mode::Tls => { let stream = { let connector = if let Some(connector) = connector { connector } else { SslConnector::builder(SslMethod::tls()) .map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err))? .build() .configure() .map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err))? }; let ssl = connector .into_ssl(&domain) .map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err))?; let mut stream = Box::pin( TlsStream::new(ssl, socket) .map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err))?, ); stream .as_mut() .connect() .await .map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err))?; stream }; Ok(StreamSwitcher::Tls(TokioAdapter::new(stream))) } } } /// Creates a WebSocket handshake from a request and a stream, /// upgrading the stream to TLS if required and using the given /// connector and WebSocket configuration. pub async fn client_async_tls_with_connector_and_config( request: R, stream: S, connector: Option, config: Option, ) -> Result<(WebSocketStream>, Response), Error> where R: IntoClientRequest + Unpin, S: 'static + tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin + std::fmt::Debug + Send + Sync, AutoStream: Unpin, { let request: Request = request.into_client_request()?; let domain = domain(&request)?; // Make sure we check domain and mode first. URL must be valid. let mode = uri_mode(request.uri())?; let stream = wrap_stream(stream, domain, connector, mode).await?; client_async_with_config(request, stream, config).await } async-tungstenite-0.28.0/src/tokio/rustls.rs000064400000000000000000000103751046102023000172230ustar 00000000000000use real_tokio_rustls::rustls::{ClientConfig, RootCertStore}; use real_tokio_rustls::{client::TlsStream, TlsConnector}; use rustls_pki_types::ServerName; use tungstenite::client::{uri_mode, IntoClientRequest}; use tungstenite::error::TlsError; use tungstenite::handshake::client::Request; use tungstenite::stream::Mode; use tungstenite::Error; use std::convert::TryFrom; use crate::stream::Stream as StreamSwitcher; use crate::{client_async_with_config, domain, Response, WebSocketConfig, WebSocketStream}; use super::TokioAdapter; /// A stream that might be protected with TLS. pub type MaybeTlsStream = StreamSwitcher, TokioAdapter>>; pub type AutoStream = MaybeTlsStream; pub type Connector = TlsConnector; async fn wrap_stream( socket: S, domain: String, connector: Option, mode: Mode, ) -> Result, Error> where S: 'static + tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin, { match mode { Mode::Plain => Ok(StreamSwitcher::Plain(TokioAdapter::new(socket))), Mode::Tls => { let stream = { let connector = if let Some(connector) = connector { connector } else { #[cfg(feature = "tokio-rustls-manual-roots")] log::error!("tokio-rustls-manual-roots was selected, but no connector was provided! No certificates can be verified in this state."); #[cfg(feature = "tokio-rustls-manual-roots")] let root_store = RootCertStore::empty(); #[cfg(not(feature = "tokio-rustls-manual-roots"))] let mut root_store = RootCertStore::empty(); #[cfg(feature = "tokio-rustls-native-certs")] { let mut native_certs = rustls_native_certs::load_native_certs(); if let Some(err) = native_certs.errors.drain(..).next() { return Err(std::io::Error::new(std::io::ErrorKind::Other, err).into()); } let native_certs = native_certs.certs; let total_number = native_certs.len(); let (number_added, number_ignored) = root_store.add_parsable_certificates(native_certs); log::debug!("Added {number_added}/{total_number} native root certificates (ignored {number_ignored})"); } #[cfg(all( feature = "tokio-rustls-webpki-roots", not(feature = "tokio-rustls-native-certs"), not(feature = "tokio-rustls-manual-roots") ))] { root_store.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned()); } TlsConnector::from(std::sync::Arc::new( ClientConfig::builder() .with_root_certificates(root_store) .with_no_client_auth(), )) }; let domain = ServerName::try_from(domain) .map_err(|_| Error::Tls(TlsError::InvalidDnsName))?; connector.connect(domain, socket).await? }; Ok(StreamSwitcher::Tls(TokioAdapter::new(stream))) } } } /// Creates a WebSocket handshake from a request and a stream, /// upgrading the stream to TLS if required and using the given /// connector and WebSocket configuration. pub async fn client_async_tls_with_connector_and_config( request: R, stream: S, connector: Option, config: Option, ) -> Result<(WebSocketStream>, Response), Error> where R: IntoClientRequest + Unpin, S: 'static + tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin, AutoStream: Unpin, { let request: Request = request.into_client_request()?; let domain = domain(&request)?; // Make sure we check domain and mode first. URL must be valid. let mode = uri_mode(request.uri())?; let stream = wrap_stream(stream, domain, connector, mode).await?; client_async_with_config(request, stream, config).await } async-tungstenite-0.28.0/src/tokio.rs000064400000000000000000000423521046102023000156670ustar 00000000000000//! `tokio` integration. use tungstenite::client::IntoClientRequest; use tungstenite::handshake::client::{Request, Response}; use tungstenite::handshake::server::{Callback, NoCallback}; use tungstenite::protocol::WebSocketConfig; use tungstenite::Error; use tokio::net::TcpStream; use super::{domain, port, WebSocketStream}; use futures_io::{AsyncRead, AsyncWrite}; #[cfg(feature = "tokio-native-tls")] #[path = "tokio/native_tls.rs"] mod tls; #[cfg(all( any( feature = "tokio-rustls-manual-roots", feature = "tokio-rustls-native-certs", feature = "tokio-rustls-webpki-roots" ), not(feature = "tokio-native-tls") ))] #[path = "tokio/rustls.rs"] mod tls; #[cfg(all( feature = "tokio-openssl", not(any( feature = "tokio-native-tls", feature = "tokio-rustls-manual-roots", feature = "tokio-rustls-native-certs", feature = "tokio-rustls-webpki-roots" )) ))] #[path = "tokio/openssl.rs"] mod tls; #[cfg(all( feature = "async-tls", not(any( feature = "tokio-native-tls", feature = "tokio-rustls-manual-roots", feature = "tokio-rustls-native-certs", feature = "tokio-rustls-webpki-roots", feature = "tokio-openssl" )) ))] #[path = "tokio/async_tls.rs"] mod tls; #[cfg(not(any( feature = "tokio-native-tls", feature = "tokio-rustls-manual-roots", feature = "tokio-rustls-native-certs", feature = "tokio-rustls-webpki-roots", feature = "tokio-openssl", feature = "async-tls" )))] #[path = "tokio/dummy_tls.rs"] mod tls; #[cfg(any( feature = "tokio-native-tls", feature = "tokio-rustls-manual-roots", feature = "tokio-rustls-native-certs", feature = "tokio-rustls-webpki-roots", feature = "tokio-openssl", feature = "async-tls", ))] pub use self::tls::client_async_tls_with_connector_and_config; #[cfg(any( feature = "tokio-native-tls", feature = "tokio-rustls-manual-roots", feature = "tokio-rustls-native-certs", feature = "tokio-rustls-webpki-roots", feature = "tokio-openssl", feature = "async-tls" ))] use self::tls::{AutoStream, Connector}; #[cfg(not(any( feature = "tokio-native-tls", feature = "tokio-rustls-manual-roots", feature = "tokio-rustls-native-certs", feature = "tokio-rustls-webpki-roots", feature = "tokio-openssl", feature = "async-tls" )))] pub use self::tls::client_async_tls_with_connector_and_config; #[cfg(not(any( feature = "tokio-native-tls", feature = "tokio-rustls-manual-roots", feature = "tokio-rustls-native-certs", feature = "tokio-rustls-webpki-roots", feature = "tokio-openssl", feature = "async-tls" )))] use self::tls::AutoStream; /// Creates a WebSocket handshake from a request and a stream. /// For convenience, the user may call this with a url string, a URL, /// or a `Request`. Calling with `Request` allows the user to add /// a WebSocket protocol or other custom headers. /// /// Internally, this custom creates a handshake representation and returns /// a future representing the resolution of the WebSocket handshake. The /// returned future will resolve to either `WebSocketStream` or `Error` /// depending on whether the handshake is successful. /// /// This is typically used for clients who have already established, for /// example, a TCP connection to the remote server. pub async fn client_async<'a, R, S>( request: R, stream: S, ) -> Result<(WebSocketStream>, Response), Error> where R: IntoClientRequest + Unpin, S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin, { client_async_with_config(request, stream, None).await } /// The same as `client_async()` but the one can specify a websocket configuration. /// Please refer to `client_async()` for more details. pub async fn client_async_with_config<'a, R, S>( request: R, stream: S, config: Option, ) -> Result<(WebSocketStream>, Response), Error> where R: IntoClientRequest + Unpin, S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin, { crate::client_async_with_config(request, TokioAdapter::new(stream), config).await } /// Accepts a new WebSocket connection with the provided stream. /// /// This function will internally call `server::accept` to create a /// handshake representation and returns a future representing the /// resolution of the WebSocket handshake. The returned future will resolve /// to either `WebSocketStream` or `Error` depending if it's successful /// or not. /// /// This is typically used after a socket has been accepted from a /// `TcpListener`. That socket is then passed to this function to perform /// the server half of the accepting a client's websocket connection. pub async fn accept_async(stream: S) -> Result>, Error> where S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin, { accept_hdr_async(stream, NoCallback).await } /// The same as `accept_async()` but the one can specify a websocket configuration. /// Please refer to `accept_async()` for more details. pub async fn accept_async_with_config( stream: S, config: Option, ) -> Result>, Error> where S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin, { accept_hdr_async_with_config(stream, NoCallback, config).await } /// Accepts a new WebSocket connection with the provided stream. /// /// This function does the same as `accept_async()` but accepts an extra callback /// for header processing. The callback receives headers of the incoming /// requests and is able to add extra headers to the reply. pub async fn accept_hdr_async( stream: S, callback: C, ) -> Result>, Error> where S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin, C: Callback + Unpin, { accept_hdr_async_with_config(stream, callback, None).await } /// The same as `accept_hdr_async()` but the one can specify a websocket configuration. /// Please refer to `accept_hdr_async()` for more details. pub async fn accept_hdr_async_with_config( stream: S, callback: C, config: Option, ) -> Result>, Error> where S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin, C: Callback + Unpin, { crate::accept_hdr_async_with_config(TokioAdapter::new(stream), callback, config).await } /// Type alias for the stream type of the `client_async()` functions. pub type ClientStream = AutoStream; #[cfg(any( feature = "tokio-native-tls", feature = "tokio-rustls-native-certs", feature = "tokio-rustls-webpki-roots", all(feature = "__rustls-tls", not(feature = "tokio-rustls-manual-roots")), // No roots will be available all(feature = "async-tls", not(feature = "tokio-openssl")) ))] /// Creates a WebSocket handshake from a request and a stream, /// upgrading the stream to TLS if required. pub async fn client_async_tls( request: R, stream: S, ) -> Result<(WebSocketStream>, Response), Error> where R: IntoClientRequest + Unpin, S: 'static + tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin, AutoStream: Unpin, { client_async_tls_with_connector_and_config(request, stream, None, None).await } #[cfg(any( feature = "tokio-native-tls", feature = "tokio-rustls-native-certs", feature = "tokio-rustls-webpki-roots", all(feature = "__rustls-tls", not(feature = "tokio-rustls-manual-roots")), // No roots will be available all(feature = "async-tls", not(feature = "tokio-openssl")) ))] /// Creates a WebSocket handshake from a request and a stream, /// upgrading the stream to TLS if required and using the given /// WebSocket configuration. pub async fn client_async_tls_with_config( request: R, stream: S, config: Option, ) -> Result<(WebSocketStream>, Response), Error> where R: IntoClientRequest + Unpin, S: 'static + tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin, AutoStream: Unpin, { client_async_tls_with_connector_and_config(request, stream, None, config).await } #[cfg(any( feature = "tokio-native-tls", feature = "tokio-rustls-manual-roots", feature = "tokio-rustls-native-certs", feature = "tokio-rustls-webpki-roots", all(feature = "async-tls", not(feature = "tokio-openssl")) ))] /// Creates a WebSocket handshake from a request and a stream, /// upgrading the stream to TLS if required and using the given /// connector. pub async fn client_async_tls_with_connector( request: R, stream: S, connector: Option, ) -> Result<(WebSocketStream>, Response), Error> where R: IntoClientRequest + Unpin, S: 'static + tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin, AutoStream: Unpin, { client_async_tls_with_connector_and_config(request, stream, connector, None).await } #[cfg(all( feature = "tokio-openssl", not(any( feature = "tokio-native-tls", feature = "tokio-rustls-manual-roots", feature = "tokio-rustls-native-certs", feature = "tokio-rustls-webpki-roots" )) ))] /// Creates a WebSocket handshake from a request and a stream, /// upgrading the stream to TLS if required. pub async fn client_async_tls( request: R, stream: S, ) -> Result<(WebSocketStream>, Response), Error> where R: IntoClientRequest + Unpin, S: 'static + tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin + std::fmt::Debug + Send + Sync, AutoStream: Unpin, { client_async_tls_with_connector_and_config(request, stream, None, None).await } #[cfg(all( feature = "tokio-openssl", not(any( feature = "tokio-native-tls", feature = "tokio-rustls-manual-roots", feature = "tokio-rustls-native-certs", feature = "tokio-rustls-webpki-roots" )) ))] /// Creates a WebSocket handshake from a request and a stream, /// upgrading the stream to TLS if required and using the given /// WebSocket configuration. pub async fn client_async_tls_with_config( request: R, stream: S, config: Option, ) -> Result<(WebSocketStream>, Response), Error> where R: IntoClientRequest + Unpin, S: 'static + tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin + std::fmt::Debug + Send + Sync, AutoStream: Unpin, { client_async_tls_with_connector_and_config(request, stream, None, config).await } #[cfg(all( feature = "tokio-openssl", not(any( feature = "tokio-native-tls", feature = "tokio-rustls-manual-roots", feature = "tokio-rustls-native-certs", feature = "tokio-rustls-webpki-roots" )) ))] /// Creates a WebSocket handshake from a request and a stream, /// upgrading the stream to TLS if required and using the given /// connector. pub async fn client_async_tls_with_connector( request: R, stream: S, connector: Option, ) -> Result<(WebSocketStream>, Response), Error> where R: IntoClientRequest + Unpin, S: 'static + tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin + std::fmt::Debug + Send + Sync, AutoStream: Unpin, { client_async_tls_with_connector_and_config(request, stream, connector, None).await } /// Type alias for the stream type of the `connect_async()` functions. pub type ConnectStream = ClientStream; /// Connect to a given URL. /// /// Accepts any request that implements [`IntoClientRequest`], which is often just `&str`, but can /// be a variety of types such as `httparse::Request` or [`tungstenite::http::Request`] for more /// complex uses. /// /// ```no_run /// # use tungstenite::client::IntoClientRequest; /// /// # async fn test() { /// use tungstenite::http::{Method, Request}; /// use async_tungstenite::tokio::connect_async; /// /// let mut request = "wss://api.example.com".into_client_request().unwrap(); /// request.headers_mut().insert("api-key", "42".parse().unwrap()); /// /// let (stream, response) = connect_async(request).await.unwrap(); /// # } /// ``` pub async fn connect_async( request: R, ) -> Result<(WebSocketStream, Response), Error> where R: IntoClientRequest + Unpin, { connect_async_with_config(request, None).await } /// Connect to a given URL with a given WebSocket configuration. pub async fn connect_async_with_config( request: R, config: Option, ) -> Result<(WebSocketStream, Response), Error> where R: IntoClientRequest + Unpin, { let request: Request = request.into_client_request()?; let domain = domain(&request)?; let port = port(&request)?; let try_socket = TcpStream::connect((domain.as_str(), port)).await; let socket = try_socket.map_err(Error::Io)?; client_async_tls_with_connector_and_config(request, socket, None, config).await } #[cfg(any( feature = "async-tls", feature = "tokio-native-tls", feature = "tokio-rustls-manual-roots", feature = "tokio-rustls-native-certs", feature = "tokio-rustls-webpki-roots", feature = "tokio-openssl" ))] /// Connect to a given URL using the provided TLS connector. pub async fn connect_async_with_tls_connector( request: R, connector: Option, ) -> Result<(WebSocketStream, Response), Error> where R: IntoClientRequest + Unpin, { connect_async_with_tls_connector_and_config(request, connector, None).await } #[cfg(any( feature = "async-tls", feature = "tokio-native-tls", feature = "tokio-rustls-manual-roots", feature = "tokio-rustls-native-certs", feature = "tokio-rustls-webpki-roots", feature = "tokio-openssl" ))] /// Connect to a given URL using the provided TLS connector. pub async fn connect_async_with_tls_connector_and_config( request: R, connector: Option, config: Option, ) -> Result<(WebSocketStream, Response), Error> where R: IntoClientRequest + Unpin, { let request: Request = request.into_client_request()?; let domain = domain(&request)?; let port = port(&request)?; let try_socket = TcpStream::connect((domain.as_str(), port)).await; let socket = try_socket.map_err(Error::Io)?; client_async_tls_with_connector_and_config(request, socket, connector, config).await } use std::pin::Pin; use std::task::{Context, Poll}; pin_project_lite::pin_project! { /// Adapter for `tokio::io::AsyncRead` and `tokio::io::AsyncWrite` to provide /// the variants from the `futures` crate and the other way around. #[derive(Debug, Clone)] pub struct TokioAdapter { #[pin] inner: T, } } impl TokioAdapter { /// Creates a new `TokioAdapter` wrapping the provided value. pub fn new(inner: T) -> Self { Self { inner } } /// Consumes this `TokioAdapter`, returning the underlying value. pub fn into_inner(self) -> T { self.inner } /// Get a reference to the underlying value. pub fn get_ref(&self) -> &T { &self.inner } /// Get a mutable reference to the underlying value. pub fn get_mut(&mut self) -> &mut T { &mut self.inner } } impl AsyncRead for TokioAdapter { fn poll_read( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8], ) -> Poll> { let mut buf = tokio::io::ReadBuf::new(buf); match self.project().inner.poll_read(cx, &mut buf)? { Poll::Pending => Poll::Pending, Poll::Ready(_) => Poll::Ready(Ok(buf.filled().len())), } } } impl AsyncWrite for TokioAdapter { fn poll_write( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8], ) -> Poll> { self.project().inner.poll_write(cx, buf) } fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { self.project().inner.poll_flush(cx) } fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { self.project().inner.poll_shutdown(cx) } } impl tokio::io::AsyncRead for TokioAdapter { fn poll_read( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut tokio::io::ReadBuf<'_>, ) -> Poll> { let slice = buf.initialize_unfilled(); let n = match self.project().inner.poll_read(cx, slice)? { Poll::Pending => return Poll::Pending, Poll::Ready(n) => n, }; buf.advance(n); Poll::Ready(Ok(())) } } impl tokio::io::AsyncWrite for TokioAdapter { fn poll_write( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8], ) -> Poll> { self.project().inner.poll_write(cx, buf) } fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { self.project().inner.poll_flush(cx) } fn poll_shutdown( self: Pin<&mut Self>, cx: &mut Context<'_>, ) -> Poll> { self.project().inner.poll_close(cx) } }