diff --git a/worker/Cargo.toml b/worker/Cargo.toml index 7988f670f..8409deee1 100644 --- a/worker/Cargo.toml +++ b/worker/Cargo.toml @@ -64,9 +64,15 @@ version = "0.7" optional = true default-features = false +[dependencies.tower] +version = "0.5.1" +optional = true +default-features = false +features = ["util", "buffer"] + [features] queue = ["worker-macros/queue", "worker-sys/queue"] d1 = ["worker-sys/d1"] -http = ["worker-macros/http"] +http = ["worker-macros/http", "dep:tower"] axum = ["dep:axum"] timezone = ["dep:chrono-tz"] diff --git a/worker/src/global.rs b/worker/src/global.rs index 5a33635c2..b18e64993 100644 --- a/worker/src/global.rs +++ b/worker/src/global.rs @@ -14,18 +14,18 @@ pub enum Fetch { impl Fetch { /// Execute a Fetch call and receive a Response. - pub async fn send(&self) -> Result { + pub async fn send(self) -> Result { match self { Fetch::Url(url) => fetch_with_str(url.as_ref(), None).await, - Fetch::Request(req) => fetch_with_request(req, None).await, + Fetch::Request(req) => fetch_with_request(req.to_owned(), None).await, } } /// Execute a Fetch call and receive a Response. - pub async fn send_with_signal(&self, signal: &AbortSignal) -> Result { + pub async fn send_with_signal(self, signal: &AbortSignal) -> Result { match self { Fetch::Url(url) => fetch_with_str(url.as_ref(), Some(signal)).await, - Fetch::Request(req) => fetch_with_request(req, Some(signal)).await, + Fetch::Request(req) => fetch_with_request(req.to_owned(), Some(signal)).await, } } } @@ -41,7 +41,7 @@ async fn fetch_with_str(url: &str, signal: Option<&AbortSignal>) -> Result) -> Result { +async fn fetch_with_request(request: Request, signal: Option<&AbortSignal>) -> Result { let init = web_sys::RequestInit::new(); init.set_signal(signal.map(|x| x.deref())); diff --git a/worker/src/http.rs b/worker/src/http.rs index 9ae29480a..e6761677e 100644 --- a/worker/src/http.rs +++ b/worker/src/http.rs @@ -10,6 +10,8 @@ mod redirect; pub mod request; #[cfg(feature = "http")] pub mod response; +#[cfg(feature = "http")] +pub mod service; /// A [`Method`](https://developer.mozilla.org/en-US/docs/Web/API/Request/method) representation /// used on Request objects. diff --git a/worker/src/http/service.rs b/worker/src/http/service.rs new file mode 100644 index 000000000..fb91fb94c --- /dev/null +++ b/worker/src/http/service.rs @@ -0,0 +1,43 @@ +use std::convert::TryInto; +use std::task::Context; +use std::{future::Future, pin::Pin, task::Poll}; + +use crate::send::SendFuture; +use crate::{Body, Error, Fetch, HttpResponse, Request}; + +/// A Tower-compatible Service implementation for Cloudflare Workers. +/// +/// This struct implements the `tower::Service` trait, allowing it to be used +/// as a service in the Tower middleware ecosystem. +#[derive(Debug, Default, Clone, Copy)] +pub struct Service; + +impl + Clone + 'static> tower::Service> + for Service +{ + type Response = http::Response; + type Error = Error; + type Future = + Pin> + Send>>; + + fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll> { + Poll::Ready(Ok(())) + } + + fn call(&mut self, req: http::Request) -> Self::Future { + // Convert a http Request to a worker Request + let worker_request: Request = req.try_into().unwrap(); + + // Send the request with Fetch and receive a Future + let fut = Fetch::Request(worker_request).send(); + + // Convert the Future output to a HttpResponse + let http_response = + async { Ok(TryInto::::try_into(fut.await.unwrap()).unwrap()) }; + + // Wrap the Future in a SendFuture to make it Send + let wrapped = SendFuture::new(http_response); + + Box::pin(wrapped) + } +} diff --git a/worker/src/lib.rs b/worker/src/lib.rs index ddeccf288..01c6a2939 100644 --- a/worker/src/lib.rs +++ b/worker/src/lib.rs @@ -248,3 +248,5 @@ pub type HttpRequest = ::http::Request; #[cfg(feature = "http")] /// **Requires** `http` feature. Type alias for `http::Response`. pub type HttpResponse = ::http::Response; +#[cfg(feature = "http")] +pub use http::service::Service; diff --git a/worker/src/request.rs b/worker/src/request.rs index 6be8a7b80..712d1e18d 100644 --- a/worker/src/request.rs +++ b/worker/src/request.rs @@ -16,7 +16,7 @@ use worker_sys::ext::RequestExt; /// A [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) representation for /// handling incoming and creating outbound HTTP requests. -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Request { method: Method, path: String,