From b09fc258ccc85bca6bcad00318f6f44d8605c85d Mon Sep 17 00:00:00 2001 From: Rudra Arora Date: Tue, 18 Jul 2023 17:22:06 +0100 Subject: [PATCH 1/5] tutorials links to wasmer edge --- .../docs/language-guide/rust/tutorials/wasix-axum.mdx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/pages/docs/language-guide/rust/tutorials/wasix-axum.mdx b/pages/docs/language-guide/rust/tutorials/wasix-axum.mdx index 863e3ce..6756d5a 100644 --- a/pages/docs/language-guide/rust/tutorials/wasix-axum.mdx +++ b/pages/docs/language-guide/rust/tutorials/wasix-axum.mdx @@ -141,7 +141,7 @@ tokio = { version = "=1.24.2", default-features = false, features = ["full"] } # parking_lot = { version = "=0.12.1", features = ["nightly"] } # ← Added Line [patch.crates-io] -socket2 = { git = "https://github.com/wasix-org/socket2.git", branch = "v0.4.7" } # ← Added Line +socket2 = { git = "https://github.com/wasix-org/socket2.git", branch = "v0.4.9" } # ← Added Line libc = { git = "https://github.com/wasix-org/libc.git" } # ← Added Line tokio = { git = "https://github.com/wasix-org/tokio.git", branch = "wasix-1.24.2" } # ← Added Line ``` @@ -216,13 +216,19 @@ Now in a separate terminal, you can use `curl` to make a request to the server: ```shell $ curl http://localhost:3000 -Hello, Axum ❤️ WASIX!% +Hello, Axum ❤️ WASIX! ``` Yay, it works! 🎉 + + You can also deploy you application to the edge. Checkout this + [tutorial](https://docs.wasmer.io/edge/quickstart/http-server) for deploying + your wasix-axum server to wasmer edge. + + ## Conclusion In this tutorial, we learned: From 6b3a53c99e315dea903b305816f021fbb73d2672 Mon Sep 17 00:00:00 2001 From: Rudra Arora Date: Mon, 31 Jul 2023 00:45:03 +0100 Subject: [PATCH 2/5] epoll --- pages/docs/explanation/_meta.json | 1 + pages/docs/explanation/epoll-and-tls.mdx | 150 +++++++++++ .../language-guide/rust/tutorials/_meta.json | 1 + .../rust/tutorials/wasix-reqwest.mdx | 254 ++++++++++++++++++ 4 files changed, 406 insertions(+) create mode 100644 pages/docs/explanation/epoll-and-tls.mdx create mode 100644 pages/docs/language-guide/rust/tutorials/wasix-reqwest.mdx diff --git a/pages/docs/explanation/_meta.json b/pages/docs/explanation/_meta.json index 92e154f..1351cda 100644 --- a/pages/docs/explanation/_meta.json +++ b/pages/docs/explanation/_meta.json @@ -1,5 +1,6 @@ { "features": "Features", "extensions-to-wasi": "Extensions to WASI", + "epoll-and-tls": "Epoll and TLS", "faqs": "FAQs" } diff --git a/pages/docs/explanation/epoll-and-tls.mdx b/pages/docs/explanation/epoll-and-tls.mdx new file mode 100644 index 0000000..92a1d7b --- /dev/null +++ b/pages/docs/explanation/epoll-and-tls.mdx @@ -0,0 +1,150 @@ +import { Callout } from "nextra-theme-docs"; + +# WASIX: Epoll and TLS + + + As of [wasmer 4.1](https://wasmer.io/posts/wasmer-4.1), wasmer implements + `epoll` for polling on file descriptors. This syscall was added to improve + performance in wasix. However, `poll_oneoff` is still supported. + + +The release of wasmer 4.1 introduced `epoll` support for wasix. Works for both features, `epoll` and **TLS** support started in April 2023. +Both features were very important for wasix, as they open up gates for new use cases and improve performance in aspects such as networking, file system access, cryptography, etc. + +## Epoll + +`epoll` is a variant of `poll` available in the Linux kernel, designed to be more efficient when dealing with large numbers of file descriptors. +Unlike `poll`, which scans through all file descriptors each time it is called, epoll uses an event-driven approach. +It maintains a **watch list** of file descriptors, and only those that have changed status since the last call will be returned to the user. + +You can learn more about `epoll`, `poll` and `select` in this [article](https://jvns.ca/blog/2017/06/03/async-io-on-linux--select--poll--and-epoll/) by Julia Evans and from a github repository dedicated to learning I/O polling [here](https://github.com/pniewiejski/learn-io-polling). + +### Implmentation history + +Works on `epoll` for WASIX started in April 2023, in the PR [#3830](https://github.com/wasmerio/wasmer/pull/3830). + +This PR was just a proof of concept, for asynchronous I/O multiplexing using `epoll` in WASIX. This POC would have given huge performance benefits when used correctly by a WASIX program. + +This PR served as a foundation for [#4050](https://github.com/wasmerio/wasmer/pull/4050) which was the implementation of **asynchronous I/O** using `epoll` in WASIX. + +(Can you elaborate more ?) - TODO @sharrattj ? + +### What this means for WASIX ? + +Before wasmer 4.1, wasmer runtime used the `poll_oneoff` syscall for non-blocking operations such as networking, file system access, etc. This meant that we had to fork mio to use the `poll_oneoff` syscall but found limitations with inconsistencies on how POSIX implements poll and how WASI specified `poll_oneoff`. +By implementing the much more scalable epoll syscall this allows for a consistent implementation that matches closer to POSIX without hurting WASI backwards compatibility which WASIX is committed to retain. + +This means that: + +- `epoll` scales much better when running lots of file descriptors. E.g. a http server with hundreds of connections. +- The I/O lattency is more deterministic and predictable when under heavy load. +- CPU usage is more efficient than `poll_oneoff` +- The new epoll calls are much more stable as the code paths are cleaner under the hood as they are much closer to how Linux works + +To sum up, the bread and butter of an HTTP Server is now more **stable** and **scalable**. + +### What this means for libraries ? + +`tokio` the most popular asynchronous runtime for Rust. It is used by many libraries such as `hyper`, `actix-web`, `tide`, `sqlx`, `async-std`, etc. +It's multiplexed I/O is implemented using `mio` which is a library that provides a cross-platform interface for multiplexed I/O. +`mio` uses `epoll` and `kqueue` in its native implementaiton but implements [`poll_oneoff`](https://github.com/tokio-rs/mio/blob/master/src/sys/wasi/mod.rs) for WASI. + +The official [notes](https://github.com/tokio-rs/mio/blob/2123bedbed00e24dccc036a0e1799e9e1d7dba1c/src/sys/wasi/mod.rs#L1-L14) from `mio`'s WASI implementation too state that: + +> The current implementation is somewhat limited. The `Waker` is not implemented, as at the time of writing there is no way to support to wake-up a thread from calling `poll_oneoff`. +> Furthermore the (re/de)register functions also don't work while concurrently polling as both registering and polling requires a lock on the `subscriptions`. +> Finally `Selector::try_clone`, required by `Registry::try_clone`, doesn't work. However this could be implemented by use of an `Arc`. +> In summary, **this only (barely) works using a single thread.** + +**SINGLE THREADED!! ???** Would you settle for single threaded when you can have the full power of tokio in WASIX ! That's what we thought too. + +## TLS + +Now, comming to TLS. One of the most rewqested feature. (pun intended) + +TLS is a cryptographic protocol that provides end-to-end encryption and authentication over the internet. +It is required by many applications such as HTTPS, SMTPS, SFTP, etc. + +Our primary focus for TLS was to enable HTTPS clients support for WASIX. This would allow WASIX to be used for outbound HTTPS requests, external API calls, etc. + +### Implementation history + +Okay, this story is kind of a roller coaster ride. So, buckle up. + +TLS works by using a **handshake** protocol to establish a secure connection between two parties. This handshake protocol is implemented by any cryptographic library such as OpenSSL, LibreSSL, BoringSSL, etc. +For WASI this is under a proposal called [WASI Crypto](https://github.com/WebAssembly/wasi-crypto). This proposal is lead by [Frank Denis](https://github.com/jedisct1) and [Daiki Ueno](https://github.com/ueno). + +So there were two paths to implement TLS in WASIX: + +1. Use WASI Crypto to implement TLS in WASIX. +2. Try to compile ring for WASIX. + +Like any sane person, we should have waited for WASI Crypto to be implemented or just tried the basic implementation of [WASI crypto](https://github.com/wasm-crypto/wasi-crypto-host-functions) in WASIX. +But this would have meant that all the libraries that didn't have this implementation such as rustls would not work in WASIX. + +But, one thing I learnt at Wasmer is you don't compromise with the developer experience and implement the future NOW. +So I went down the rabbit hole of trying to compile ring for WASIX. + + + **This didn't come in easy.** + + +The challenge was ring implements a lot of cryptographic algorithms and implements them using Assembly language which are precompiled for every target +such as Linux, MacOS, Windows, etc. but for targets that don't have a precompiled assembly language implementation, ring uses a C implementation. + +Boom, this is what we needed. We just needed to compile the C implementation of ring for WASIX. But, this was not as easy as it sounds. + +I started exploring the ring codebase and found two potential PRs to test out: + +- [#1499](https://github.com/briansmith/ring/pull/1499) +- [#1568](https://github.com/briansmith/ring/pull/1568) + +Sadly none of them compiled as **#1499** was not well updated and **#1568** resulted in an error of bn_mul_mont. Which is actually now fixed in the latest ring available on master. + +This too was back in April. I then moved on but interestingly one day I got a notification from [Frank Denis](https://github.com/jedisct1) that he compiled ring for WASI and WASIX in his [ring-wasi](https://github.com/jedisct1/ring-wasi) repository. +This was really exciting and I started testing it out. I quickly forked the repo and started testing it out in WASIX. Sadly, it didn't work but it got us to a 99% working implementation. + +So, a few sleepless nights, lot's of energy drink and a dangling around trying to compile every possible `C` file in ring and adding a `bn_mul_mont` fallback. I finally got it to work. +It was like first time looking at a rainbow 🌈. + +Now our implementation of ring which works for WASI/WASIX lives [here](https://github.com/wasix-org/ring). + +Compiling ring was the first step. The team quickly got to work to implement all other required libraries: + +- [rustls](https://github.com/wasix-org/rustls) +- [tokio-rustls](https://github.com/wasix-org/tokio-rustls) +- [hyper](https://github.com/wasix-org/hyper) +- [hyper-rustls](https://github.com/wasix-org/hyper-rustls) +- [reqwest](https://github.com/wasix-org/reqwest) +- [webpki-roots](https://github.com/wasix-org/webpki-roots) +- [webpki](https://github.com/wasix-org/webpki) +- [sct](https://github.com/wasix-org/sct) + + + WASI/WASIX can't use the CA certificates available on a host machine so it + need `webpki-roots` to be able to verify the certificates. + + +### What this means for WASIX ? + +This means that WASIX can now be used for outbound HTTPS requests, external API calls, etc. This is a huge step for WASIX as it opens up a lot of use cases for WASIX. + +1. **Secure Access to APIs**: Many modern APIs require a client to communicate over HTTPS. With TLS support, WASIX applications can securely access these APIs directly. +2. **Secure Database Connections**: WASIX applications can use TLS to connect securely to databases that support encrypted connections. This ensures that sensitive data is protected during transit. +3. **Secure Third-Party Integrations**: If your WASIX applications need to interact with third-party services (like payment gateways, OAuth providers, etc.), TLS client support allows these interactions to occur securely. +4. **Ingress and Egress Data Security**: Implementing TLS clients ensures that both incoming and outgoing data from the application is secure, a significant benefit in complex systems where both ingress and egress points need to be equally secure. +5. **CDN and Edge Computing**: TLS client support can ensure secure communication with Content Delivery Networks (CDNs) and edge computing resources, protecting data integrity and confidentiality while improving content delivery speed. +6. **Confidential Computing**: With TLS client support, applications can securely retrieve and use confidential data, cryptographic keys, or certificates from remote secure servers or key management systems. +7. **IoT Applications**: In IoT applications, devices often need to communicate with a central server. TLS client support can be used to ensure these communications are secure. + +## Conclusion + +The power of `epoll` and `TLS` makes WASIX more stable, secure and scalable than ever. + +This was a huge step for WASIX and we are really excited to see what the community builds with this. +We are also working on a few examples to showcase the power of WASIX. +You can try out our starter tutorial for outbound proxies [here](/todo/). More examples will follow suit. + +At the end, I would like to thank Frank Denis on the behalf of whole Wasmer Team for his work on the ring-wasi implementation and all of the wasmer team for their support and guidance and ofcourse their work on Wasmer 4.1. + +If you have any questions, feel free to reach out to us on [Discord](https://discord.gg/rWkMNStrEW). diff --git a/pages/docs/language-guide/rust/tutorials/_meta.json b/pages/docs/language-guide/rust/tutorials/_meta.json index 1be8c09..3799047 100644 --- a/pages/docs/language-guide/rust/tutorials/_meta.json +++ b/pages/docs/language-guide/rust/tutorials/_meta.json @@ -1,5 +1,6 @@ { "wasix-axum": "Wasix with Axum", + "wasix-reqwest": "Wasix with Reqwest", "condvar": "Condition variables", "threading": "Threading with Wasix" } diff --git a/pages/docs/language-guide/rust/tutorials/wasix-reqwest.mdx b/pages/docs/language-guide/rust/tutorials/wasix-reqwest.mdx new file mode 100644 index 0000000..e527e48 --- /dev/null +++ b/pages/docs/language-guide/rust/tutorials/wasix-reqwest.mdx @@ -0,0 +1,254 @@ +import { Steps } from "nextra-theme-docs"; +import { Callout, FileTree } from "nextra-theme-docs"; + +## WASIX with Reqwest + +This is a sample project that shows how to use a Reqwest client to build an outbound proxy and compile it to the WASIX. + +### Prerequisites + +The project requires the following tools to be installed on your system: + +- [Rust](https://www.rust-lang.org/tools/install) +- [WASIX](/docs/language-guide/rust/installation) + + + +### Start a new project + +```shell +$ cargo new --bin wasix-axum + Created binary (application) `wasix-axum` package +``` + +Your `wasix-axum` directory structure should look like this: + + + + + + + + + + + +### Add dependencies + +```shell +$ cd wasix-axum +$ cargo add axum --features tokio +$ cargo add tokio --features full +``` + +Now your `Cargo.toml` should look like this: + +```toml filename="Cargo.toml" +[package] +name = "wasix-axum" +version = "0.1.0" +edition = "2021" + +[dependencies] +axum = { version = "0.6.18", features = ["tokio"] } +tokio = { version = "1.28.1", features = ["full"] } +``` + +### Writing the Application + +#### Basic Application Setup + +Now, let's stub out a basic `get` route that returns a string using a `handler` function. + +```rust copy filename="src/main.rs" +use axum::{routing::get, Router}; +use std::net::SocketAddr; + +#[tokio::main] +async fn main() { + // Building our application with a single Route + let app = Router::new().route("/", get(handler)); + + // Run the server with hyper on http://127.0.0.1:3000 + let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); + axum::Server::bind(&addr) + .serve(app.into_make_service()) + .await + .unwrap(); +} + +async fn handler() -> &'static str { + "Hello, Axum ❤️ WASIX!" +} + +``` + +#### Running the Application + +Run the application with the `cargo`: + +```shell +$ cargo run + Compiling wasix-axum v0.1.0 (/wasix-axum) + Finished dev [unoptimized + debuginfo] target(s) in 1.41s + Running `target/debug/wasix-axum` +``` + +Now in a separate terminal, you can use `curl` to make a request to the server: + +```shell +$ curl http://127.0.0.1:3000 +Hello, Axum ❤️ WASIX!% +``` + +Hmm, but let's see does it work with wasix ? Let's try to build it with wasix: + +```shell +$ cargo wasix build +... + ::: .cargo/registry/src/index.crates.io/socket2-0.4.9/src/lib.rs:104:16 + | +104 | fn from(socket: $from) -> $for { + | ---- implicitly returns `()` as its body has no tail or `return` expression + +Some errors have detailed explanations: E0061, E0308, E0412, E0422, E0425, E0432, E0433, E0583, E0618. +For more information about an error, try `rustc --explain E0061`. +error: could not compile `socket2` (lib) due to 202 previous errors +warning: build failed, waiting for other jobs to finish.. +... +``` + +Oh no, it doesn't work. But why ? + +#### Compiling with WASIX + + + For making certain features such as networking, sockets, threading, etc. work + with wasix we need patch dependencies for some crates that use those features. + + +Let's add the following patch to our `Cargo.toml`: + +```toml copy filename="Cargo.toml" +[package] +name = "wasix-axum" +version = "0.1.0" +edition = "2021" + +[dependencies] +axum = { version = "=0.6.9", features = ["tokio"] } # ← Updated Line +tokio = { version = "=1.24.2", default-features = false, features = ["full"] } # ← Updated Line +parking_lot = { version = "=0.12.1", features = ["nightly"] } # ← Added Line + +[patch.crates-io] +socket2 = { git = "https://github.com/wasix-org/socket2.git", branch = "v0.4.9" } # ← Added Line +libc = { git = "https://github.com/wasix-org/libc.git" } # ← Added Line +tokio = { git = "https://github.com/wasix-org/tokio.git", branch = "wasix-1.24.2" } # ← Added Line +``` + + + As you can see above the `parking_lot` crate works out of the box 🚀 with + wasix. It just needs the `nightly` feature to be enabled. + + + + We need to pin and replace some dependencies to achieve wasix compatibility. + So, currently supported axum version is `0.6.9` and tokio version is `1.24.2`. + + +Now, let's try to build it with wasix again: + +```shell +$ cargo wasix build + Blocking waiting for file lock on package cache + Updating crates.io index + Blocking waiting for file lock on package cache + Blocking waiting for file lock on package cache + Compiling tokio v1.24.2 (https://github.com/wasix-org/tokio.git?branch=wasix-1.24.2#8ba16a72) + Compiling tower v0.4.13 + Compiling hyper v0.14.26 + Compiling tower-http v0.4.0 + Compiling axum v0.6.9 + Compiling wasix-axum v0.1.0 (/wasix-axum) + Finished dev [unoptimized + debuginfo] target(s) in 14.63s +info: Post-processing WebAssembly files +``` + +Yay, it builds! Now, let's try to run it: + + + It could happen that the above command might fail for you, this is because of + dependencies not resolving correctly. You can easily fix this by running + `cargo update` and then running `cargo wasix build` again. + + +```shell +$ cargo wasix run + Finished dev [unoptimized + debuginfo] target(s) in 0.23s + Running `/Users/xorcist/.cargo/bin/cargo-wasix target/wasm32-wasmer-wasi/debug/wasix-axum.wasm` +info: Post-processing WebAssembly files + Running `target/wasm32-wasmer-wasi/debug/wasix-axum.wasm` +thread 'main' panicked at 'error binding to 127.0.0.1:3000: error creating server listener: Not supported (os error 58)', .cargo/registry/src/index.crates.io-/hyper-0.14.26/src/server/server.rs:79:13 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +error: failed to run `target/wasm32-wasmer-wasi/debug/wasix-axum.wasm` +╰─▶ 1: RuntimeError: unreachable +error: failed to execute "wasmer" "--enable-threads" "--" "target/wasm32-wasmer-wasi/debug/wasix-axum.wasm" + status: exit status: 134 +``` + + + Currently, we need to run it using `wasmer run`. See the + [issue](https://github.com/wasix-org/cargo-wasix/issues/13) + + +Let's try to run it with wasmer: + +```shell copy +$ wasmer run target/wasm32-wasmer-wasi/debug/wasix-axum.wasm --net --enable-threads +``` + +Let's go through the flags we used above: + +1. `--net` - This flag enables networking support for wasm files. +2. `--enable-threads` - This flag enables threading support for wasm files. + +Now in a separate terminal, you can use `curl` to make a request to the server: + +```shell +$ curl http://localhost:3000 +Hello, Axum ❤️ WASIX! +``` + +Yay, it works! 🎉 + + + + + You can also deploy you application to the edge. Checkout this + [tutorial](https://docs.wasmer.io/edge/quickstart/http-server) for deploying + your wasix-axum server to wasmer edge. + + +## Conclusion + +In this tutorial, we learned: + +- How to build a simple web server using axum and **compile it with wasix**. +- How to **patch** dependencies add WASIX support until changes are adopted upstream. +- How to run wasix based `.wasm` files with **Wasmer**. +- How to enable **networking** and **threading** support for wasm files. + +import { Card, Cards } from "nextra-theme-docs"; + + + + + } + title="wasix-rust-examples/wasix-axum" + href="https://github.com/wasix-org/wasix-rust-examples/tree/main/wasix-axum" +/> From 953467d7fa7828806e5cf9244d5f2045ad4b1bad Mon Sep 17 00:00:00 2001 From: Rudra Arora Date: Mon, 31 Jul 2023 01:50:04 +0100 Subject: [PATCH 3/5] wasix reqwest tutorial --- .../rust/tutorials/wasix-axum.mdx | 2 +- .../rust/tutorials/wasix-reqwest.mdx | 323 +++++++++++------- 2 files changed, 202 insertions(+), 123 deletions(-) diff --git a/pages/docs/language-guide/rust/tutorials/wasix-axum.mdx b/pages/docs/language-guide/rust/tutorials/wasix-axum.mdx index 6756d5a..568b4a2 100644 --- a/pages/docs/language-guide/rust/tutorials/wasix-axum.mdx +++ b/pages/docs/language-guide/rust/tutorials/wasix-axum.mdx @@ -109,7 +109,7 @@ $ cargo wasix build ::: .cargo/registry/src/index.crates.io/socket2-0.4.9/src/lib.rs:104:16 | 104 | fn from(socket: $from) -> $for { - | ---- implicitly returns `()` as its body has no tail or `return` expression + | ---- implicitly returns "()" as its body has no tail or `return` expression Some errors have detailed explanations: E0061, E0308, E0412, E0422, E0425, E0432, E0433, E0583, E0618. For more information about an error, try `rustc --explain E0061`. diff --git a/pages/docs/language-guide/rust/tutorials/wasix-reqwest.mdx b/pages/docs/language-guide/rust/tutorials/wasix-reqwest.mdx index e527e48..bf31497 100644 --- a/pages/docs/language-guide/rust/tutorials/wasix-reqwest.mdx +++ b/pages/docs/language-guide/rust/tutorials/wasix-reqwest.mdx @@ -1,9 +1,15 @@ import { Steps } from "nextra-theme-docs"; import { Callout, FileTree } from "nextra-theme-docs"; + + As of [wasmer 4.1](https://wasmer.io/posts/wasmer-4.1), `epoll` syscall and + `TLS` clients are now supported in WASIX. This was done by compiling ring. + Read our whole blog post about it [here](/link/blog/epoll-n-tls/TODO). + + ## WASIX with Reqwest -This is a sample project that shows how to use a Reqwest client to build an outbound proxy and compile it to the WASIX. +This is a sample project that shows how to use a Reqwest client to build an outbound proxy and compile it to WASIX. ### Prerequisites @@ -17,14 +23,14 @@ The project requires the following tools to be installed on your system: ### Start a new project ```shell -$ cargo new --bin wasix-axum - Created binary (application) `wasix-axum` package +$ cargo new --bin wasix-reqwest-proxy + Created binary (application) `wasix-reqwest-proxy` package ``` -Your `wasix-axum` directory structure should look like this: +Your `wasix-reqwest-proxy` directory structure should look like this: - + @@ -35,165 +41,209 @@ Your `wasix-axum` directory structure should look like this: ### Add dependencies + + We will use pinned dependencies from + [**wasix-org**](https://github.com/wasix-org) to make sure that our project + compiles with wasix. + + ```shell -$ cd wasix-axum -$ cargo add axum --features tokio -$ cargo add tokio --features full +$ cd wasix-reqwest-proxy +$ cargo add tokio --git https://github.com/wasix-org/tokio.git --branch wasix-1.24.2 --features rt-multi-thread,macros,fs,io-util,net,signal +$ cargo add reqwest --git https://github.com/wasix-org/reqwest.git --features json,rustls-tls +$ cargo add hyper --git https://github.com/wasix-org/hyper.git --branch v0.14.27 --features server +$ cargo add anyhow ``` -Now your `Cargo.toml` should look like this: +We also need to add some patch crates to our `Cargo.toml` so that all other dependencies compile with wasix: ```toml filename="Cargo.toml" [package] -name = "wasix-axum" +name = "wasix-reqwest-proxy" version = "0.1.0" edition = "2021" [dependencies] -axum = { version = "0.6.18", features = ["tokio"] } -tokio = { version = "1.28.1", features = ["full"] } +tokio = { git = "https://github.com/wasix-org/tokio.git", branch = "epoll", default-features = false, features = [ + "rt-multi-thread", + "macros", + "fs", + "io-util", + "net", + "signal", +] } +reqwest = { git = "https://github.com/wasix-org/reqwest.git", default-features = false, features = [ + "json", + "rustls-tls", +] } +anyhow = { version = "1.0.71" } +hyper = { git = "https://github.com/wasix-org/hyper.git", branch = "v0.14.27", features = [ + "server", +] } + +[patch.crates-io] # 👈🏼 Added section here +socket2 = { git = "https://github.com/wasix-org/socket2.git", branch = "v0.4.9" } # 👈🏼 Added line here +libc = { git = "https://github.com/wasix-org/libc.git" } # 👈🏼 Added line here +tokio = { git = "https://github.com/wasix-org/tokio.git", branch = "epoll" } # 👈🏼 Added line here +rustls = { git = "https://github.com/wasix-org/rustls.git", branch = "v0.21.5" } # 👈🏼 Added line here +hyper = { git = "https://github.com/wasix-org/hyper.git", branch = "v0.14.27" } # 👈🏼 Added line here + ``` + + For making certain features such as **networking**, **sockets**, + **threading**, etc. work with wasix we need patch dependencies for some crates + that use those features. + + ### Writing the Application -#### Basic Application Setup +Our outbound proxy application will have two parts: -Now, let's stub out a basic `get` route that returns a string using a `handler` function. +1. Listen for incoming requests using the `hyper` server +2. Forward the request to the destination using the `reqwest` client and return the response to the client -```rust copy filename="src/main.rs" -use axum::{routing::get, Router}; -use std::net::SocketAddr; +#### Part 1. - Listening for incoming requests -#[tokio::main] -async fn main() { - // Building our application with a single Route - let app = Router::new().route("/", get(handler)); +Let's setup a basic `hyper` server that listens on port `3000`. This code goes inside our main function. - // Run the server with hyper on http://127.0.0.1:3000 +```rust copy filename="src/main.rs" let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); - axum::Server::bind(&addr) - .serve(app.into_make_service()) - .await - .unwrap(); -} -async fn handler() -> &'static str { - "Hello, Axum ❤️ WASIX!" -} + println!("Listening on {}", addr); + + // And a MakeService to handle each connection... + let make_service = make_service_fn(|_conn| async { Ok::<_, Infallible>(service_fn(handle)) }); + // ^^^^^^ + // 🔦 Focus here - This handle function is what connects to the part 2 of our application. + + // Then bind and serve... + let server = Server::bind(&addr).serve(make_service); + // And run forever... + Ok(server.await?) ``` -#### Running the Application +#### Part 2. - Forwarding the request to the destination -Run the application with the `cargo`: +Now let's write the `handle` function that will be called for each incoming request. This function will use the `reqwest` client to forward the request to the destination and return the response to the client. -```shell -$ cargo run - Compiling wasix-axum v0.1.0 (/wasix-axum) - Finished dev [unoptimized + debuginfo] target(s) in 1.41s - Running `target/debug/wasix-axum` +```rust copy filename="src/main.rs" +async fn handle(req: Request) -> Result, Infallible> { + // Create the destination URL + let path = format!( + "https://www.rust-lang.org/{}", + req.uri() + .path_and_query() + .map(|p| p.as_str()) + .unwrap_or(req.uri().path()) + ); // ← 1. + + let mut status = StatusCode::OK; + let body = match async { reqwest::get(path).await?.text().await }.await { + Ok(b) => b, + Err(err) => { + status = err.status().unwrap_or(StatusCode::BAD_REQUEST); + format!("{err}") + } + }; // ← 2. + let body = String::from_utf8_lossy(body.as_bytes()).to_string(); // ← 3. + + let mut res = Response::new(Body::from(body)); // ← 4. + *res.status_mut() = status; // ← 5. + Ok(res) // ← 6. +} ``` -Now in a separate terminal, you can use `curl` to make a request to the server: +Let's go through the code above: -```shell -$ curl http://127.0.0.1:3000 -Hello, Axum ❤️ WASIX!% -``` +1. Create a `path` variable that contains the destination URL. We use the `req.uri()` to get the request URI and then append it to the destination URL. +2. Use the `reqwest` client to make a request to the destination URL. We use the `await` keyword to wait for the response. If the request fails, we set the `status` variable to `BAD_REQUEST` and return the error message as the response body. +3. Convert the response body to a `String` using `String::from_utf8_lossy`. This is required because the `Body` type requires the body to be `Send` and `Sync` and `String` implements both of these traits. +4. Create a new `Response` with the body we received from the destination. +5. Set the status of the response to the `status` variable we set earlier. +6. Finally, Return the response. -Hmm, but let's see does it work with wasix ? Let's try to build it with wasix: +Your `src/main.rs` should now look like this: -```shell -$ cargo wasix build -... - ::: .cargo/registry/src/index.crates.io/socket2-0.4.9/src/lib.rs:104:16 - | -104 | fn from(socket: $from) -> $for { - | ---- implicitly returns `()` as its body has no tail or `return` expression - -Some errors have detailed explanations: E0061, E0308, E0412, E0422, E0425, E0432, E0433, E0583, E0618. -For more information about an error, try `rustc --explain E0061`. -error: could not compile `socket2` (lib) due to 202 previous errors -warning: build failed, waiting for other jobs to finish.. -... -``` +```rust copy filename="src/main.rs" +use hyper::service::{make_service_fn, service_fn}; +use hyper::{Body, Request, Response, Server, StatusCode}; +use std::convert::Infallible; +use std::net::SocketAddr; -Oh no, it doesn't work. But why ? +async fn handle(req: Request) -> Result, Infallible> { + let path = format!( + "https://www.rust-lang.org/{}", + req.uri() + .path_and_query() + .map(|p| p.as_str()) + .unwrap_or(req.uri().path()) + ); + + let mut status = StatusCode::OK; + let body = match async { reqwest::get(path).await?.text().await }.await { + Ok(b) => b, + Err(err) => { + status = err.status().unwrap_or(StatusCode::BAD_REQUEST); + format!("{err}") + } + }; + let body = String::from_utf8_lossy(body.as_bytes()).to_string(); + + let mut res = Response::new(Body::from(body)); + *res.status_mut() = status; + Ok(res) +} -#### Compiling with WASIX +#[tokio::main] +async fn main() -> anyhow::Result<()> { + let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); - - For making certain features such as networking, sockets, threading, etc. work - with wasix we need patch dependencies for some crates that use those features. - + println!("Listening on {}", addr); -Let's add the following patch to our `Cargo.toml`: + // And a MakeService to handle each connection... + let make_service = make_service_fn(|_conn| async { Ok::<_, Infallible>(service_fn(handle)) }); -```toml copy filename="Cargo.toml" -[package] -name = "wasix-axum" -version = "0.1.0" -edition = "2021" + // Then bind and serve... + let server = Server::bind(&addr).serve(make_service); -[dependencies] -axum = { version = "=0.6.9", features = ["tokio"] } # ← Updated Line -tokio = { version = "=1.24.2", default-features = false, features = ["full"] } # ← Updated Line -parking_lot = { version = "=0.12.1", features = ["nightly"] } # ← Added Line - -[patch.crates-io] -socket2 = { git = "https://github.com/wasix-org/socket2.git", branch = "v0.4.9" } # ← Added Line -libc = { git = "https://github.com/wasix-org/libc.git" } # ← Added Line -tokio = { git = "https://github.com/wasix-org/tokio.git", branch = "wasix-1.24.2" } # ← Added Line + // And run forever... + Ok(server.await?) +} ``` - - As you can see above the `parking_lot` crate works out of the box 🚀 with - wasix. It just needs the `nightly` feature to be enabled. - +#### Running the Application - - We need to pin and replace some dependencies to achieve wasix compatibility. - So, currently supported axum version is `0.6.9` and tokio version is `1.24.2`. - +Let's compile the application to WASIX and run it: -Now, let's try to build it with wasix again: +##### Compiling to WASIX ```shell $ cargo wasix build - Blocking waiting for file lock on package cache - Updating crates.io index - Blocking waiting for file lock on package cache - Blocking waiting for file lock on package cache - Compiling tokio v1.24.2 (https://github.com/wasix-org/tokio.git?branch=wasix-1.24.2#8ba16a72) - Compiling tower v0.4.13 - Compiling hyper v0.14.26 - Compiling tower-http v0.4.0 - Compiling axum v0.6.9 - Compiling wasix-axum v0.1.0 (/wasix-axum) - Finished dev [unoptimized + debuginfo] target(s) in 14.63s -info: Post-processing WebAssembly files +Compiling autocfg v1.1.0 +Compiling wasi v0.11.0+wasi-snapshot-preview1 +Compiling proc-macro2 v1.0.66 +Compiling cfg-if v1.0.0 +Compiling unicode-ident v1.0.11 +Compiling libc v0.2.139 (https://github.com/wasix-org/libc.git#4c0c6c29) +Compiling wasix-reqwest-proxy v0.1.0 (/wasix-reqwest-proxy) + ... ``` -Yay, it builds! Now, let's try to run it: - It could happen that the above command might fail for you, this is because of dependencies not resolving correctly. You can easily fix this by running `cargo update` and then running `cargo wasix build` again. +Yay, it builds! Now, let's try to run it: + +##### Running the Application with Wasmer + ```shell -$ cargo wasix run - Finished dev [unoptimized + debuginfo] target(s) in 0.23s - Running `/Users/xorcist/.cargo/bin/cargo-wasix target/wasm32-wasmer-wasi/debug/wasix-axum.wasm` -info: Post-processing WebAssembly files - Running `target/wasm32-wasmer-wasi/debug/wasix-axum.wasm` -thread 'main' panicked at 'error binding to 127.0.0.1:3000: error creating server listener: Not supported (os error 58)', .cargo/registry/src/index.crates.io-/hyper-0.14.26/src/server/server.rs:79:13 -note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -error: failed to run `target/wasm32-wasmer-wasi/debug/wasix-axum.wasm` -╰─▶ 1: RuntimeError: unreachable -error: failed to execute "wasmer" "--enable-threads" "--" "target/wasm32-wasmer-wasi/debug/wasix-axum.wasm" - status: exit status: 134 +$ wasmer run target/wasm32-wasmer-wasi/debug/wasix-reqwest-proxy.wasm + ``` @@ -204,7 +254,7 @@ error: failed to execute "wasmer" "--enable-threads" "--" "target/wasm32-wasmer- Let's try to run it with wasmer: ```shell copy -$ wasmer run target/wasm32-wasmer-wasi/debug/wasix-axum.wasm --net --enable-threads +$ wasmer run target/wasm32-wasmer-wasi/debug/wasix-reqwest-proxy.wasm --net --enable-threads ``` Let's go through the flags we used above: @@ -215,26 +265,55 @@ Let's go through the flags we used above: Now in a separate terminal, you can use `curl` to make a request to the server: ```shell -$ curl http://localhost:3000 -Hello, Axum ❤️ WASIX! +$ curl localhost:3000 + + + + + + Rust Programming Language + ... ``` -Yay, it works! 🎉 +Congratulations! You have successfully built an outbound proxy server using hyper, reqwest and wasix. </Steps> <Callout type="info" emoji="ℹ️"> You can also deploy you application to the edge. Checkout this - [tutorial](https://docs.wasmer.io/edge/quickstart/http-server) for deploying - your wasix-axum server to wasmer edge. + [tutorial](TODO) for deploying your wasix-reqwest-proxy server to wasmer edge. +</Callout> + +## Exercises + +### Exercise 1 + +Try to take the destination URL as a query parameter. + +```shell +$ curl localhost:3000?url=https://www.rust-lang.org +``` + +### Exercise 2 + +Try to take the destination URL as a parameter for the `.wasm` file. + +```shell +$ wasmer run target/wasm32-wasmer-wasi/debug/wasix-reqwest-proxy.wasm --net --enable-threads -- --url=https://www.rust-lang.org +``` + +<Callout type="default" emoji="💡"> + You can use the `--` to pass arguments to the `.wasm` file and use the rust's + default `std::env::args` to parse the arguments. Learn more about + [wasmer-cli](/todo/). </Callout> ## Conclusion In this tutorial, we learned: -- How to build a simple web server using axum and **compile it with wasix**. -- How to **patch** dependencies add WASIX support until changes are adopted upstream. +- How to build a simple outbound proxy server using `hyper` and `reqwest`. +- How to **patch** dependencies add WASIX support. - How to run wasix based `.wasm` files with **Wasmer**. - How to enable **networking** and **threading** support for wasm files. @@ -249,6 +328,6 @@ import { Card, Cards } from "nextra-theme-docs"; /> </svg> } - title="wasix-rust-examples/wasix-axum" - href="https://github.com/wasix-org/wasix-rust-examples/tree/main/wasix-axum" + title="wasix-rust-examples/wasix-reqwest-proxy" + href="https://github.com/wasix-org/wasix-rust-examples/tree/main/wasix-reqwest-proxy" /> From 98e86ed8a97d1cbca6517db8bd264e8cee8eb3dc Mon Sep 17 00:00:00 2001 From: Rudra Arora <aroraru@tcd.ie> Date: Mon, 31 Jul 2023 01:51:20 +0100 Subject: [PATCH 4/5] deleted tls-article --- pages/docs/explanation/_meta.json | 1 - pages/docs/explanation/epoll-and-tls.mdx | 150 ----------------------- 2 files changed, 151 deletions(-) delete mode 100644 pages/docs/explanation/epoll-and-tls.mdx diff --git a/pages/docs/explanation/_meta.json b/pages/docs/explanation/_meta.json index 1351cda..92e154f 100644 --- a/pages/docs/explanation/_meta.json +++ b/pages/docs/explanation/_meta.json @@ -1,6 +1,5 @@ { "features": "Features", "extensions-to-wasi": "Extensions to WASI", - "epoll-and-tls": "Epoll and TLS", "faqs": "FAQs" } diff --git a/pages/docs/explanation/epoll-and-tls.mdx b/pages/docs/explanation/epoll-and-tls.mdx deleted file mode 100644 index 92a1d7b..0000000 --- a/pages/docs/explanation/epoll-and-tls.mdx +++ /dev/null @@ -1,150 +0,0 @@ -import { Callout } from "nextra-theme-docs"; - -# WASIX: Epoll and TLS - -<Callout type="info" emoji="ℹ️"> - As of [wasmer 4.1](https://wasmer.io/posts/wasmer-4.1), wasmer implements - `epoll` for polling on file descriptors. This syscall was added to improve - performance in wasix. However, `poll_oneoff` is still supported. -</Callout> - -The release of wasmer 4.1 introduced `epoll` support for wasix. Works for both features, `epoll` and **TLS** support started in April 2023. -Both features were very important for wasix, as they open up gates for new use cases and improve performance in aspects such as networking, file system access, cryptography, etc. - -## Epoll - -`epoll` is a variant of `poll` available in the Linux kernel, designed to be more efficient when dealing with large numbers of file descriptors. -Unlike `poll`, which scans through all file descriptors each time it is called, epoll uses an event-driven approach. -It maintains a **watch list** of file descriptors, and only those that have changed status since the last call will be returned to the user. - -You can learn more about `epoll`, `poll` and `select` in this [article](https://jvns.ca/blog/2017/06/03/async-io-on-linux--select--poll--and-epoll/) by Julia Evans and from a github repository dedicated to learning I/O polling [here](https://github.com/pniewiejski/learn-io-polling). - -### Implmentation history - -Works on `epoll` for WASIX started in April 2023, in the PR [#3830](https://github.com/wasmerio/wasmer/pull/3830). - -This PR was just a proof of concept, for asynchronous I/O multiplexing using `epoll` in WASIX. This POC would have given huge performance benefits when used correctly by a WASIX program. - -This PR served as a foundation for [#4050](https://github.com/wasmerio/wasmer/pull/4050) which was the implementation of **asynchronous I/O** using `epoll` in WASIX. - -(Can you elaborate more ?) - TODO @sharrattj ? - -### What this means for WASIX ? - -Before wasmer 4.1, wasmer runtime used the `poll_oneoff` syscall for non-blocking operations such as networking, file system access, etc. This meant that we had to fork mio to use the `poll_oneoff` syscall but found limitations with inconsistencies on how POSIX implements poll and how WASI specified `poll_oneoff`. -By implementing the much more scalable epoll syscall this allows for a consistent implementation that matches closer to POSIX without hurting WASI backwards compatibility which WASIX is committed to retain. - -This means that: - -- `epoll` scales much better when running lots of file descriptors. E.g. a http server with hundreds of connections. -- The I/O lattency is more deterministic and predictable when under heavy load. -- CPU usage is more efficient than `poll_oneoff` -- The new epoll calls are much more stable as the code paths are cleaner under the hood as they are much closer to how Linux works - -To sum up, the bread and butter of an HTTP Server is now more **stable** and **scalable**. - -### What this means for libraries ? - -`tokio` the most popular asynchronous runtime for Rust. It is used by many libraries such as `hyper`, `actix-web`, `tide`, `sqlx`, `async-std`, etc. -It's multiplexed I/O is implemented using `mio` which is a library that provides a cross-platform interface for multiplexed I/O. -`mio` uses `epoll` and `kqueue` in its native implementaiton but implements [`poll_oneoff`](https://github.com/tokio-rs/mio/blob/master/src/sys/wasi/mod.rs) for WASI. - -The official [notes](https://github.com/tokio-rs/mio/blob/2123bedbed00e24dccc036a0e1799e9e1d7dba1c/src/sys/wasi/mod.rs#L1-L14) from `mio`'s WASI implementation too state that: - -> The current implementation is somewhat limited. The `Waker` is not implemented, as at the time of writing there is no way to support to wake-up a thread from calling `poll_oneoff`. -> Furthermore the (re/de)register functions also don't work while concurrently polling as both registering and polling requires a lock on the `subscriptions`. -> Finally `Selector::try_clone`, required by `Registry::try_clone`, doesn't work. However this could be implemented by use of an `Arc`. -> In summary, **this only (barely) works using a single thread.** - -**SINGLE THREADED!! ???** Would you settle for single threaded when you can have the full power of tokio in WASIX ! That's what we thought too. - -## TLS - -Now, comming to TLS. One of the most rewqested feature. (pun intended) - -TLS is a cryptographic protocol that provides end-to-end encryption and authentication over the internet. -It is required by many applications such as HTTPS, SMTPS, SFTP, etc. - -Our primary focus for TLS was to enable HTTPS clients support for WASIX. This would allow WASIX to be used for outbound HTTPS requests, external API calls, etc. - -### Implementation history - -Okay, this story is kind of a roller coaster ride. So, buckle up. - -TLS works by using a **handshake** protocol to establish a secure connection between two parties. This handshake protocol is implemented by any cryptographic library such as OpenSSL, LibreSSL, BoringSSL, etc. -For WASI this is under a proposal called [WASI Crypto](https://github.com/WebAssembly/wasi-crypto). This proposal is lead by [Frank Denis](https://github.com/jedisct1) and [Daiki Ueno](https://github.com/ueno). - -So there were two paths to implement TLS in WASIX: - -1. Use WASI Crypto to implement TLS in WASIX. -2. Try to compile ring for WASIX. - -Like any sane person, we should have waited for WASI Crypto to be implemented or just tried the basic implementation of [WASI crypto](https://github.com/wasm-crypto/wasi-crypto-host-functions) in WASIX. -But this would have meant that all the libraries that didn't have this implementation such as rustls would not work in WASIX. - -But, one thing I learnt at Wasmer is you don't compromise with the developer experience and implement the future NOW. -So I went down the rabbit hole of trying to compile ring for WASIX. - -<Callout type="default" emoji="🥲"> - **This didn't come in easy.** -</Callout> - -The challenge was ring implements a lot of cryptographic algorithms and implements them using Assembly language which are precompiled for every target -such as Linux, MacOS, Windows, etc. but for targets that don't have a precompiled assembly language implementation, ring uses a C implementation. - -Boom, this is what we needed. We just needed to compile the C implementation of ring for WASIX. But, this was not as easy as it sounds. - -I started exploring the ring codebase and found two potential PRs to test out: - -- [#1499](https://github.com/briansmith/ring/pull/1499) -- [#1568](https://github.com/briansmith/ring/pull/1568) - -Sadly none of them compiled as **#1499** was not well updated and **#1568** resulted in an error of bn_mul_mont. Which is actually now fixed in the latest ring available on master. - -This too was back in April. I then moved on but interestingly one day I got a notification from [Frank Denis](https://github.com/jedisct1) that he compiled ring for WASI and WASIX in his [ring-wasi](https://github.com/jedisct1/ring-wasi) repository. -This was really exciting and I started testing it out. I quickly forked the repo and started testing it out in WASIX. Sadly, it didn't work but it got us to a 99% working implementation. - -So, a few sleepless nights, lot's of energy drink and a dangling around trying to compile every possible `C` file in ring and adding a `bn_mul_mont` fallback. I finally got it to work. -It was like first time looking at a rainbow 🌈. - -Now our implementation of ring which works for WASI/WASIX lives [here](https://github.com/wasix-org/ring). - -Compiling ring was the first step. The team quickly got to work to implement all other required libraries: - -- [rustls](https://github.com/wasix-org/rustls) -- [tokio-rustls](https://github.com/wasix-org/tokio-rustls) -- [hyper](https://github.com/wasix-org/hyper) -- [hyper-rustls](https://github.com/wasix-org/hyper-rustls) -- [reqwest](https://github.com/wasix-org/reqwest) -- [webpki-roots](https://github.com/wasix-org/webpki-roots) -- [webpki](https://github.com/wasix-org/webpki) -- [sct](https://github.com/wasix-org/sct) - -<Callout type="info" emoji="ℹ️"> - WASI/WASIX can't use the CA certificates available on a host machine so it - need `webpki-roots` to be able to verify the certificates. -</Callout> - -### What this means for WASIX ? - -This means that WASIX can now be used for outbound HTTPS requests, external API calls, etc. This is a huge step for WASIX as it opens up a lot of use cases for WASIX. - -1. **Secure Access to APIs**: Many modern APIs require a client to communicate over HTTPS. With TLS support, WASIX applications can securely access these APIs directly. -2. **Secure Database Connections**: WASIX applications can use TLS to connect securely to databases that support encrypted connections. This ensures that sensitive data is protected during transit. -3. **Secure Third-Party Integrations**: If your WASIX applications need to interact with third-party services (like payment gateways, OAuth providers, etc.), TLS client support allows these interactions to occur securely. -4. **Ingress and Egress Data Security**: Implementing TLS clients ensures that both incoming and outgoing data from the application is secure, a significant benefit in complex systems where both ingress and egress points need to be equally secure. -5. **CDN and Edge Computing**: TLS client support can ensure secure communication with Content Delivery Networks (CDNs) and edge computing resources, protecting data integrity and confidentiality while improving content delivery speed. -6. **Confidential Computing**: With TLS client support, applications can securely retrieve and use confidential data, cryptographic keys, or certificates from remote secure servers or key management systems. -7. **IoT Applications**: In IoT applications, devices often need to communicate with a central server. TLS client support can be used to ensure these communications are secure. - -## Conclusion - -The power of `epoll` and `TLS` makes WASIX more stable, secure and scalable than ever. - -This was a huge step for WASIX and we are really excited to see what the community builds with this. -We are also working on a few examples to showcase the power of WASIX. -You can try out our starter tutorial for outbound proxies [here](/todo/). More examples will follow suit. - -At the end, I would like to thank Frank Denis on the behalf of whole Wasmer Team for his work on the ring-wasi implementation and all of the wasmer team for their support and guidance and ofcourse their work on Wasmer 4.1. - -If you have any questions, feel free to reach out to us on [Discord](https://discord.gg/rWkMNStrEW). From 61586c3a06ffe78111634e52dd9b10370cf96832 Mon Sep 17 00:00:00 2001 From: Rudra Arora <aroraru@tcd.ie> Date: Wed, 9 Aug 2023 18:57:48 +0100 Subject: [PATCH 5/5] add: minor changes in sentences --- pages/docs/language-guide/rust/tutorials/wasix-axum.mdx | 2 +- pages/docs/language-guide/rust/tutorials/wasix-reqwest.mdx | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/pages/docs/language-guide/rust/tutorials/wasix-axum.mdx b/pages/docs/language-guide/rust/tutorials/wasix-axum.mdx index 568b4a2..22e353c 100644 --- a/pages/docs/language-guide/rust/tutorials/wasix-axum.mdx +++ b/pages/docs/language-guide/rust/tutorials/wasix-axum.mdx @@ -224,7 +224,7 @@ Yay, it works! 🎉 </Steps> <Callout type="info" emoji="ℹ️"> - You can also deploy you application to the edge. Checkout this + You can also deploy your application to the edge. Checkout this [tutorial](https://docs.wasmer.io/edge/quickstart/http-server) for deploying your wasix-axum server to wasmer edge. </Callout> diff --git a/pages/docs/language-guide/rust/tutorials/wasix-reqwest.mdx b/pages/docs/language-guide/rust/tutorials/wasix-reqwest.mdx index bf31497..049bb8a 100644 --- a/pages/docs/language-guide/rust/tutorials/wasix-reqwest.mdx +++ b/pages/docs/language-guide/rust/tutorials/wasix-reqwest.mdx @@ -4,12 +4,11 @@ import { Callout, FileTree } from "nextra-theme-docs"; <Callout type="default" emoji="🎉"> As of [wasmer 4.1](https://wasmer.io/posts/wasmer-4.1), `epoll` syscall and `TLS` clients are now supported in WASIX. This was done by compiling ring. - Read our whole blog post about it [here](/link/blog/epoll-n-tls/TODO). </Callout> ## WASIX with Reqwest -This is a sample project that shows how to use a Reqwest client to build an outbound proxy and compile it to WASIX. +This is a sample project that shows how to use a `reqwest` client to build an outbound proxy and compile it to WASIX. ### Prerequisites