From eac30f4ff2cb279d6ed5bb8279783a89d0047796 Mon Sep 17 00:00:00 2001 From: alexeiakimov Date: Fri, 28 Apr 2023 17:16:30 +0200 Subject: [PATCH 01/14] Performance of Rejections::into_response is improved. (#1005) Closes #1002 --- src/reject.rs | 60 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 44 insertions(+), 16 deletions(-) diff --git a/src/reject.rs b/src/reject.rs index fd0918841..23a4440f8 100644 --- a/src/reject.rs +++ b/src/reject.rs @@ -436,7 +436,7 @@ impl Rejections { | Known::BodyConsumedMultipleTimes(_) => StatusCode::INTERNAL_SERVER_ERROR, }, Rejections::Custom(..) => StatusCode::INTERNAL_SERVER_ERROR, - Rejections::Combined(ref a, ref b) => preferred(a, b).status(), + Rejections::Combined(..) => self.preferred().status(), } } @@ -465,7 +465,7 @@ impl Rejections { ); res } - Rejections::Combined(ref a, ref b) => preferred(a, b).into_response(), + Rejections::Combined(..) => self.preferred().into_response(), } } @@ -491,21 +491,30 @@ impl Rejections { } } } -} -fn preferred<'a>(a: &'a Rejections, b: &'a Rejections) -> &'a Rejections { - // Compare status codes, with this priority: - // - NOT_FOUND is lowest - // - METHOD_NOT_ALLOWED is second - // - if one status code is greater than the other - // - otherwise, prefer A... - match (a.status(), b.status()) { - (_, StatusCode::NOT_FOUND) => a, - (StatusCode::NOT_FOUND, _) => b, - (_, StatusCode::METHOD_NOT_ALLOWED) => a, - (StatusCode::METHOD_NOT_ALLOWED, _) => b, - (sa, sb) if sa < sb => b, - _ => a, + fn preferred(&self) -> &Rejections { + match self { + Rejections::Known(_) | Rejections::Custom(_) => self, + Rejections::Combined(a, b) => { + let a = a.preferred(); + let b = b.preferred(); + // Now both a and b are known or custom, so it is safe + // to get status + // Compare status codes, with this priority: + // - NOT_FOUND is lowest + // - METHOD_NOT_ALLOWED is second + // - if one status code is greater than the other + // - otherwise, prefer A... + match (a.status(), b.status()) { + (_, StatusCode::NOT_FOUND) => a, + (StatusCode::NOT_FOUND, _) => b, + (_, StatusCode::METHOD_NOT_ALLOWED) => a, + (StatusCode::METHOD_NOT_ALLOWED, _) => b, + (sa, sb) if sa < sb => b, + _ => a, + } + } + } } } @@ -841,4 +850,23 @@ mod tests { let s = format!("{:?}", rej); assert_eq!(s, "Rejection([X(0), X(1), X(2)])"); } + + #[test] + fn convert_big_rejections_into_response() { + let mut rejections = Rejections::Custom(Box::new(std::io::Error::from_raw_os_error(100))); + for _ in 0..50 { + rejections = Rejections::Combined( + Box::new(Rejections::Known(Known::MethodNotAllowed( + MethodNotAllowed { _p: () }, + ))), + Box::new(rejections), + ); + } + let reason = Reason::Other(Box::new(rejections)); + let rejection = Rejection { reason }; + assert_eq!( + StatusCode::INTERNAL_SERVER_ERROR, + rejection.into_response().status() + ); + } } From 220be141b218ffd9a4e4959429ca6fdafaad6c7a Mon Sep 17 00:00:00 2001 From: Sean McArthur Date: Fri, 28 Apr 2023 11:21:59 -0400 Subject: [PATCH 02/14] v0.3.5 --- CHANGELOG.md | 6 ++++++ Cargo.toml | 2 +- src/lib.rs | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 81ebd9e59..139a90b83 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +### v0.3.5 (April 28, 2023) + +- **Fixes**: + - `multipart` filters now use `multer` dependency, fixing some streaming bugs. + - `Rejection::into_response()` is significantly faster. + ### v0.3.4 (March 31, 2023) - **Fixes**: diff --git a/Cargo.toml b/Cargo.toml index dcd2d43f7..93ea57369 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "warp" -version = "0.3.4" # don't forget to update html_root_url +version = "0.3.5" # don't forget to update html_root_url description = "serve the web at warp speeds" authors = ["Sean McArthur "] license = "MIT" diff --git a/src/lib.rs b/src/lib.rs index 3f33a1260..f20e67c10 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -#![doc(html_root_url = "https://docs.rs/warp/0.3.4")] +#![doc(html_root_url = "https://docs.rs/warp/0.3.5")] #![deny(missing_docs)] #![deny(missing_debug_implementations)] #![deny(rust_2018_idioms)] From 4c1f7ba8536baef222bbe0a6fac741b82df66018 Mon Sep 17 00:00:00 2001 From: Jarred Nicholls Date: Fri, 5 May 2023 07:54:01 -0400 Subject: [PATCH 03/14] Add try_bind_with_graceful_shutdown method to the TlsServer (#717) To have fallible semantics rather than panics when a TLS configuration fails. --- src/server.rs | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/server.rs b/src/server.rs index f1eb33b95..929d96eb3 100644 --- a/src/server.rs +++ b/src/server.rs @@ -128,6 +128,10 @@ where ::Error: IsReject, { /// Run this `Server` forever on the current thread. + /// + /// # Panics + /// + /// Panics if we are unable to bind to the provided address. pub async fn run(self, addr: impl Into) { let (addr, fut) = self.bind_ephemeral(addr); let span = tracing::info_span!("Server::run", ?addr); @@ -275,6 +279,10 @@ where /// let _ = tx.send(()); /// # } /// ``` + /// + /// # Panics + /// + /// Panics if we are unable to bind to the provided address. pub fn bind_with_graceful_shutdown( self, addr: impl Into + 'static, @@ -516,6 +524,10 @@ where /// executed on a runtime. /// /// *This function requires the `"tls"` feature.* + /// + /// # Panics + /// + /// Panics if we are unable to bind to the provided address. pub async fn bind(self, addr: impl Into) { let (_, fut) = self.bind_ephemeral(addr); fut.await; @@ -527,6 +539,10 @@ where /// the current runtime. /// /// *This function requires the `"tls"` feature.* + /// + /// # Panics + /// + /// Panics if we are unable to bind to the provided address. pub fn bind_ephemeral( self, addr: impl Into, @@ -547,6 +563,10 @@ where /// process. /// /// *This function requires the `"tls"` feature.* + /// + /// # Panics + /// + /// Panics if we are unable to bind to the provided address. pub fn bind_with_graceful_shutdown( self, addr: impl Into + 'static, @@ -561,6 +581,28 @@ where }); (addr, fut) } + + /// Create a server with graceful shutdown signal. + /// + /// When the signal completes, the server will start the graceful shutdown + /// process. + /// + /// *This function requires the `"tls"` feature.* + pub fn try_bind_with_graceful_shutdown( + self, + addr: impl Into + 'static, + signal: impl Future + Send + 'static, + ) -> Result<(SocketAddr, impl Future + 'static), crate::Error> { + let addr = addr.into(); + let (addr, srv) = try_bind!(tls: self, &addr).map_err(crate::Error::new)?; + let srv = srv.with_graceful_shutdown(signal).map(|result| { + if let Err(err) = result { + tracing::error!("server error: {}", err) + } + }); + + Ok((addr, srv)) + } } #[cfg(feature = "tls")] From f9394045852ef55ace2b33650bf7d04645a8be83 Mon Sep 17 00:00:00 2001 From: kouta-kun <44276987+kouta-kun@users.noreply.github.com> Date: Thu, 1 Jun 2023 11:34:55 -0300 Subject: [PATCH 04/14] Doing only one call to field.data() can be incomplete, examples should iterate over it to explain how to read big files. (#1044) --- examples/multipart.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/examples/multipart.rs b/examples/multipart.rs index 40548d1e2..43215b165 100644 --- a/examples/multipart.rs +++ b/examples/multipart.rs @@ -9,13 +9,18 @@ async fn main() { let route = warp::multipart::form().and_then(|form: FormData| async move { let field_names: Vec<_> = form .and_then(|mut field| async move { - let contents = - String::from_utf8_lossy(field.data().await.unwrap().unwrap().chunk()) - .to_string(); + let mut bytes: Vec = Vec::new(); + + // field.data() only returns a piece of the content, you should call over it until it replies None + while let Some(content) = field.data().await { + let content = content.unwrap(); + let chunk: &[u8] = content.chunk(); + bytes.extend_from_slice(chunk); + } Ok(( field.name().to_string(), field.filename().unwrap().to_string(), - contents, + String::from_utf8_lossy(&*bytes).to_string(), )) }) .try_collect() From e65937c6a8834e28456eaf756110a351b347451b Mon Sep 17 00:00:00 2001 From: tottoto Date: Thu, 1 Jun 2023 23:41:51 +0900 Subject: [PATCH 05/14] deps: update pretty_env_logger to 0.5 (#1043) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 93ea57369..bc9bf1638 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,7 +44,7 @@ tokio-rustls = { version = "0.23", optional = true } rustls-pemfile = "1.0" [dev-dependencies] -pretty_env_logger = "0.4" +pretty_env_logger = "0.5" tracing-subscriber = { version = "0.3", features = ["env-filter"] } tracing-log = "0.1" serde_derive = "1.0" From d73dc543019448ef589d1cfd4a547d22a1a7cf8a Mon Sep 17 00:00:00 2001 From: Avery Edmondson <33769131+aedmondson@users.noreply.github.com> Date: Mon, 5 Jun 2023 14:19:33 -0700 Subject: [PATCH 06/14] updated Part.content_type() to return Mime.as_ref() string (#1046) --- src/filters/multipart.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/filters/multipart.rs b/src/filters/multipart.rs index 434c2a165..00948cb22 100644 --- a/src/filters/multipart.rs +++ b/src/filters/multipart.rs @@ -142,7 +142,7 @@ impl Part { /// Get the content-type of this part, if present. pub fn content_type(&self) -> Option<&str> { let content_type = self.part.content_type(); - content_type.map(|t| t.type_().as_str()) + content_type.map(|t| t.as_ref()) } /// Asynchronously get some of the data for this `Part`. From e562afac9a3fd77eee49859786bb3a9c3f654a2a Mon Sep 17 00:00:00 2001 From: Ville Outamaa Date: Mon, 12 Jun 2023 19:16:31 +0300 Subject: [PATCH 07/14] feat: add option to ignore content-length with multipart body (#919) The `max_length` field is changed to accept an `impl Into>`, so people can pass `None` to disable the limit. --- src/filters/multipart.rs | 24 ++++++++++++-------- tests/multipart.rs | 48 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 9 deletions(-) diff --git a/src/filters/multipart.rs b/src/filters/multipart.rs index 00948cb22..36c612939 100644 --- a/src/filters/multipart.rs +++ b/src/filters/multipart.rs @@ -27,7 +27,7 @@ const DEFAULT_FORM_DATA_MAX_LENGTH: u64 = 1024 * 1024 * 2; /// Create with the `warp::multipart::form()` function. #[derive(Debug, Clone)] pub struct FormOptions { - max_length: u64, + max_length: Option, } /// A `Stream` of multipart/form-data `Part`s. @@ -50,7 +50,7 @@ pub struct Part { /// in turn is a `Stream` of bytes. pub fn form() -> FormOptions { FormOptions { - max_length: DEFAULT_FORM_DATA_MAX_LENGTH, + max_length: Some(DEFAULT_FORM_DATA_MAX_LENGTH), } } @@ -59,9 +59,10 @@ pub fn form() -> FormOptions { impl FormOptions { /// Set the maximum byte length allowed for this body. /// + /// `max_length(None)` means that maximum byte length is not checked. /// Defaults to 2MB. - pub fn max_length(mut self, max: u64) -> Self { - self.max_length = max; + pub fn max_length(mut self, max: impl Into>) -> Self { + self.max_length = max.into(); self } } @@ -83,8 +84,7 @@ impl FilterBase for FormOptions { future::ready(mime) }); - let filt = super::body::content_length_limit(self.max_length) - .and(boundary) + let filt = boundary .and(super::body::body()) .map(|boundary: String, body| { let body = BodyIoError(body); @@ -93,9 +93,15 @@ impl FilterBase for FormOptions { } }); - let fut = filt.filter(Internal); - - Box::pin(fut) + if let Some(max_length) = self.max_length { + Box::pin( + super::body::content_length_limit(max_length) + .and(filt) + .filter(Internal), + ) + } else { + Box::pin(filt.filter(Internal)) + } } } diff --git a/tests/multipart.rs b/tests/multipart.rs index 3172367bc..ed98232be 100644 --- a/tests/multipart.rs +++ b/tests/multipart.rs @@ -52,3 +52,51 @@ async fn form_fields() { assert_eq!(&vec[0].0, "foo"); assert_eq!(&vec[0].1, b"bar"); } + +#[tokio::test] +async fn max_length_is_enforced() { + let _ = pretty_env_logger::try_init(); + + let route = multipart::form() + .and_then(|_: multipart::FormData| async { Ok::<(), warp::Rejection>(()) }); + + let boundary = "--abcdef1234--"; + + let req = warp::test::request() + .method("POST") + // Note no content-length header + .header("transfer-encoding", "chunked") + .header( + "content-type", + format!("multipart/form-data; boundary={}", boundary), + ); + + // Intentionally don't add body, as it automatically also adds + // content-length header + let resp = req.filter(&route).await; + assert!(resp.is_err()); +} + +#[tokio::test] +async fn max_length_can_be_disabled() { + let _ = pretty_env_logger::try_init(); + + let route = multipart::form() + .max_length(None) + .and_then(|_: multipart::FormData| async { Ok::<(), warp::Rejection>(()) }); + + let boundary = "--abcdef1234--"; + + let req = warp::test::request() + .method("POST") + .header("transfer-encoding", "chunked") + .header( + "content-type", + format!("multipart/form-data; boundary={}", boundary), + ); + + // Intentionally don't add body, as it automatically also adds + // content-length header + let resp = req.filter(&route).await; + assert!(resp.is_ok()); +} From da47391afe7ede0d0efc671ca9e29160deec7917 Mon Sep 17 00:00:00 2001 From: gtsiam Date: Fri, 21 Jul 2023 21:46:58 +0300 Subject: [PATCH 08/14] feat: implement Reply for Result (#909) --- src/reply.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/reply.rs b/src/reply.rs index 74dee278d..79e6dfd0e 100644 --- a/src/reply.rs +++ b/src/reply.rs @@ -411,18 +411,24 @@ impl Reply for ::http::StatusCode { } } -impl Reply for Result +impl Reply for ::http::Error { + #[inline] + fn into_response(self) -> Response { + tracing::error!("reply error: {:?}", self); + StatusCode::INTERNAL_SERVER_ERROR.into_response() + } +} + +impl Reply for Result where - T: Reply + Send, + T: Reply, + E: Reply, { #[inline] fn into_response(self) -> Response { match self { Ok(t) => t.into_response(), - Err(e) => { - tracing::error!("reply error: {:?}", e); - StatusCode::INTERNAL_SERVER_ERROR.into_response() - } + Err(e) => e.into_response(), } } } From 08ee8097a99ebb218c0ce78516a858956cae643c Mon Sep 17 00:00:00 2001 From: Sean McArthur Date: Thu, 27 Jul 2023 16:25:06 -0400 Subject: [PATCH 09/14] example: multipart is wrongly using Buf::chunk (#1055) --- examples/multipart.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/multipart.rs b/examples/multipart.rs index 43215b165..e28dd01de 100644 --- a/examples/multipart.rs +++ b/examples/multipart.rs @@ -1,6 +1,6 @@ +use bytes::BufMut; use futures_util::TryStreamExt; use warp::multipart::FormData; -use warp::Buf; use warp::Filter; #[tokio::main] @@ -14,8 +14,7 @@ async fn main() { // field.data() only returns a piece of the content, you should call over it until it replies None while let Some(content) = field.data().await { let content = content.unwrap(); - let chunk: &[u8] = content.chunk(); - bytes.extend_from_slice(chunk); + bytes.put(content); } Ok(( field.name().to_string(), From 376c80528fbf783dfb2825f8686698c3a51ac6d4 Mon Sep 17 00:00:00 2001 From: Louise Yousre <79291748+louiseyousre200@users.noreply.github.com> Date: Sat, 29 Jul 2023 19:31:12 +0300 Subject: [PATCH 10/14] More detailed redirects documentation (#1056) Added a description, usage and common use cases for each one of the redirects. --- src/redirect.rs | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/redirect.rs b/src/redirect.rs index ee2c3ad79..6e3746ab7 100644 --- a/src/redirect.rs +++ b/src/redirect.rs @@ -8,7 +8,10 @@ use http::{header, StatusCode}; pub use self::sealed::AsLocation; use crate::reply::{self, Reply}; -/// A simple `301` permanent redirect to a different location. +/// HTTP 301 Moved Permanently +/// Description: The requested resource has been permanently moved to a new URL. +/// Usage: It is used when a URL has permanently moved to a new location. Search engines will update their index to the new URL. Browsers and clients will automatically cache this redirect, so subsequent requests for the old URL will automatically go to the new URL without making a request to the old URL. +/// Common Use Case: Changing domain names, restructuring website URLs. /// /// # Example /// @@ -28,7 +31,10 @@ pub fn redirect(uri: impl AsLocation) -> impl Reply { ) } -/// A simple `302` found redirect to a different location +/// HTTP 302 Found (or Temporary Redirect) +/// Description: The requested resource can be found at a different URL temporarily. +/// Usage: Historically, this status code was used for temporary redirects. However, its meaning was often misunderstood, and different clients treated it differently. As a result, it is recommended to use 307 (or 303) for temporary redirects instead. +/// Common Use Case: Rarely used directly due to ambiguity; replaced by 307 or 303. /// /// # Example /// @@ -44,7 +50,10 @@ pub fn found(uri: impl AsLocation) -> impl Reply { reply::with_header(StatusCode::FOUND, header::LOCATION, uri.header_value()) } -/// A simple `303` redirect to a different location. +/// HTTP 303 See Other +/// Description: The response to the request can be found at a different URL, and the client should retrieve it using the GET method. +/// Usage: It is typically used to redirect the client to another URL using a GET request after processing a POST request. It ensures that the client doesn't repeat the POST request if they refresh the page. +/// Common Use Case: After form submissions or any non-idempotent request. /// /// The HTTP method of the request to the new location will always be `GET`. /// @@ -62,7 +71,10 @@ pub fn see_other(uri: impl AsLocation) -> impl Reply { reply::with_header(StatusCode::SEE_OTHER, header::LOCATION, uri.header_value()) } -/// A simple `307` temporary redirect to a different location. +/// HTTP 307 Temporary Redirect: +/// Description: The requested resource can be found at a different URL temporarily. +/// Usage: Similar to 302, but explicitly defined as a temporary redirect. The main difference between 307 and 302 is that 307 preserves the method of the original request when redirecting. If the original request was a POST, the subsequent request to the new URL will also be a POST. +/// Common Use Case: Temporary redirects that should preserve the original request method. /// /// This is similar to [`see_other`](fn@see_other) but the HTTP method and the body of the request /// to the new location will be the same as the method and body of the current request. @@ -85,7 +97,10 @@ pub fn temporary(uri: impl AsLocation) -> impl Reply { ) } -/// A simple `308` permanent redirect to a different location. +/// HTTP 308 Permanent Redirect +/// Description: The requested resource has been permanently moved to a new URL, and future requests should use the new URL. +/// Usage: Similar to 301, but like 307, it preserves the original request method when redirecting. It indicates that the redirection is permanent, and browsers and clients will cache this redirect like they do for 301. +// Common Use Case: Permanently moving resources to a new URL while maintaining the original request method. /// /// This is similar to [`redirect`](fn@redirect) but the HTTP method of the request to the new /// location will be the same as the method of the current request. From 149913fed948bbe2149b52b9016170bcaef950ab Mon Sep 17 00:00:00 2001 From: Nicholas Parker Date: Mon, 7 Aug 2023 04:09:40 +1200 Subject: [PATCH 11/14] Add example (and doc reference) for warp::body::stream() (#1061) * Add example (and doc reference) for warp::body::stream() As of right now it didn't look like there was example usage for this functionality. It took me some trial and error to figure out the typing for the Stream so that I could pass it into a handler function like this. This example hopefully avoids similar headaches for others. * cargo fmt --- examples/stream.rs | 30 ++++++++++++++++++++++++++++++ src/filters/body.rs | 2 ++ 2 files changed, 32 insertions(+) create mode 100644 examples/stream.rs diff --git a/examples/stream.rs b/examples/stream.rs new file mode 100644 index 000000000..d5f578357 --- /dev/null +++ b/examples/stream.rs @@ -0,0 +1,30 @@ +use bytes::Buf; +use futures_util::{Stream, StreamExt}; +use warp::{reply::Response, Filter, Reply}; + +#[tokio::main] +async fn main() { + // Running curl -T /path/to/a/file 'localhost:3030/' should echo back the content of the file, + // or an HTTP 413 error if the configured size limit is exceeded. + let route = warp::body::content_length_limit(65536) + .and(warp::body::stream()) + .then(handler); + warp::serve(route).run(([127, 0, 0, 1], 3030)).await; +} + +async fn handler( + mut body: impl Stream> + Unpin + Send + Sync, +) -> Response { + let mut collected: Vec = vec![]; + while let Some(buf) = body.next().await { + let mut buf = buf.unwrap(); + while buf.remaining() > 0 { + let chunk = buf.chunk(); + let chunk_len = chunk.len(); + collected.extend_from_slice(chunk); + buf.advance(chunk_len); + } + } + println!("Sending {} bytes", collected.len()); + collected.into_response() +} diff --git a/src/filters/body.rs b/src/filters/body.rs index 3bb08d2b4..85dabbfea 100644 --- a/src/filters/body.rs +++ b/src/filters/body.rs @@ -70,6 +70,8 @@ pub fn content_length_limit(limit: u64) -> impl Filter Date: Fri, 25 Aug 2023 12:33:08 +0100 Subject: [PATCH 12/14] Fix docs build (#1064) fix "Build docs" CI step. --- src/filters/any.rs | 2 +- src/filters/fs.rs | 2 +- src/filters/log.rs | 2 +- src/filters/reply.rs | 12 ++++++------ src/filters/sse.rs | 4 +++- src/filters/trace.rs | 2 +- src/filters/ws.rs | 2 +- src/lib.rs | 2 +- src/redirect.rs | 2 +- src/test.rs | 2 +- 10 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/filters/any.rs b/src/filters/any.rs index 707fd82dd..2b21b8c5e 100644 --- a/src/filters/any.rs +++ b/src/filters/any.rs @@ -9,7 +9,7 @@ use crate::filter::{Filter, FilterBase, Internal}; /// A filter that matches any route. /// /// This can be a useful building block to build new filters from, -/// since [`Filter`](crate::Filter) is otherwise a sealed trait. +/// since [`Filter`] is otherwise a sealed trait. /// /// # Example /// diff --git a/src/filters/fs.rs b/src/filters/fs.rs index 0949b66ec..fdfa70968 100644 --- a/src/filters/fs.rs +++ b/src/filters/fs.rs @@ -37,7 +37,7 @@ use crate::reply::{Reply, Response}; /// filters, such as after validating in `POST` request, wanting to return a /// specific file as the body. /// -/// For serving a directory, see [dir](dir). +/// For serving a directory, see [dir]. /// /// # Example /// diff --git a/src/filters/log.rs b/src/filters/log.rs index eae597402..1f93ab7d7 100644 --- a/src/filters/log.rs +++ b/src/filters/log.rs @@ -77,7 +77,7 @@ where Log { func } } -/// Decorates a [`Filter`](crate::Filter) to log requests and responses. +/// Decorates a [`Filter`] to log requests and responses. #[derive(Clone, Copy, Debug)] pub struct Log { func: F, diff --git a/src/filters/reply.rs b/src/filters/reply.rs index c4c37bbd8..42b661d3e 100644 --- a/src/filters/reply.rs +++ b/src/filters/reply.rs @@ -28,12 +28,12 @@ use self::sealed::{WithDefaultHeader_, WithHeader_, WithHeaders_}; use crate::filter::{Filter, Map, WrapSealed}; use crate::reply::Reply; -/// Wrap a [`Filter`](crate::Filter) that adds a header to the reply. +/// Wrap a [`Filter`] that adds a header to the reply. /// /// # Note /// /// This **only** adds a header if the underlying filter is successful, and -/// returns a [`Reply`](Reply). If the underlying filter was rejected, the +/// returns a [`Reply`] If the underlying filter was rejected, the /// header is not added. /// /// # Example @@ -57,12 +57,12 @@ where WithHeader { name, value } } -/// Wrap a [`Filter`](crate::Filter) that adds multiple headers to the reply. +/// Wrap a [`Filter`] that adds multiple headers to the reply. /// /// # Note /// /// This **only** adds a header if the underlying filter is successful, and -/// returns a [`Reply`](Reply). If the underlying filter was rejected, the +/// returns a [`Reply`] If the underlying filter was rejected, the /// header is not added. /// /// # Example @@ -88,13 +88,13 @@ pub fn headers(headers: HeaderMap) -> WithHeaders { // pub fn headers? -/// Wrap a [`Filter`](crate::Filter) that adds a header to the reply, if they +/// Wrap a [`Filter`] that adds a header to the reply, if they /// aren't already set. /// /// # Note /// /// This **only** adds a header if the underlying filter is successful, and -/// returns a [`Reply`](Reply). If the underlying filter was rejected, the +/// returns a [`Reply`] If the underlying filter was rejected, the /// header is not added. /// /// # Example diff --git a/src/filters/sse.rs b/src/filters/sse.rs index 2fb9b7ef1..413456aab 100644 --- a/src/filters/sse.rs +++ b/src/filters/sse.rs @@ -39,6 +39,8 @@ //! which specifies the expected behavior of Server Sent Events. //! +#![allow(rustdoc::invalid_html_tags)] + use serde::Serialize; use std::borrow::Cow; use std::error::Error as StdError; @@ -376,7 +378,7 @@ impl KeepAlive { /// Wrap an event stream with keep-alive functionality. /// - /// See [`keep_alive`](keep_alive) for more. + /// See [`keep_alive`] for more. pub fn stream( self, event_stream: S, diff --git a/src/filters/trace.rs b/src/filters/trace.rs index 5ca4e9df9..60686b430 100644 --- a/src/filters/trace.rs +++ b/src/filters/trace.rs @@ -123,7 +123,7 @@ pub fn named(name: &'static str) -> Trace) -> Span + Copy> { trace(move |_| tracing::debug_span!("context", "{}", name,)) } -/// Decorates a [`Filter`](crate::Filter) to create a [`tracing`] [span] for +/// Decorates a [`Filter`] to create a [`tracing`] [span] for /// requests and responses. /// /// [`tracing`]: https://crates.io/crates/tracing diff --git a/src/filters/ws.rs b/src/filters/ws.rs index 1e953c7a3..e5ae62c43 100644 --- a/src/filters/ws.rs +++ b/src/filters/ws.rs @@ -68,7 +68,7 @@ pub fn ws() -> impl Filter, Error = Rejection> + Copy { ) } -/// Extracted by the [`ws`](ws) filter, and used to finish an upgrade. +/// Extracted by the [`ws`] filter, and used to finish an upgrade. pub struct Ws { config: Option, key: SecWebsocketKey, diff --git a/src/lib.rs b/src/lib.rs index f20e67c10..6bc4cf0c9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -81,7 +81,7 @@ //! ## Testing //! //! Testing your web services easily is extremely important, and warp provides -//! a [`test`](self::test) module to help send mocked requests through your service. +//! a [`test`](mod@self::test) module to help send mocked requests through your service. //! //! [Filter]: trait.Filter.html //! [reject]: reject/index.html diff --git a/src/redirect.rs b/src/redirect.rs index 6e3746ab7..373ab546f 100644 --- a/src/redirect.rs +++ b/src/redirect.rs @@ -1,6 +1,6 @@ //! Redirect requests to a new location. //! -//! The types in this module are helpers that implement [`Reply`](Reply), and easy +//! The types in this module are helpers that implement [`Reply`], and easy //! to use in order to setup redirects. use http::{header, StatusCode}; diff --git a/src/test.rs b/src/test.rs index 3c67c34d8..ca2710fae 100644 --- a/src/test.rs +++ b/src/test.rs @@ -366,7 +366,7 @@ impl RequestBuilder { /// Returns `Response` provided by applying the `Filter`. /// - /// This requires that the supplied `Filter` return a [`Reply`](Reply). + /// This requires that the supplied `Filter` return a [`Reply`]. pub async fn reply(self, f: &F) -> Response where F: Filter + 'static, From 2f2c74471a2dd83f58d2f29ef2cc74163ac29fe2 Mon Sep 17 00:00:00 2001 From: Jeron Aldaron Lau Date: Fri, 25 Aug 2023 06:43:23 -0500 Subject: [PATCH 13/14] Update tokio-rustls to 0.24 (Fix RUSTSEC-2023-0052 when "tls" feature enabled) (#1063) --- Cargo.toml | 2 +- src/tls.rs | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index bc9bf1638..002de45d2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,7 +40,7 @@ tower-service = "0.3" tokio-tungstenite = { version = "0.18", optional = true } percent-encoding = "2.1" pin-project = "1.0" -tokio-rustls = { version = "0.23", optional = true } +tokio-rustls = { version = "0.24", optional = true } rustls-pemfile = "1.0" [dev-dependencies] diff --git a/src/tls.rs b/src/tls.rs index 1f81a6bd2..96b6ed74e 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -221,18 +221,19 @@ impl TlsConfigBuilder { } let client_auth = match self.client_auth { - TlsClientAuth::Off => NoClientAuth::new(), + TlsClientAuth::Off => NoClientAuth::boxed(), TlsClientAuth::Optional(trust_anchor) => { AllowAnyAnonymousOrAuthenticatedClient::new(read_trust_anchor(trust_anchor)?) + .boxed() } TlsClientAuth::Required(trust_anchor) => { - AllowAnyAuthenticatedClient::new(read_trust_anchor(trust_anchor)?) + AllowAnyAuthenticatedClient::new(read_trust_anchor(trust_anchor)?).boxed() } }; let mut config = ServerConfig::builder() .with_safe_defaults() - .with_client_cert_verifier(client_auth.into()) + .with_client_cert_verifier(client_auth) .with_single_cert_with_ocsp_and_sct(cert, key, self.ocsp_resp, Vec::new()) .map_err(TlsConfigError::InvalidKey)?; config.alpn_protocols = vec!["h2".into(), "http/1.1".into()]; From 5ad8a9cb155f6485d13d591a564d8c70053a388a Mon Sep 17 00:00:00 2001 From: belgoking Date: Mon, 28 Aug 2023 14:46:20 +0200 Subject: [PATCH 14/14] Add references to `Filter` in documentation (#1062) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Tobias Kölsch --- src/filter/boxed.rs | 2 +- src/filters/any.rs | 2 +- src/filters/cors.rs | 4 ++-- src/filters/log.rs | 4 ++-- src/filters/multipart.rs | 6 +++--- src/filters/path.rs | 6 +++--- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/filter/boxed.rs b/src/filter/boxed.rs index 1ed4a7d80..5dd43cbca 100644 --- a/src/filter/boxed.rs +++ b/src/filter/boxed.rs @@ -8,7 +8,7 @@ use futures_util::TryFutureExt; use super::{Filter, FilterBase, Internal, Tuple}; use crate::reject::Rejection; -/// A type representing a boxed `Filter` trait object. +/// A type representing a boxed [`Filter`](crate::Filter) trait object. /// /// The filter inside is a dynamic trait object. The purpose of this type is /// to ease returning `Filter`s from other functions. diff --git a/src/filters/any.rs b/src/filters/any.rs index 2b21b8c5e..7328b8a64 100644 --- a/src/filters/any.rs +++ b/src/filters/any.rs @@ -6,7 +6,7 @@ use std::task::{Context, Poll}; use crate::filter::{Filter, FilterBase, Internal}; -/// A filter that matches any route. +/// A [`Filter`](crate::Filter) that matches any route. /// /// This can be a useful building block to build new filters from, /// since [`Filter`] is otherwise a sealed trait. diff --git a/src/filters/cors.rs b/src/filters/cors.rs index fa28893c2..39ea240e3 100644 --- a/src/filters/cors.rs +++ b/src/filters/cors.rs @@ -20,7 +20,7 @@ use crate::reply::Reply; use self::internal::{CorsFilter, IntoOrigin, Seconds}; -/// Create a wrapping filter that exposes [CORS][] behavior for a wrapped +/// Create a wrapping [`Filter`](crate::Filter) that exposes [CORS][] behavior for a wrapped /// filter. /// /// [CORS]: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS @@ -56,7 +56,7 @@ pub fn cors() -> Builder { } } -/// A wrapping filter constructed via `warp::cors()`. +/// A wrapping [`Filter`](crate::Filter) constructed via `warp::cors()`. #[derive(Clone, Debug)] pub struct Cors { config: Arc, diff --git a/src/filters/log.rs b/src/filters/log.rs index 1f93ab7d7..3790fd8a8 100644 --- a/src/filters/log.rs +++ b/src/filters/log.rs @@ -13,7 +13,7 @@ use crate::route::Route; use self::internal::WithLog; -/// Create a wrapping filter with the specified `name` as the `target`. +/// Create a wrapping [`Filter`](crate::Filter) with the specified `name` as the `target`. /// /// This uses the default access logging format, and log records produced /// will have their `target` set to `name`. @@ -50,7 +50,7 @@ pub fn log(name: &'static str) -> Log) + Copy> { Log { func } } -/// Create a wrapping filter that receives `warp::log::Info`. +/// Create a wrapping [`Filter`](crate::Filter) that receives `warp::log::Info`. /// /// # Example /// diff --git a/src/filters/multipart.rs b/src/filters/multipart.rs index 36c612939..103f25760 100644 --- a/src/filters/multipart.rs +++ b/src/filters/multipart.rs @@ -1,6 +1,6 @@ //! Multipart body filters //! -//! Filters that extract a multipart body for a route. +//! [`Filter`](crate::Filter)s that extract a multipart body for a route. use std::error::Error as StdError; use std::fmt::{Display, Formatter}; @@ -22,7 +22,7 @@ use crate::reject::{self, Rejection}; // If not otherwise configured, default to 2MB. const DEFAULT_FORM_DATA_MAX_LENGTH: u64 = 1024 * 1024 * 2; -/// A `Filter` to extract a `multipart/form-data` body from a request. +/// A [`Filter`](crate::Filter) to extract a `multipart/form-data` body from a request. /// /// Create with the `warp::multipart::form()` function. #[derive(Debug, Clone)] @@ -44,7 +44,7 @@ pub struct Part { part: PartInner<'static>, } -/// Create a `Filter` to extract a `multipart/form-data` body from a request. +/// Create a [`Filter`](crate::Filter) to extract a `multipart/form-data` body from a request. /// /// The extracted `FormData` type is a `Stream` of `Part`s, and each `Part` /// in turn is a `Stream` of bytes. diff --git a/src/filters/path.rs b/src/filters/path.rs index 179a8d1c9..29676a729 100644 --- a/src/filters/path.rs +++ b/src/filters/path.rs @@ -1,6 +1,6 @@ //! Path Filters //! -//! The filters here work on the "path" of requests. +//! The [`Filter`](crate::Filter)s here work on the "path" of requests. //! //! - [`path`](./fn.path.html) matches a specific segment, like `/foo`. //! - [`param`](./fn.param.html) tries to parse a segment into a type, like `/:u16`. @@ -137,7 +137,7 @@ use crate::filter::{filter_fn, one, Filter, FilterBase, Internal, One, Tuple}; use crate::reject::{self, Rejection}; use crate::route::{self, Route}; -/// Create an exact match path segment `Filter`. +/// Create an exact match path segment [`Filter`](crate::Filter). /// /// This will try to match exactly to the current request path segment. /// @@ -189,7 +189,7 @@ where */ } -/// A `Filter` matching an exact path segment. +/// A [`Filter`](crate::Filter) matching an exact path segment. /// /// Constructed from `path()` or `path!()`. #[allow(missing_debug_implementations)]