From b2aabc1be118c26e8c2b5c45cd38d92927bf22a3 Mon Sep 17 00:00:00 2001 From: Kevin Flansburg Date: Fri, 15 Mar 2024 09:44:58 -0400 Subject: [PATCH] Introduce `http` feature for `http` crate types (#477) * http 1.1 * http feature flag * Fetcher http flag * Implement todos * Implement redirect / ws / abort signal * Add http tests to CI * Add Cf context to http::Request * Fix test working directories * Axum example * fix clippy in CI * Handle generic http_body return type * Documentation * Remove unwraps * Tweak introduction version in docs * Final touches --- .github/workflows/pullrequest.yml | 17 +- Cargo.lock | 494 +++++-------------------- Cargo.toml | 4 +- README.md | 37 ++ examples/{hyper => axum}/.gitignore | 0 examples/{hyper => axum}/Cargo.lock | 384 +++++++++---------- examples/{hyper => axum}/Cargo.toml | 11 +- examples/axum/README.md | 3 + examples/{hyper => axum}/package.json | 2 +- examples/axum/src/lib.rs | 22 ++ examples/{hyper => axum}/wrangler.toml | 2 +- examples/hyper/README.md | 3 - examples/hyper/src/lib.rs | 65 ---- package.json | 3 +- worker-macros/Cargo.toml | 1 + worker-macros/src/event.rs | 20 +- worker-macros/src/lib.rs | 9 +- worker-sandbox/Cargo.toml | 9 +- worker-sandbox/src/lib.rs | 63 +++- worker/Cargo.toml | 13 +- worker/src/abort.rs | 10 +- worker/src/cf.rs | 15 +- worker/src/d1/macros.rs | 2 +- worker/src/env.rs | 3 + worker/src/error.rs | 55 +++ worker/src/fetcher.rs | 50 ++- worker/src/http.rs | 11 + worker/src/http/body.rs | 134 +++++++ worker/src/http/header.rs | 31 ++ worker/src/http/redirect.rs | 41 ++ worker/src/http/request.rs | 81 ++++ worker/src/http/response.rs | 111 ++++++ worker/src/lib.rs | 70 ++++ worker/src/request.rs | 17 + worker/src/response.rs | 20 + worker/src/websocket.rs | 6 + 36 files changed, 1119 insertions(+), 700 deletions(-) rename examples/{hyper => axum}/.gitignore (100%) rename examples/{hyper => axum}/Cargo.lock (76%) rename examples/{hyper => axum}/Cargo.toml (54%) create mode 100644 examples/axum/README.md rename examples/{hyper => axum}/package.json (85%) create mode 100644 examples/axum/src/lib.rs rename examples/{hyper => axum}/wrangler.toml (85%) delete mode 100644 examples/hyper/README.md delete mode 100644 examples/hyper/src/lib.rs create mode 100644 worker/src/http/body.rs create mode 100644 worker/src/http/header.rs create mode 100644 worker/src/http/redirect.rs create mode 100644 worker/src/http/request.rs create mode 100644 worker/src/http/response.rs diff --git a/.github/workflows/pullrequest.yml b/.github/workflows/pullrequest.yml index ec77d4ea..7d58df99 100644 --- a/.github/workflows/pullrequest.yml +++ b/.github/workflows/pullrequest.yml @@ -20,7 +20,10 @@ jobs: run: cargo fmt --all -- --check - name: Check for idiomatic code - run: cargo clippy --all-features --all-targets --all -- -D warnings + run: cargo clippy --features d1,queue --all-targets --workspace -- -D warnings + + - name: Check for idiomatic code (http) + run: cargo clippy --all-features --package worker-sandbox --all-targets -- -D warnings test: name: Test runs-on: ubuntu-latest @@ -70,12 +73,10 @@ jobs: shell: bash run: npm ci - - name: Build worker - shell: bash - working-directory: ./worker-sandbox - run: NO_MINIFY=1 worker-build --dev - - name: Run tests shell: bash - working-directory: ./worker-sandbox - run: NODE_OPTIONS=--experimental-vm-modules npx vitest run + run: npm run test + + - name: Run tests (http) + shell: bash + run: npm run test-http diff --git a/Cargo.lock b/Cargo.lock index 0a3057bd..dd6eb558 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,9 +43,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.80" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" +checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" [[package]] name = "async-trait" @@ -64,6 +64,53 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "axum" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1236b4b292f6c4d6dc34604bb5120d85c3fe1d1aa596bd5cc52ca054d13e7b9e" +dependencies = [ + "async-trait", + "axum-core", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "sync_wrapper", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-core" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper", + "tower-layer", + "tower-service", +] + [[package]] name = "backtrace" version = "0.3.69" @@ -191,16 +238,6 @@ dependencies = [ "wasm-bindgen", ] -[[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.6" @@ -282,21 +319,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "encoding_rs" -version = "0.8.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" -dependencies = [ - "cfg-if", -] - -[[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.8" @@ -353,21 +375,6 @@ 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" @@ -469,7 +476,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d" dependencies = [ "fallible-iterator", - "indexmap 1.9.3", + "indexmap", "stable_deref_trait", ] @@ -479,37 +486,12 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" -[[package]] -name = "h2" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http 0.2.12", - "indexmap 2.2.5", - "slab", - "tokio", - "tokio-util", - "tracing", -] - [[package]] name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -[[package]] -name = "hashbrown" -version = "0.14.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" - [[package]] name = "heck" version = "0.3.3" @@ -540,17 +522,6 @@ dependencies = [ "digest", ] -[[package]] -name = "http" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - [[package]] name = "http" version = "1.1.0" @@ -564,74 +535,32 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.6" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" dependencies = [ "bytes", - "http 0.2.12", - "pin-project-lite", + "http", ] [[package]] -name = "httparse" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" - -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - -[[package]] -name = "hyper" -version = "0.14.28" +name = "http-body-util" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" +checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" dependencies = [ "bytes", - "futures-channel", "futures-core", - "futures-util", - "h2", - "http 0.2.12", + "http", "http-body", - "httparse", - "httpdate", - "itoa", "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", - "want", ] [[package]] -name = "hyper-on-workers" -version = "0.1.0" -dependencies = [ - "console_error_panic_hook", - "hyper", - "tokio", - "wasm-bindgen-futures", - "worker", -] - -[[package]] -name = "hyper-tls" -version = "0.5.0" +name = "httparse" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" -dependencies = [ - "bytes", - "hyper", - "native-tls", - "tokio", - "tokio-native-tls", -] +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" [[package]] name = "iana-time-zone" @@ -679,25 +608,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", - "hashbrown 0.12.3", + "hashbrown", ] -[[package]] -name = "indexmap" -version = "2.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" -dependencies = [ - "equivalent", - "hashbrown 0.14.3", -] - -[[package]] -name = "ipnet" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" - [[package]] name = "itoa" version = "1.0.10" @@ -798,16 +711,6 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" -[[package]] -name = "mime_guess" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" -dependencies = [ - "mime", - "unicase", -] - [[package]] name = "miniz_oxide" version = "0.7.2" @@ -828,24 +731,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "native-tls" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" -dependencies = [ - "lazy_static", - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -896,50 +781,6 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" -[[package]] -name = "openssl" -version = "0.10.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" -dependencies = [ - "bitflags 2.4.2", - "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.52", -] - -[[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.101" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dda2b0f344e78efc2facf7d195d098df0dd72151b26ab98da807afc26c198dff" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - [[package]] name = "overload" version = "0.1.1" @@ -1054,12 +895,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "pkg-config" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" - [[package]] name = "postgres-protocol" version = "0.6.6" @@ -1104,9 +939,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" dependencies = [ "unicode-ident", ] @@ -1199,49 +1034,6 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" -[[package]] -name = "reqwest" -version = "0.11.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6920094eb85afde5e4a138be3f2de8bbdf28000f0029e72c45025a56b042251" -dependencies = [ - "base64", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2", - "http 0.2.12", - "http-body", - "hyper", - "hyper-tls", - "ipnet", - "js-sys", - "log", - "mime", - "mime_guess", - "native-tls", - "once_cell", - "percent-encoding", - "pin-project-lite", - "rustls-pemfile", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper", - "system-configuration", - "tokio", - "tokio-native-tls", - "tokio-util", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-streams", - "web-sys", - "winreg", -] - [[package]] name = "retry" version = "2.0.0" @@ -1308,15 +1100,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "rustls-pemfile" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" -dependencies = [ - "base64", -] - [[package]] name = "rustls-pki-types" version = "1.3.1" @@ -1335,19 +1118,16 @@ dependencies = [ ] [[package]] -name = "ryu" -version = "1.0.17" +name = "rustversion" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" [[package]] -name = "schannel" -version = "0.1.23" +name = "ryu" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" -dependencies = [ - "windows-sys 0.52.0", -] +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" [[package]] name = "scoped-tls" @@ -1361,29 +1141,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "security-framework" -version = "2.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "serde" version = "1.0.197" @@ -1577,27 +1334,6 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" -[[package]] -name = "system-configuration" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "tar" version = "0.4.40" @@ -1623,18 +1359,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.57" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.57" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", @@ -1728,16 +1464,6 @@ dependencies = [ "syn 2.0.52", ] -[[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-postgres" version = "0.7.10" @@ -1786,6 +1512,26 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + [[package]] name = "tower-service" version = "0.3.2" @@ -1887,12 +1633,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "try-lock" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - [[package]] name = "tungstenite" version = "0.21.0" @@ -1902,7 +1642,7 @@ dependencies = [ "byteorder", "bytes", "data-encoding", - "http 1.1.0", + "http", "httparse", "log", "rand", @@ -1918,15 +1658,6 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" -[[package]] -name = "unicase" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] - [[package]] name = "unicode-bidi" version = "0.3.15" @@ -2010,12 +1741,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - [[package]] name = "version_check" version = "0.9.4" @@ -2050,15 +1775,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -2286,9 +2002,9 @@ dependencies = [ [[package]] name = "whoami" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fec781d48b41f8163426ed18e8fc2864c12937df9ce54c88ede7bd47270893e" +checksum = "a44ab49fad634e88f55bf8f9bb3abd2f27d7204172a112c7c9987e01c1c94ea9" dependencies = [ "redox_syscall", "wasite", @@ -2458,26 +2174,19 @@ version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" -[[package]] -name = "winreg" -version = "0.50.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - [[package]] name = "worker" version = "0.0.20" dependencies = [ "async-trait", + "axum", + "bytes", "chrono", "chrono-tz", "futures-channel", "futures-util", - "http 1.1.0", + "http", + "http-body", "js-sys", "matchit", "pin-project", @@ -2550,11 +2259,10 @@ dependencies = [ "futures-util", "getrandom", "hex", - "http 1.1.0", + "http", "md5", "rand", "regex", - "reqwest", "retry", "serde", "serde-wasm-bindgen 0.6.5", diff --git a/Cargo.toml b/Cargo.toml index 8b1bc936..502e7f20 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ members = [ "worker-sys", "examples/*", ] -exclude = ["examples/coredump"] +exclude = ["examples/coredump", "examples/axum"] resolver = "2" [workspace.dependencies] @@ -19,7 +19,7 @@ chrono = { version = "0.4.35", default-features = false, features = [ chrono-tz = { version = "0.8.4", default-features = false } futures-channel = "0.3.29" futures-util = { version = "0.3.29", default-features = false } -http = "1.0.0" +http = "1.1.0" js-sys = "0.3.66" wasm-bindgen = "0.2.91" wasm-bindgen-cli-support = "0.2.91" diff --git a/README.md b/README.md index 3796f946..d8ff131a 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,43 @@ pub async fn main(req: Request, env: Env, _ctx: worker::Context) -> Result`. +1. The expected return type for the fetch handler is `http::Response` where `B` can be any `http_body::Body`. +1. The argument for `Fetcher::fetch_request` is `http::Request`. +1. The return type of `Fetcher::fetch_request` is `Result>`. + +The end result is being able to use frameworks like `axum` directly (see [example](./examples/axum)): + +```rust +pub async fn root() -> &'static str { + "Hello Axum!" +} + +fn router() -> Router { + Router::new().route("/", get(root)) +} + +#[event(fetch)] +async fn fetch( + req: HttpRequest, + _env: Env, + _ctx: Context, +) -> Result> { + Ok(router().call(req).await?) +} +``` + +We also implement `try_from` between `worker::Request` and `http::Request`, and between `worker::Response` and `http::Response`. This allows you to convert your code incrementally if it is tightly coupled to the original types. + ### Or use the `Router`: Parameterize routes and access the parameter values from within a handler. Each handler function takes a diff --git a/examples/hyper/.gitignore b/examples/axum/.gitignore similarity index 100% rename from examples/hyper/.gitignore rename to examples/axum/.gitignore diff --git a/examples/hyper/Cargo.lock b/examples/axum/Cargo.lock similarity index 76% rename from examples/hyper/Cargo.lock rename to examples/axum/Cargo.lock index 794dcaf0..b2e58425 100644 --- a/examples/hyper/Cargo.lock +++ b/examples/axum/Cargo.lock @@ -4,13 +4,13 @@ version = 3 [[package]] name = "async-trait" -version = "0.1.68" +version = "0.1.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" +checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn", ] [[package]] @@ -19,6 +19,65 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "axum" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1236b4b292f6c4d6dc34604bb5120d85c3fe1d1aa596bd5cc52ca054d13e7b9e" +dependencies = [ + "async-trait", + "axum-core", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "sync_wrapper", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-core" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-on-workers" +version = "0.1.0" +dependencies = [ + "axum", + "console_error_panic_hook", + "tower-service", + "wasm-bindgen-futures", + "worker", + "worker-macros", +] + [[package]] name = "bumpalo" version = "3.13.0" @@ -27,9 +86,9 @@ checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" [[package]] name = "bytes" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "cfg-if" @@ -39,21 +98,20 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.24" +version = "0.4.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b" +checksum = "8eaf5903dcbc0a39312feb77df2ff4c76387d591b9fc7b04a238dcf8bb62639a" dependencies = [ "js-sys", - "num-integer", "num-traits", "wasm-bindgen", ] [[package]] name = "chrono-tz" -version = "0.6.3" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c39203181991a7dd4343b8005bd804e7a9a37afb8ac070e43771e8c820bbde" +checksum = "d59ae0466b83e838b81a54256c39d5d7c20b9d7daa10510a242d9b75abd5936e" dependencies = [ "chrono", "chrono-tz-build", @@ -62,9 +120,9 @@ dependencies = [ [[package]] name = "chrono-tz-build" -version = "0.0.3" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f509c3a87b33437b05e2458750a0700e5bdd6956176773e6c7d6dd15a283a0c" +checksum = "433e39f13c9a060046954e0592a8d0a4bcb1040125cbf91cb8ee58964cfb350f" dependencies = [ "parse-zoneinfo", "phf", @@ -89,62 +147,62 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "form_urlencoded" -version = "1.1.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] [[package]] name = "futures-channel" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" dependencies = [ "futures-core", ] [[package]] name = "futures-core" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" [[package]] name = "futures-io" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" [[package]] name = "futures-macro" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn", ] [[package]] name = "futures-sink" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" [[package]] name = "futures-task" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-util" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-core", "futures-io", @@ -159,9 +217,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.9" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" dependencies = [ "bytes", "fnv", @@ -170,54 +228,32 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.5" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" dependencies = [ "bytes", "http", - "pin-project-lite", ] [[package]] -name = "httparse" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" - -[[package]] -name = "httpdate" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" - -[[package]] -name = "hyper" -version = "0.14.26" +name = "http-body-util" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab302d72a6f11a3b910431ff93aae7e773078c769f0a3ef15fb9ec692ed147d4" +checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" dependencies = [ "bytes", - "futures-channel", "futures-core", - "futures-util", "http", "http-body", - "httparse", - "httpdate", - "itoa", "pin-project-lite", - "tokio", - "tower-service", - "tracing", - "want", ] [[package]] name = "idna" -version = "0.3.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -231,9 +267,9 @@ checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" [[package]] name = "js-sys" -version = "0.3.61" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] @@ -249,9 +285,9 @@ dependencies = [ [[package]] name = "matchit" -version = "0.4.6" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9376a4f0340565ad675d11fc1419227faf5f60cd7ac9cb2e7185a471f30af833" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" [[package]] name = "memchr" @@ -260,14 +296,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] -name = "num-integer" -version = "0.1.45" +name = "mime" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg", - "num-traits", -] +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "num-traits" @@ -295,9 +327,9 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.2.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "phf" @@ -335,7 +367,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1fb5f6f826b772a8d4c0394209441e7d37cbbb967ae9c7e0e8134365c9ee676" dependencies = [ "siphasher", - "uncased", ] [[package]] @@ -355,7 +386,7 @@ checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn", ] [[package]] @@ -372,18 +403,18 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "proc-macro2" -version = "1.0.58" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa1fb82fc0c281dd9671101b66b771ebbe1eaf967b96ac8740dcba4b70005ca8" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.27" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f4f29d145265ec1c483c7c654450edde0bfe043d3938d6972630663356d9500" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -418,6 +449,12 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + [[package]] name = "ryu" version = "1.0.13" @@ -426,9 +463,9 @@ checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" [[package]] name = "serde" -version = "1.0.163" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] @@ -444,15 +481,26 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "serde-wasm-bindgen" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", +] + [[package]] name = "serde_derive" -version = "1.0.163" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn", ] [[package]] @@ -466,6 +514,18 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + [[package]] name = "siphasher" version = "0.3.10" @@ -483,9 +543,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.109" +version = "2.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" dependencies = [ "proc-macro2", "quote", @@ -493,15 +553,10 @@ dependencies = [ ] [[package]] -name = "syn" -version = "2.0.16" +name = "sync_wrapper" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6f671d4b5ffdb8eadec19c0ae67fe2639df8684bd7bc4b83d986b8db549cf01" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" [[package]] name = "thiserror" @@ -520,7 +575,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn", ] [[package]] @@ -545,63 +600,35 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0aa32867d44e6f2ce3385e89dceb990188b8bb0fb25b0cf576647a6f98ac5105" dependencies = [ "autocfg", - "bytes", "pin-project-lite", - "tokio-macros", "windows-sys", ] [[package]] -name = "tokio-macros" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.16", -] - -[[package]] -name = "tower-service" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" - -[[package]] -name = "tracing" -version = "0.1.37" +name = "tower" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" dependencies = [ - "cfg-if", + "futures-core", + "futures-util", + "pin-project", "pin-project-lite", - "tracing-core", -] - -[[package]] -name = "tracing-core" -version = "0.1.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" -dependencies = [ - "once_cell", + "tower-layer", + "tower-service", ] [[package]] -name = "try-lock" -version = "0.2.4" +name = "tower-layer" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" [[package]] -name = "uncased" -version = "0.9.9" +name = "tower-service" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b9bc53168a4be7402ab86c3aad243a84dd7381d09be0eddc81280c1da95ca68" -dependencies = [ - "version_check", -] +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "unicode-bidi" @@ -626,36 +653,20 @@ dependencies = [ [[package]] name = "url" -version = "2.3.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", "idna", "percent-encoding", ] -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "want" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" -dependencies = [ - "log", - "try-lock", -] - [[package]] name = "wasm-bindgen" -version = "0.2.84" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -663,24 +674,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.84" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 1.0.109", + "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.34" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" dependencies = [ "cfg-if", "js-sys", @@ -690,9 +701,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.84" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -700,28 +711,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.84" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.84" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "wasm-streams" -version = "0.2.3" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bbae3363c08332cadccd13b67db371814cd214c2524020932f0804b8cf7c078" +checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129" dependencies = [ "futures-util", "js-sys", @@ -732,9 +743,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.61" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" dependencies = [ "js-sys", "wasm-bindgen", @@ -808,20 +819,24 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "worker" -version = "0.0.16" +version = "0.0.20" dependencies = [ "async-trait", + "axum", + "bytes", "chrono", "chrono-tz", "futures-channel", "futures-util", "http", + "http-body", "js-sys", "matchit", "pin-project", "serde", - "serde-wasm-bindgen", + "serde-wasm-bindgen 0.6.5", "serde_json", + "serde_urlencoded", "tokio", "url", "wasm-bindgen", @@ -841,7 +856,7 @@ checksum = "3d4b9fe1a87b7aef252fceb4f30bf6303036a5de329c81ccad9be9c35d1fdbc7" dependencies = [ "js-sys", "serde", - "serde-wasm-bindgen", + "serde-wasm-bindgen 0.5.0", "serde_json", "thiserror", "wasm-bindgen", @@ -850,32 +865,21 @@ dependencies = [ [[package]] name = "worker-macros" -version = "0.0.8" +version = "0.0.12" dependencies = [ "async-trait", "proc-macro2", "quote", - "syn 1.0.109", + "syn", "wasm-bindgen", "wasm-bindgen-futures", "wasm-bindgen-macro-support", "worker-sys", ] -[[package]] -name = "worker-rust" -version = "0.1.0" -dependencies = [ - "console_error_panic_hook", - "hyper", - "tokio", - "wasm-bindgen-futures", - "worker", -] - [[package]] name = "worker-sys" -version = "0.0.8" +version = "0.0.12" dependencies = [ "cfg-if", "js-sys", diff --git a/examples/hyper/Cargo.toml b/examples/axum/Cargo.toml similarity index 54% rename from examples/hyper/Cargo.toml rename to examples/axum/Cargo.toml index ec258b47..3f5d49ac 100644 --- a/examples/hyper/Cargo.toml +++ b/examples/axum/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "hyper-on-workers" +name = "axum-on-workers" version = "0.1.0" edition = "2021" @@ -14,8 +14,9 @@ wasm-opt = false crate-type = ["cdylib"] [dependencies] -worker = { workspace=true } -hyper = { version="0.14", default-features=false, features=['http1', 'client'] } -tokio = { version = "1.0", default-features=false, features=['io-util', 'macros']} +worker = { path="../../worker", features=['http'] } +worker-macros = { path="../../worker-macros", features=['http'] } +axum = { version = "0.7", default-features = false } +tower-service = "0.3.2" console_error_panic_hook = { version = "0.1.1" } -wasm-bindgen-futures = "0.4" +wasm-bindgen-futures = "0.4" \ No newline at end of file diff --git a/examples/axum/README.md b/examples/axum/README.md new file mode 100644 index 00000000..157be3fb --- /dev/null +++ b/examples/axum/README.md @@ -0,0 +1,3 @@ +# `axum` on Cloudflare Workers + +Demonstration of using the `axum` web framework for routing on Cloudflare Workers. diff --git a/examples/hyper/package.json b/examples/axum/package.json similarity index 85% rename from examples/hyper/package.json rename to examples/axum/package.json index 1c3490c8..af220808 100644 --- a/examples/hyper/package.json +++ b/examples/axum/package.json @@ -1,5 +1,5 @@ { - "name": "hyper-on-workers", + "name": "axum-on-workers", "version": "0.0.0", "private": true, "scripts": { diff --git a/examples/axum/src/lib.rs b/examples/axum/src/lib.rs new file mode 100644 index 00000000..0f3d326d --- /dev/null +++ b/examples/axum/src/lib.rs @@ -0,0 +1,22 @@ +use axum::{routing::get, Router}; +use tower_service::Service; +use worker::*; + +fn router() -> Router { + Router::new().route("/", get(root)) +} + +#[event(fetch)] +async fn fetch( + req: HttpRequest, + _env: Env, + _ctx: Context, +) -> Result> { + console_error_panic_hook::set_once(); + + Ok(router().call(req).await?) +} + +pub async fn root() -> &'static str { + "Hello Axum!" +} diff --git a/examples/hyper/wrangler.toml b/examples/axum/wrangler.toml similarity index 85% rename from examples/hyper/wrangler.toml rename to examples/axum/wrangler.toml index cc7d7e91..f434f523 100644 --- a/examples/hyper/wrangler.toml +++ b/examples/axum/wrangler.toml @@ -1,4 +1,4 @@ -name = "hyper-on-workers" +name = "axum-on-workers" main = "build/worker/shim.mjs" compatibility_date = "2023-03-22" diff --git a/examples/hyper/README.md b/examples/hyper/README.md deleted file mode 100644 index 513c3e90..00000000 --- a/examples/hyper/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# `hyper` on Cloudflare Workers - -Demonstration of using `hyper::client::conn` (the low-level client) on Cloudflare Workers using TCP Sockets. diff --git a/examples/hyper/src/lib.rs b/examples/hyper/src/lib.rs deleted file mode 100644 index b45eb7d2..00000000 --- a/examples/hyper/src/lib.rs +++ /dev/null @@ -1,65 +0,0 @@ -use std::str::Utf8Error; - -use worker::*; - -pub use console_error_panic_hook::set_once as set_panic_hook; - -async fn make_request( - mut sender: hyper::client::conn::SendRequest, - request: hyper::Request, -) -> Result { - // Send and recieve HTTP request - let hyper_response = sender - .send_request(request) - .await - .map_err(map_hyper_error)?; - - // Convert back to worker::Response - let buf = hyper::body::to_bytes(hyper_response) - .await - .map_err(map_hyper_error)?; - let text = std::str::from_utf8(&buf).map_err(map_utf8_error)?; - let mut response = Response::ok(text)?; - response - .headers_mut() - .append("Content-Type", "text/html; charset=utf-8")?; - Ok(response) -} -#[event(fetch)] -async fn main(_req: Request, _env: Env, _ctx: Context) -> worker::Result { - set_panic_hook(); - - let socket = Socket::builder() - .secure_transport(SecureTransport::On) - .connect("example.com", 443)?; - - let (sender, connection) = hyper::client::conn::handshake(socket) - .await - .map_err(map_hyper_error)?; - - let request = hyper::Request::builder() - .header("Host", "example.com") - .method("GET") - .body(hyper::Body::from("")) - .map_err(map_hyper_http_error)?; - - tokio::select!( - res = connection => { - console_error!("Connection exited: {:?}", res); - Err(worker::Error::RustError("Connection exited".to_string())) - }, - result = make_request(sender, request) => result - ) -} - -fn map_utf8_error(error: Utf8Error) -> worker::Error { - worker::Error::RustError(format!("Utf8Error: {:?}", error)) -} - -fn map_hyper_error(error: hyper::Error) -> worker::Error { - worker::Error::RustError(format!("hyper::Error: {:?}", error)) -} - -fn map_hyper_http_error(error: hyper::http::Error) -> worker::Error { - worker::Error::RustError(format!("hyper::http::Error: {:?}", error)) -} diff --git a/package.json b/package.json index 1aa26614..5cab54ff 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "vitest": "^0.32.4" }, "scripts": { - "test": "cd worker-sandbox && vitest" + "test": "cd worker-sandbox && NO_MINIFY=1 worker-build --dev && NODE_OPTIONS=--experimental-vm-modules npx vitest run", + "test-http": "cd worker-sandbox && NO_MINIFY=1 worker-build --dev --features http && NODE_OPTIONS=--experimental-vm-modules npx vitest run" } } diff --git a/worker-macros/Cargo.toml b/worker-macros/Cargo.toml index ee885522..e91d3177 100644 --- a/worker-macros/Cargo.toml +++ b/worker-macros/Cargo.toml @@ -23,3 +23,4 @@ quote = "1.0.28" [features] queue = [] +http = [] diff --git a/worker-macros/src/event.rs b/worker-macros/src/event.rs index dfa47e8e..eb92188e 100644 --- a/worker-macros/src/event.rs +++ b/worker-macros/src/event.rs @@ -2,7 +2,7 @@ use proc_macro::TokenStream; use quote::quote; use syn::{parse_macro_input, punctuated::Punctuated, token::Comma, Ident, ItemFn}; -pub fn expand_macro(attr: TokenStream, item: TokenStream) -> TokenStream { +pub fn expand_macro(attr: TokenStream, item: TokenStream, http: bool) -> TokenStream { let attrs: Punctuated = parse_macro_input!(attr with Punctuated::parse_terminated); @@ -61,6 +61,21 @@ pub fn expand_macro(attr: TokenStream, item: TokenStream) -> TokenStream { } }; + let fetch_invoke = if http { + quote! ( + match ::worker::request_from_wasm(req) { + Ok(request) => match #input_fn_ident(request, env, ctx).await.map(::worker::response_to_wasm) { + Ok(Ok(response)) => Ok(response), + Ok(Err(e)) => Err(e), + Err(e) => Err(e) + }, + Err(e) => Err(e) + } + ) + } else { + quote!(#input_fn_ident(::worker::Request::from(req), env, ctx).await.map(::worker::worker_sys::web_sys::Response::from)) + }; + // create a new "main" function that takes the worker_sys::Request, and calls the // original attributed function, passing in a converted worker::Request let wrapper_fn = quote! { @@ -70,8 +85,9 @@ pub fn expand_macro(attr: TokenStream, item: TokenStream) -> TokenStream { ctx: ::worker::worker_sys::Context ) -> ::worker::worker_sys::web_sys::Response { let ctx = worker::Context::new(ctx); + let result = #fetch_invoke; // get the worker::Result by calling the original fn - match #input_fn_ident(::worker::Request::from(req), env, ctx).await.map(::worker::worker_sys::web_sys::Response::from) { + match result { Ok(res) => res, Err(e) => { ::worker::console_error!("{}", &e); diff --git a/worker-macros/src/lib.rs b/worker-macros/src/lib.rs index 9194caa9..c0f1e3fc 100644 --- a/worker-macros/src/lib.rs +++ b/worker-macros/src/lib.rs @@ -10,7 +10,14 @@ pub fn durable_object(_attr: TokenStream, item: TokenStream) -> TokenStream { .into() } +#[cfg(feature = "http")] #[proc_macro_attribute] pub fn event(attr: TokenStream, item: TokenStream) -> TokenStream { - event::expand_macro(attr, item) + event::expand_macro(attr, item, true) +} + +#[cfg(not(feature = "http"))] +#[proc_macro_attribute] +pub fn event(attr: TokenStream, item: TokenStream) -> TokenStream { + event::expand_macro(attr, item, false) } diff --git a/worker-sandbox/Cargo.toml b/worker-sandbox/Cargo.toml index 238be9d5..f13b5066 100644 --- a/worker-sandbox/Cargo.toml +++ b/worker-sandbox/Cargo.toml @@ -14,6 +14,7 @@ path = "src/lib.rs" [features] default = ["console_error_panic_hook"] +http = ["worker/http"] [dependencies] futures-channel.workspace = true @@ -27,7 +28,7 @@ cfg-if = "1.0.0" console_error_panic_hook = { version = "0.1.7", optional = true } getrandom = { version = "0.2.10", features = ["js"] } hex = "0.4.3" -http = "1" +http.workspace=true regex = "1.8.4" serde = { version = "1.0.164", features = ["derive"] } serde_json = "1.0.96" @@ -43,12 +44,6 @@ futures-channel = { version = "0.3.29", features = ["sink"] } futures-util = { version = "0.3.29", default-features = false, features = [ "sink", ] } -reqwest = { version = "0.11.18", features = [ - "blocking", - "json", - "multipart", - "stream", -] } tokio = { version = "1.28.2", features = ["macros", "rt", "test-util"] } tungstenite = "0.21" retry = "2.0.0" diff --git a/worker-sandbox/src/lib.rs b/worker-sandbox/src/lib.rs index 4beff7b5..8e18e040 100644 --- a/worker-sandbox/src/lib.rs +++ b/worker-sandbox/src/lib.rs @@ -1,3 +1,9 @@ +use blake2::{Blake2b512, Digest}; +use futures_util::{future::Either, StreamExt, TryStreamExt}; +use rand::Rng; +use serde::{Deserialize, Serialize}; +#[cfg(feature = "http")] +use std::convert::TryInto; use std::{ sync::{ atomic::{AtomicBool, Ordering}, @@ -5,11 +11,6 @@ use std::{ }, time::Duration, }; - -use blake2::{Blake2b512, Digest}; -use futures_util::{future::Either, StreamExt, TryStreamExt}; -use rand::Rng; -use serde::{Deserialize, Serialize}; use uuid::Uuid; use worker::*; @@ -92,15 +93,33 @@ pub fn start() { GLOBAL_STATE.store(true, Ordering::SeqCst); } +#[cfg(feature = "http")] +type HandlerRequest = HttpRequest; +#[cfg(not(feature = "http"))] +type HandlerRequest = Request; +#[cfg(feature = "http")] +type HandlerResponse = HttpResponse; +#[cfg(not(feature = "http"))] +type HandlerResponse = Response; + #[event(fetch)] -pub async fn main(req: Request, env: Env, _ctx: worker::Context) -> Result { +pub async fn main( + request: HandlerRequest, + env: Env, + _ctx: worker::Context, +) -> Result { let data = SomeSharedData { regex: regex::Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap(), }; let router = Router::with_data(data); // if no data is needed, pass `()` or any other valid data - router + #[cfg(feature = "http")] + let req: Request = request.try_into()?; + #[cfg(not(feature = "http"))] + let req = request; + + let worker_response = router .get("/request", handle_a_request) // can pass a fn pointer to keep routes tidy .get_async("/async-request", handle_async_request) .get("/websocket", |_, ctx| { @@ -670,14 +689,33 @@ pub async fn main(req: Request, env: Env, _ctx: worker::Context) -> Result::try_into(response)?); + #[cfg(not(feature="http"))] + let result = Ok(response); + + result }) .get_async("/remote-by-path", |req, ctx| async move { let fetcher = ctx.service("remote")?; let mut init = RequestInit::new(); init.with_method(Method::Post); + let response = fetcher.fetch(req.url()?.to_string(), Some(init)).await?; + + #[cfg(feature="http")] + let result = Ok(TryInto::::try_into(response)?); + #[cfg(not(feature="http"))] + let result = Ok(response); - fetcher.fetch(req.url()?.to_string(), Some(init)).await + result }) .post_async("/queue/send/:id", |_req, ctx| async move { let id = match ctx.param("id").map(|id|Uuid::try_parse(id).ok()).and_then(|u|u) { @@ -733,7 +771,12 @@ pub async fn main(req: Request, env: Env, _ctx: worker::Context) -> Result(req: Request, _ctx: RouteContext) -> Result { diff --git a/worker/Cargo.toml b/worker/Cargo.toml index a5f9f0f8..d32e3b21 100644 --- a/worker/Cargo.toml +++ b/worker/Cargo.toml @@ -11,8 +11,12 @@ readme = "../README.md" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[package.metadata.docs.rs] +all-features = true + [dependencies] async-trait.workspace = true +bytes = "1.5" chrono.workspace = true chrono-tz.workspace = true futures-channel.workspace = true @@ -20,7 +24,8 @@ futures-util.workspace = true wasm-bindgen.workspace = true wasm-bindgen-futures.workspace = true js-sys.workspace = true -http = "1" +http.workspace = true +http-body = "1" matchit = "0.7" pin-project = "1.1.0" serde = { version = "1.0.164", features = ["derive"] } @@ -49,6 +54,12 @@ default-features = false features = ["js"] optional = true +[dependencies.axum] +version = "0.7" +optional = true +default-features = false + [features] queue = ["worker-macros/queue", "worker-sys/queue"] d1 = ["worker-sys/d1"] +http = ["worker-macros/http", "dep:axum"] diff --git a/worker/src/abort.rs b/worker/src/abort.rs index 12a43b52..ad4d69c1 100644 --- a/worker/src/abort.rs +++ b/worker/src/abort.rs @@ -37,11 +37,14 @@ impl Default for AbortController { /// An interface representing a signal that can be passed to cancellable operations, primarily a /// [Fetch](crate::Fetch) request. -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct AbortSignal { inner: web_sys::AbortSignal, } +unsafe impl Send for AbortSignal {} +unsafe impl Sync for AbortSignal {} + impl AbortSignal { /// A [bool] indicating if the operation that the signal is used for has been aborted. pub fn aborted(&self) -> bool { @@ -63,6 +66,11 @@ impl AbortSignal { let reason = reason.into(); Self::from(web_sys::AbortSignal::abort_with_reason(&reason)) } + + #[cfg(feature = "http")] + pub(crate) fn inner(&self) -> &web_sys::AbortSignal { + &self.inner + } } impl From for AbortSignal { diff --git a/worker/src/cf.rs b/worker/src/cf.rs index 4079ac92..1cafc35f 100644 --- a/worker/src/cf.rs +++ b/worker/src/cf.rs @@ -1,12 +1,25 @@ /// In addition to the methods on the `Request` struct, the `Cf` struct on an inbound Request contains information about the request provided by Cloudflare’s edge. /// /// [Details](https://developers.cloudflare.com/workers/runtime-apis/request#incomingrequestcfproperties) -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Cf { inner: worker_sys::IncomingRequestCfProperties, } +unsafe impl Send for Cf {} +unsafe impl Sync for Cf {} + impl Cf { + #[cfg(feature = "http")] + pub(crate) fn new(inner: worker_sys::IncomingRequestCfProperties) -> Self { + Self { inner } + } + + #[cfg(feature = "http")] + pub(crate) fn inner(&self) -> &worker_sys::IncomingRequestCfProperties { + &self.inner + } + /// The three-letter airport code (e.g. `ATX`, `LUX`) representing /// the colocation which processed the request pub fn colo(&self) -> String { diff --git a/worker/src/d1/macros.rs b/worker/src/d1/macros.rs index 14ed269d..e32fa31d 100644 --- a/worker/src/d1/macros.rs +++ b/worker/src/d1/macros.rs @@ -1,4 +1,4 @@ -/// Prepare a D1 query from the provided D1Database, query string, and optional query parameters. +/// **Requires** `d1` feature. Prepare a D1 query from the provided D1Database, query string, and optional query parameters. /// /// Any parameter provided is required to implement [`serde::Serialize`] to be used. /// diff --git a/worker/src/env.rs b/worker/src/env.rs index 64a66a62..0ea2f107 100644 --- a/worker/src/env.rs +++ b/worker/src/env.rs @@ -15,6 +15,9 @@ extern "C" { pub type Env; } +unsafe impl Send for Env {} +unsafe impl Sync for Env {} + impl Env { /// Access a binding that does not have a wrapper in workers-rs. Useful for internal-only or /// unstable bindings. diff --git a/worker/src/error.rs b/worker/src/error.rs index f16c712f..b7287e8d 100644 --- a/worker/src/error.rs +++ b/worker/src/error.rs @@ -8,6 +8,9 @@ pub enum Error { BodyUsed, Json((String, u16)), JsError(String), + #[cfg(feature = "http")] + Http(http::Error), + Infallible, Internal(JsValue), Io(std::io::Error), BindingError(String), @@ -17,8 +20,54 @@ pub enum Error { SerdeJsonError(serde_json::Error), #[cfg(feature = "queue")] SerdeWasmBindgenError(serde_wasm_bindgen::Error), + #[cfg(feature = "http")] + StatusCode(http::status::InvalidStatusCode), #[cfg(feature = "d1")] D1(crate::d1::D1Error), + Utf8Error(std::str::Utf8Error), +} + +unsafe impl Sync for Error {} +unsafe impl Send for Error {} + +#[cfg(feature = "http")] +impl From for Error { + fn from(value: http::Error) -> Self { + Self::Http(value) + } +} + +#[cfg(feature = "http")] +impl From for Error { + fn from(value: http::status::InvalidStatusCode) -> Self { + Self::StatusCode(value) + } +} + +#[cfg(feature = "http")] +impl From for Error { + fn from(value: http::header::InvalidHeaderName) -> Self { + Self::RustError(format!("Invalid header name: {:?}", value)) + } +} + +#[cfg(feature = "http")] +impl From for Error { + fn from(value: http::header::InvalidHeaderValue) -> Self { + Self::RustError(format!("Invalid header value: {:?}", value)) + } +} + +impl From for Error { + fn from(value: std::str::Utf8Error) -> Self { + Self::Utf8Error(value) + } +} + +impl From for Error { + fn from(_value: core::convert::Infallible) -> Self { + Error::Infallible + } } impl From for Error { @@ -63,6 +112,9 @@ impl std::fmt::Display for Error { Error::JsError(s) | Error::RustError(s) => { write!(f, "{s}") } + #[cfg(feature = "http")] + Error::Http(e) => write!(f, "http::Error: {e}"), + Error::Infallible => write!(f, "infallible"), Error::Internal(_) => write!(f, "unrecognized JavaScript object"), Error::Io(e) => write!(f, "IO Error: {e}"), Error::BindingError(name) => write!(f, "no binding found for `{name}`"), @@ -71,8 +123,11 @@ impl std::fmt::Display for Error { Error::SerdeJsonError(e) => write!(f, "Serde Error: {e}"), #[cfg(feature = "queue")] Error::SerdeWasmBindgenError(e) => write!(f, "Serde Error: {e}"), + #[cfg(feature = "http")] + Error::StatusCode(e) => write!(f, "{e}"), #[cfg(feature = "d1")] Error::D1(e) => write!(f, "D1: {e:#?}"), + Error::Utf8Error(e) => write!(f, "{e}"), } } } diff --git a/worker/src/fetcher.rs b/worker/src/fetcher.rs index 7de8eb59..eb35531d 100644 --- a/worker/src/fetcher.rs +++ b/worker/src/fetcher.rs @@ -1,18 +1,35 @@ +use crate::{env::EnvBinding, RequestInit, Result}; +#[cfg(feature = "http")] +use std::convert::TryInto; use wasm_bindgen::{JsCast, JsValue}; use wasm_bindgen_futures::JsFuture; -use crate::{env::EnvBinding, Request, RequestInit, Response, Result}; - +#[cfg(feature = "http")] +use crate::{HttpRequest, HttpResponse}; +use crate::{Request, Response}; /// A struct for invoking fetch events to other Workers. pub struct Fetcher(worker_sys::Fetcher); +#[cfg(not(feature = "http"))] +type FetchResponseType = Response; +#[cfg(feature = "http")] +type FetchResponseType = HttpResponse; + +#[cfg(not(feature = "http"))] +type FetchRequestType = Request; +#[cfg(feature = "http")] +type FetchRequestType = HttpRequest; + impl Fetcher { /// Invoke a fetch event in a worker with a url and optionally a [RequestInit]. + /// + /// Return type is [`Response`](crate::Response) unless `http` feature is enabled + /// and then it is [`http::Response`]. pub async fn fetch( &self, url: impl Into, init: Option, - ) -> Result { + ) -> Result { let path = url.into(); let promise = match init { Some(ref init) => self.0.fetch_with_str_and_init(&path, &init.into()), @@ -20,14 +37,33 @@ impl Fetcher { }; let resp_sys: web_sys::Response = JsFuture::from(promise).await?.dyn_into()?; - Ok(Response::from(resp_sys)) + #[cfg(not(feature = "http"))] + let result = Ok(Response::from(resp_sys)); + #[cfg(feature = "http")] + let result = crate::response_from_wasm(resp_sys); + result } /// Invoke a fetch event with an existing [Request]. - pub async fn fetch_request(&self, request: Request) -> Result { - let promise = self.0.fetch(request.inner()); + /// + /// Argument type is [`Request`](crate::Request) unless `http` feature is enabled + /// and then it is [`http::Request`]. + /// + /// Return type is [`Response`](crate::Response) unless `http` feature is enabled + /// and then it is [`http::Response`]. + pub async fn fetch_request(&self, request: FetchRequestType) -> Result { + #[cfg(feature = "http")] + let req = TryInto::::try_into(request)?; + #[cfg(not(feature = "http"))] + let req = request; + let promise = self.0.fetch(req.inner()); let resp_sys: web_sys::Response = JsFuture::from(promise).await?.dyn_into()?; - Ok(Response::from(resp_sys)) + let response = Response::from(resp_sys); + #[cfg(feature = "http")] + let result = response.try_into(); + #[cfg(not(feature = "http"))] + let result = Ok(response); + result } } diff --git a/worker/src/http.rs b/worker/src/http.rs index 399f8044..408e356e 100644 --- a/worker/src/http.rs +++ b/worker/src/http.rs @@ -1,3 +1,14 @@ +#[cfg(feature = "http")] +pub mod body; +#[cfg(feature = "http")] +mod header; +#[cfg(feature = "http")] +mod redirect; +#[cfg(feature = "http")] +pub mod request; +#[cfg(feature = "http")] +pub mod response; + /// A [`Method`](https://developer.mozilla.org/en-US/docs/Web/API/Request/method) representation /// used on Request objects. #[derive(Default, Debug, Clone, PartialEq, Hash, Eq)] diff --git a/worker/src/http/body.rs b/worker/src/http/body.rs new file mode 100644 index 00000000..a0fb8492 --- /dev/null +++ b/worker/src/http/body.rs @@ -0,0 +1,134 @@ +use std::{ + pin::Pin, + task::{Context, Poll}, +}; +use wasm_bindgen::JsCast; +use wasm_streams::readable::IntoStream; + +use crate::Error; +use bytes::Bytes; +use futures_util::TryStream; +use futures_util::TryStreamExt; +use futures_util::{stream::FusedStream, Stream, StreamExt}; +use http_body::{Body as HttpBody, Frame}; +use js_sys::Uint8Array; + +#[derive(Debug)] +pub struct Body(Option>); + +unsafe impl Sync for Body {} +unsafe impl Send for Body {} + +impl Body { + pub fn new(stream: web_sys::ReadableStream) -> Self { + Self(Some( + wasm_streams::ReadableStream::from_raw(stream.unchecked_into()).into_stream(), + )) + } + + pub fn into_inner(self) -> Option { + self.0 + .map(|s| wasm_streams::ReadableStream::from_stream(s).into_raw()) + } + + pub fn empty() -> Self { + Self(None) + } + + /// Create a `Body` using a [`Stream`](futures_util::stream::Stream) + pub fn from_stream(stream: S) -> Result + where + S: TryStream + 'static, + S::Ok: Into>, + S::Error: std::fmt::Debug, + { + let js_stream = stream + .map_ok(|item| -> Vec { item.into() }) + .map_ok(|chunk| { + let array = Uint8Array::new_with_length(chunk.len() as _); + array.copy_from(&chunk); + array.into() + }) + .map_err(|err| crate::Error::RustError(format!("{:?}", err))) + .map_err(|e| wasm_bindgen::JsValue::from(e.to_string())); + + let stream = wasm_streams::ReadableStream::from_stream(js_stream); + let stream: web_sys::ReadableStream = stream.into_raw().dyn_into().unwrap(); + + Ok(Self::new(stream)) + } +} + +impl HttpBody for Body { + type Data = Bytes; + type Error = Error; + + #[inline] + fn poll_frame( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll, Self::Error>>> { + if let Some(ref mut stream) = &mut self.0 { + stream + .poll_next_unpin(cx) + .map_ok(|buf| { + let bytes = Bytes::copy_from_slice(&js_sys::Uint8Array::from(buf).to_vec()); + Frame::data(bytes) + }) + .map_err(Error::Internal) + } else { + Poll::Ready(None) + } + } + + #[inline] + fn size_hint(&self) -> http_body::SizeHint { + let mut hint = http_body::SizeHint::new(); + if let Some(ref stream) = self.0 { + let (lower, upper) = stream.size_hint(); + + hint.set_lower(lower as u64); + if let Some(upper) = upper { + hint.set_upper(upper as u64); + } + } else { + hint.set_lower(0); + hint.set_upper(0); + } + hint + } + + fn is_end_stream(&self) -> bool { + if let Some(ref stream) = self.0 { + stream.is_terminated() + } else { + true + } + } +} + +impl Stream for Body { + type Item = Result; + + #[inline] + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + self.poll_frame(cx).map(|o| { + if let Some(r) = o { + match r { + Ok(f) => { + if f.is_data() { + let b = f.into_data().unwrap(); + Some(Ok(b)) + } else { + // Not sure how to handle trailers in Stream + None + } + } + Err(_) => Some(Err(Error::RustError("Error polling body".to_owned()))), + } + } else { + None + } + }) + } +} diff --git a/worker/src/http/header.rs b/worker/src/http/header.rs new file mode 100644 index 00000000..09c76c2e --- /dev/null +++ b/worker/src/http/header.rs @@ -0,0 +1,31 @@ +use crate::Result; +use http::{HeaderMap, HeaderName, HeaderValue}; +use js_sys::Array; +use worker_sys::ext::HeadersExt; + +pub(crate) fn header_map_from_web_sys_headers( + from_headers: web_sys::Headers, + to_headers: &mut HeaderMap, +) -> Result<()> { + // Header.entries() doesn't error: https://developer.mozilla.org/en-US/docs/Web/API/Headers/entries + for res in from_headers.entries()?.into_iter() { + // The entries iterator.next() will always return a proper value: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols + let a: Array = res?.into(); + // The entries iterator always returns an array[2] of strings + let key = a.get(0).as_string().unwrap(); + let value = a.get(1).as_string().unwrap(); + to_headers.append( + HeaderName::from_bytes(key.as_bytes())?, + HeaderValue::from_str(&value)?, + ); + } + Ok(()) +} + +pub(crate) fn web_sys_headers_from_header_map(headers: &HeaderMap) -> Result { + let output = web_sys::Headers::new()?; + for (key, value) in headers.iter() { + output.append(key.as_str(), std::str::from_utf8(value.as_bytes())?)?; + } + Ok(output) +} diff --git a/worker/src/http/redirect.rs b/worker/src/http/redirect.rs new file mode 100644 index 00000000..946134f6 --- /dev/null +++ b/worker/src/http/redirect.rs @@ -0,0 +1,41 @@ +#[derive(Default, Debug, Clone, Copy, PartialEq)] +pub enum RequestRedirect { + Error, + #[default] + Follow, + Manual, +} + +unsafe impl Send for RequestRedirect {} +unsafe impl Sync for RequestRedirect {} + +impl From for &str { + fn from(redirect: RequestRedirect) -> Self { + match redirect { + RequestRedirect::Error => "error", + RequestRedirect::Follow => "follow", + RequestRedirect::Manual => "manual", + } + } +} + +impl From for web_sys::RequestRedirect { + fn from(redir: RequestRedirect) -> Self { + match redir { + RequestRedirect::Error => web_sys::RequestRedirect::Error, + RequestRedirect::Follow => web_sys::RequestRedirect::Follow, + RequestRedirect::Manual => web_sys::RequestRedirect::Manual, + } + } +} + +impl From for RequestRedirect { + fn from(redir: web_sys::RequestRedirect) -> Self { + match redir { + web_sys::RequestRedirect::Error => RequestRedirect::Error, + web_sys::RequestRedirect::Follow => RequestRedirect::Follow, + web_sys::RequestRedirect::Manual => RequestRedirect::Manual, + _ => panic!("unknown redirect"), + } + } +} diff --git a/worker/src/http/request.rs b/worker/src/http/request.rs new file mode 100644 index 00000000..59798e12 --- /dev/null +++ b/worker/src/http/request.rs @@ -0,0 +1,81 @@ +use crate::http::body::Body; +use crate::Cf; +use crate::Result; +use crate::{http::redirect::RequestRedirect, AbortSignal}; +use worker_sys::ext::RequestExt; + +use crate::http::header::{header_map_from_web_sys_headers, web_sys_headers_from_header_map}; + +fn version_from_string(version: &str) -> http::Version { + match version { + "HTTP/0.9" => http::Version::HTTP_09, + "HTTP/1.0" => http::Version::HTTP_10, + "HTTP/1.1" => http::Version::HTTP_11, + "HTTP/2" => http::Version::HTTP_2, + "HTTP/3" => http::Version::HTTP_3, + _ => unreachable!("no other versions exist"), + } +} + +/// **Requires** `http` feature. Convert [`web_sys::Request`](web_sys::Request) +/// to [`worker::HttpRequest`](worker::HttpRequest) +pub fn from_wasm(req: web_sys::Request) -> Result> { + let mut builder = http::request::Builder::new() + .uri(req.url()) + .extension(AbortSignal::from(req.signal())) + .extension(RequestRedirect::from(req.redirect())) + .method(&*req.method()); + + if let Some(headers) = builder.headers_mut() { + header_map_from_web_sys_headers(req.headers(), headers)?; + } + + if let Some(cf) = req.cf() { + builder = builder + .version(version_from_string(&cf.http_protocol())) + .extension(Cf::new(cf)); + } + + Ok(if let Some(body) = req.body() { + builder.body(Body::new(body))? + } else { + builder.body(Body::empty())? + }) +} + +/// **Requires** `http` feature. Convert [`worker::HttpRequest`](worker::HttpRequest) +/// to [`web_sys::Request`](web_sys::Request) +pub fn to_wasm(mut req: http::Request) -> Result { + let mut init = web_sys::RequestInit::new(); + init.method(req.method().as_str()); + let headers = web_sys_headers_from_header_map(req.headers())?; + init.headers(headers.as_ref()); + let uri = req.uri().to_string(); + + let signal = req.extensions_mut().remove::(); + init.signal(signal.as_ref().map(|s| s.inner())); + + if let Some(redirect) = req.extensions_mut().remove::() { + init.redirect(redirect.into()); + } + + if let Some(cf) = req.extensions_mut().remove::() { + // TODO: this should be handled in worker-sys + let r = ::js_sys::Reflect::set( + init.as_ref(), + &wasm_bindgen::JsValue::from("cf"), + &wasm_bindgen::JsValue::from(cf.inner()), + ); + debug_assert!( + r.is_ok(), + "setting properties should never fail on our dictionary objects" + ); + let _ = r; + } + + if let Some(readable_stream) = req.into_body().into_inner() { + init.body(Some(readable_stream.as_ref())); + } + + Ok(web_sys::Request::new_with_str_and_init(&uri, &init)?) +} diff --git a/worker/src/http/response.rs b/worker/src/http/response.rs new file mode 100644 index 00000000..1b6022db --- /dev/null +++ b/worker/src/http/response.rs @@ -0,0 +1,111 @@ +use super::header::{header_map_from_web_sys_headers, web_sys_headers_from_header_map}; +use crate::http::body::Body; +use crate::HttpResponse; +use crate::Result; +use crate::WebSocket; +use bytes::Bytes; +use futures_util::Stream; +use js_sys::Uint8Array; +use pin_project::pin_project; +use std::pin::Pin; +use std::task::Context; +use std::task::Poll; +use wasm_bindgen::JsValue; +use worker_sys::ext::ResponseExt; +use worker_sys::ext::ResponseInitExt; + +#[pin_project] +struct BodyStream { + #[pin] + inner: B, +} + +impl BodyStream { + fn new(inner: B) -> Self { + Self { inner } + } +} + +impl> Stream for BodyStream { + type Item = std::result::Result; + + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + let this = self.project(); + let inner: Pin<&mut B> = this.inner; + inner.poll_frame(cx).map(|o| { + if let Some(r) = o { + match r { + Ok(f) => { + if f.is_data() { + // Should not be Err after checking on previous line + let b = f.into_data().unwrap(); + let array = Uint8Array::new_with_length(b.len() as _); + array.copy_from(&b); + Some(Ok(array.into())) + } else { + None + } + } + Err(_) => Some(Err(JsValue::from_str("Error polling body"))), + } + } else { + None + } + }) + } + + fn size_hint(&self) -> (usize, Option) { + let hint = self.inner.size_hint(); + (hint.lower() as usize, hint.upper().map(|u| u as usize)) + } +} + +/// **Requires** `http` feature. Convert generic [`http::Response`](worker::HttpResponse) +/// to [`web_sys::Resopnse`](web_sys::Response) where `B` can be any [`http_body::Body`](http_body::Body) +pub fn to_wasm(mut res: http::Response) -> Result +where + B: http_body::Body + 'static, +{ + let mut init = web_sys::ResponseInit::new(); + init.status(res.status().as_u16()); + let headers = web_sys_headers_from_header_map(res.headers())?; + init.headers(headers.as_ref()); + if let Some(ws) = res.extensions_mut().remove::() { + init.websocket(ws.as_ref()); + } + + let body = res.into_body(); + // I'm not sure how we are supposed to determine if there is no + // body for an `http::Response`, seems like this may be the only + // option given the trait? This appears to work for things like + // `hyper::Empty`. + let readable_stream = if body.is_end_stream() { + None + } else { + let stream = BodyStream::new(body); + Some(wasm_streams::ReadableStream::from_stream(stream).into_raw()) + }; + + Ok(web_sys::Response::new_with_opt_readable_stream_and_init( + readable_stream.as_ref(), + &init, + )?) +} + +/// **Requires** `http` feature. Convert [`web_sys::Resopnse`](web_sys::Response) +/// to [`worker::HttpResponse`](worker::HttpResponse) +pub fn from_wasm(res: web_sys::Response) -> Result { + let mut builder = + http::response::Builder::new().status(http::StatusCode::from_u16(res.status())?); + if let Some(headers) = builder.headers_mut() { + header_map_from_web_sys_headers(res.headers(), headers)?; + } + if let Some(ws) = res.websocket() { + builder = builder.extension(WebSocket::from(ws)); + } + Ok(if let Some(body) = res.body() { + builder.body(Body::new(body))? + } else { + builder.body(Body::empty())? + }) +} diff --git a/worker/src/lib.rs b/worker/src/lib.rs index 9159a5c0..edb0f4dd 100644 --- a/worker/src/lib.rs +++ b/worker/src/lib.rs @@ -1,5 +1,58 @@ #![allow(clippy::new_without_default)] #![allow(clippy::or_fun_call)] +//! # Features +//! ## `d1` +//! +//! Allows the use of [D1 bindings](crate::d1) and [`query!`](crate::query) macro. +//! +//! +//! ## `queue` +//! +//! Enables `queue` event type in [`[event]`](worker_macros::event) macro. +//! +//! ``` +//! // Consume messages from a queue +//! #[event(queue)] +//! pub async fn main(message_batch: MessageBatch, env: Env, _ctx: Context) -> Result<()> { +//! Ok(()) +//! } +//! ``` +//! +//! ## `http` +//! `worker` `0.0.21` introduced an `http` feature flag which starts to replace custom types with widely used types from the [`http`](https://docs.rs/http/latest/http/) crate. +//! +//! This makes it much easier to use crates which use these standard types such as [`axum`](axum). +//! +//! This currently does a few things: +//! +//! 1. Introduce [`Body`](worker::Body), which implements [`http_body::Body`](http_body::Body) and is a simple wrapper around [`web_sys::ReadableStream`](web_sys::ReadableStream). +//! 1. The `req` argument when using the [`[event(fetch)]`](worker_macros::event) macro becomes `http::Request`. +//! 1. The expected return type for the fetch handler is `http::Response` where `B` can be any [`http_body::Body`](http_body::Body). +//! 1. The argument for [`Fetcher::fetch_request`](Fetcher::fetch_request) is `http::Request`. +//! 1. The return type of [`Fetcher::fetch_request`](Fetcher::fetch_request) is `http::Response`. +//! +//! The end result is being able to use frameworks like `axum` directly (see [example](./examples/axum)): +//! +//! ```rust +//! pub async fn root() -> &'static str { +//! "Hello Axum!" +//! } +//! +//! fn router() -> Router { +//! Router::new().route("/", get(root)) +//! } +//! +//! #[event(fetch)] +//! async fn fetch( +//! req: HttpRequest, +//! _env: Env, +//! _ctx: Context, +//! ) -> Result> { +//! Ok(router().call(req).await?) +//! } +//! ``` +//! +//! We also implement `try_from` between `worker::Request` and `http::Request`, and between `worker::Response` and `http::Response`. This allows you to convert your code incrementally if it is tightly coupled to the original types. #[doc(hidden)] use std::result::Result as StdResult; @@ -57,6 +110,7 @@ mod context; mod cors; // Require pub module for macro export #[cfg(feature = "d1")] +/// **Requires** `d1` feature. pub mod d1; mod date; mod delay; @@ -82,3 +136,19 @@ mod streams; mod websocket; pub type Result = StdResult; + +#[cfg(feature = "http")] +/// **Requires** `http` feature. A convenience Body type which wraps [`web_sys::ReadableStream`](web_sys::ReadableStream) +/// and implements [`http_body::Body`](http_body::Body) +pub use http::body::Body; +#[cfg(feature = "http")] +pub use http::{ + request::from_wasm as request_from_wasm, request::to_wasm as request_to_wasm, + response::from_wasm as response_from_wasm, response::to_wasm as response_to_wasm, +}; +#[cfg(feature = "http")] +/// **Requires** `http` feature. Type alias for `http::Request`. +pub type HttpRequest = ::http::Request; +#[cfg(feature = "http")] +/// **Requires** `http` feature. Type alias for `http::Response`. +pub type HttpResponse = ::http::Response; diff --git a/worker/src/request.rs b/worker/src/request.rs index 7cd1c3fe..ebb24094 100644 --- a/worker/src/request.rs +++ b/worker/src/request.rs @@ -24,6 +24,23 @@ pub struct Request { immutable: bool, } +#[cfg(feature = "http")] +impl TryFrom for Request { + type Error = crate::Error; + fn try_from(req: crate::HttpRequest) -> Result { + let web_request: web_sys::Request = crate::http::request::to_wasm(req)?; + Ok(Request::from(web_request)) + } +} + +#[cfg(feature = "http")] +impl TryFrom for crate::HttpRequest { + type Error = crate::Error; + fn try_from(req: Request) -> Result { + crate::http::request::from_wasm(req.edge_request) + } +} + impl From for Request { fn from(req: web_sys::Request) -> Self { Self { diff --git a/worker/src/response.rs b/worker/src/response.rs index 0b4b5f7f..e419e241 100644 --- a/worker/src/response.rs +++ b/worker/src/response.rs @@ -8,6 +8,8 @@ use crate::WebSocket; use futures_util::{TryStream, TryStreamExt}; use js_sys::Uint8Array; use serde::{de::DeserializeOwned, Serialize}; +#[cfg(feature = "http")] +use std::convert::TryFrom; use wasm_bindgen::JsCast; use wasm_bindgen::JsValue; use web_sys::ReadableStream; @@ -32,6 +34,24 @@ pub struct Response { websocket: Option, } +#[cfg(feature = "http")] +impl TryFrom for Response { + type Error = crate::Error; + fn try_from(res: crate::HttpResponse) -> Result { + let resp = crate::http::response::to_wasm(res)?; + Ok(resp.into()) + } +} + +#[cfg(feature = "http")] +impl TryFrom for crate::HttpResponse { + type Error = crate::Error; + fn try_from(res: Response) -> Result { + let sys_resp: web_sys::Response = res.into(); + crate::http::response::from_wasm(sys_resp) + } +} + impl Response { /// Create a `Response` using `B` as the body encoded as JSON. Sets the associated /// `Content-Type` header for the `Response` as `application/json`. diff --git a/worker/src/websocket.rs b/worker/src/websocket.rs index a79869ce..8c5afec4 100644 --- a/worker/src/websocket.rs +++ b/worker/src/websocket.rs @@ -21,6 +21,9 @@ pub struct WebSocketPair { pub server: WebSocket, } +unsafe impl Send for WebSocketPair {} +unsafe impl Sync for WebSocketPair {} + impl WebSocketPair { /// Creates a new `WebSocketPair`. pub fn new() -> Result { @@ -37,6 +40,9 @@ pub struct WebSocket { socket: web_sys::WebSocket, } +unsafe impl Send for WebSocket {} +unsafe impl Sync for WebSocket {} + impl WebSocket { /// Attempts to establish a [`WebSocket`] connection to the provided [`Url`]. ///