From f2e736719a19baae32a52cb6b3fd3c0c424b569e Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Thu, 20 Jan 2022 01:25:46 +0000 Subject: [PATCH 1/5] add url_for test for conflicting named resources --- actix-web-codegen/src/lib.rs | 12 +++--- src/config.rs | 10 ++++- src/request.rs | 52 ++++++++++++++++++++-- src/rmap.rs | 83 ++++++++++++++++++++++++++++++++---- src/service.rs | 1 + 5 files changed, 139 insertions(+), 19 deletions(-) diff --git a/actix-web-codegen/src/lib.rs b/actix-web-codegen/src/lib.rs index 52cfc0d8f..480fd2e4b 100644 --- a/actix-web-codegen/src/lib.rs +++ b/actix-web-codegen/src/lib.rs @@ -39,7 +39,7 @@ //! ``` //! # use actix_web::HttpResponse; //! # use actix_web_codegen::route; -//! #[route("/test", method="GET", method="HEAD")] +//! #[route("/test", method = "GET", method = "HEAD")] //! async fn get_and_head_handler() -> HttpResponse { //! HttpResponse::Ok().finish() //! } @@ -74,10 +74,12 @@ mod route; /// /// # Attributes /// - `"path"` - Raw literal string with path for which to register handler. -/// - `name="resource_name"` - Specifies resource name for the handler. If not set, the function name of handler is used. -/// - `method="HTTP_METHOD"` - Registers HTTP method to provide guard for. Upper-case string, "GET", "POST" for example. -/// - `guard="function_name"` - Registers function as guard using `actix_web::guard::fn_guard` -/// - `wrap="Middleware"` - Registers a resource middleware. +/// - `name = "resource_name"` - Specifies resource name for the handler. If not set, the function +/// name of handler is used. +/// - `method = "HTTP_METHOD"` - Registers HTTP method to provide guard for. Upper-case string, +/// "GET", "POST" for example. +/// - `guard = "function_name"` - Registers function as guard using `actix_web::guard::fn_guard` +/// - `wrap = "Middleware"` - Registers a resource middleware. /// /// # Notes /// Function name can be specified as any expression that is going to be accessible to the generate diff --git a/src/config.rs b/src/config.rs index 77fba18ed..9fe75df97 100644 --- a/src/config.rs +++ b/src/config.rs @@ -102,8 +102,14 @@ impl AppService { InitError = (), > + 'static, { - self.services - .push((rdef, boxed::factory(factory.into_factory()), guards, nested)); + dbg!(rdef.pattern()); + + self.services.push(( + rdef, + boxed::factory(factory.into_factory()), + guards, + dbg!(nested), + )); } } diff --git a/src/request.rs b/src/request.rs index 63db56fd3..61b820950 100644 --- a/src/request.rs +++ b/src/request.rs @@ -508,10 +508,12 @@ mod tests { use bytes::Bytes; use super::*; - use crate::dev::{ResourceDef, ResourceMap}; - use crate::http::{header, StatusCode}; - use crate::test::{call_service, init_service, read_body, TestRequest}; - use crate::{web, App, HttpResponse}; + use crate::{ + dev::{ResourceDef, ResourceMap}, + http::{header, StatusCode}, + test::{self, call_service, init_service, read_body, TestRequest}, + web, App, HttpResponse, + }; #[test] fn test_debug() { @@ -865,4 +867,46 @@ mod tests { let res = call_service(&srv, req).await; assert_eq!(res.status(), StatusCode::OK); } + + #[actix_rt::test] + async fn url_for_closest_named_resource() { + // we mount the route named 'nested' on 2 different scopes, 'a' and 'b' + let srv = test::init_service( + App::new() + .service( + web::scope("/foo") + .service(web::resource("/nested").name("nested").route(web::get().to( + |req: HttpRequest| { + HttpResponse::Ok() + .body(format!("{}", req.url_for_static("nested").unwrap())) + }, + ))) + .service(web::scope("/baz").service(web::resource("deep"))) + .service(web::resource("{foo_param}")), + ) + .service(web::scope("/bar").service( + web::resource("/nested").name("nested").route(web::get().to( + |req: HttpRequest| { + HttpResponse::Ok() + .body(format!("{}", req.url_for_static("nested").unwrap())) + }, + )), + )), + ) + .await; + + let foo_resp = + test::call_service(&srv, TestRequest::with_uri("/foo/nested").to_request()).await; + assert_eq!(foo_resp.status(), StatusCode::OK); + let body = read_body(foo_resp).await; + // XXX: body equals http://localhost:8080/bar/nested + // because nested from /bar overrides /foo's + assert_eq!(body, "http://localhost:8080/bar/nested"); + + let bar_resp = + test::call_service(&srv, TestRequest::with_uri("/bar/nested").to_request()).await; + assert_eq!(bar_resp.status(), StatusCode::OK); + let body = read_body(bar_resp).await; + assert_eq!(body, "http://localhost:8080/bar/nested"); + } } diff --git a/src/rmap.rs b/src/rmap.rs index 432eaf83c..932f7acde 100644 --- a/src/rmap.rs +++ b/src/rmap.rs @@ -1,6 +1,7 @@ use std::{ borrow::Cow, cell::RefCell, + fmt::Write as _, rc::{Rc, Weak}, }; @@ -10,12 +11,14 @@ use url::Url; use crate::{error::UrlGenerationError, request::HttpRequest}; +const AVG_PATH_LEN: usize = 24; + #[derive(Clone, Debug)] pub struct ResourceMap { pattern: ResourceDef, - /// Named resources within the tree or, for external resources, - /// it points to isolated nodes outside the tree. + /// Named resources within the tree or, for external resources, it points to isolated nodes + /// outside the tree. named: AHashMap>, parent: RefCell>, @@ -35,6 +38,35 @@ impl ResourceMap { } } + /// Format resource map as tree structure (unfinished). + #[allow(dead_code)] + pub(crate) fn tree(&self) -> String { + let mut buf = String::new(); + self._tree(&mut buf, 0); + buf + } + + pub(crate) fn _tree(&self, buf: &mut String, level: usize) { + if let Some(children) = &self.nodes { + for child in children { + writeln!( + buf, + "{}{} {}", + "--".repeat(level), + child.pattern.pattern().unwrap(), + child + .pattern + .name() + .map(|name| format!("({})", name)) + .unwrap_or_else(|| "".to_owned()) + ) + .unwrap(); + + ResourceMap::_tree(child, buf, level + 1); + } + } + } + /// Adds a (possibly nested) resource. /// /// To add a non-prefix pattern, `nested` must be `None`. @@ -44,7 +76,11 @@ impl ResourceMap { pattern.set_id(self.nodes.as_ref().unwrap().len() as u16); if let Some(new_node) = nested { - assert_eq!(&new_node.pattern, pattern, "`patern` and `nested` mismatch"); + debug_assert_eq!( + &new_node.pattern, pattern, + "`pattern` and `nested` mismatch" + ); + // parents absorb references to the named resources of children self.named.extend(new_node.named.clone().into_iter()); self.nodes.as_mut().unwrap().push(new_node); } else { @@ -64,7 +100,7 @@ impl ResourceMap { None => false, }; - // Don't add external resources to the tree + // don't add external resources to the tree if !is_external { self.nodes.as_mut().unwrap().push(new_node); } @@ -78,7 +114,7 @@ impl ResourceMap { } } - /// Generate url for named resource + /// Generate URL for named resource. /// /// Check [`HttpRequest::url_for`] for detailed information. pub fn url_for( @@ -97,7 +133,7 @@ impl ResourceMap { .named .get(name) .ok_or(UrlGenerationError::ResourceNotFound)? - .root_rmap_fn(String::with_capacity(24), |mut acc, node| { + .root_rmap_fn(String::with_capacity(AVG_PATH_LEN), |mut acc, node| { node.pattern .resource_path_from_iter(&mut acc, &mut elements) .then(|| acc) @@ -128,6 +164,7 @@ impl ResourceMap { Ok(url) } + /// Returns true if there is a resource that would match `path`. pub fn has_resource(&self, path: &str) -> bool { self.find_matching_node(path).is_some() } @@ -142,9 +179,10 @@ impl ResourceMap { /// is possible. pub fn match_pattern(&self, path: &str) -> Option { self.find_matching_node(path)?.root_rmap_fn( - String::with_capacity(24), + String::with_capacity(AVG_PATH_LEN), |mut acc, node| { - acc.push_str(node.pattern.pattern()?); + let pattern = node.pattern.pattern()?; + acc.push_str(pattern); Some(acc) }, ) @@ -490,4 +528,33 @@ mod tests { "https://duck.com/abcd" ); } + + #[test] + fn url_for_override_within_map() { + let mut root = ResourceMap::new(ResourceDef::prefix("")); + + let mut foo_rdef = ResourceDef::prefix("/foo"); + let mut foo_map = ResourceMap::new(foo_rdef.clone()); + let mut nested_rdef = ResourceDef::new("/nested"); + nested_rdef.set_name("nested"); + foo_map.add(&mut nested_rdef, None); + root.add(&mut foo_rdef, Some(Rc::new(foo_map))); + + let mut foo_rdef = ResourceDef::prefix("/bar"); + let mut foo_map = ResourceMap::new(foo_rdef.clone()); + let mut nested_rdef = ResourceDef::new("/nested"); + nested_rdef.set_name("nested"); + foo_map.add(&mut nested_rdef, None); + root.add(&mut foo_rdef, Some(Rc::new(foo_map))); + + let rmap = Rc::new(root); + ResourceMap::finish(&rmap); + + let req = crate::test::TestRequest::default().to_http_request(); + + let url = rmap.url_for(&req, "nested", &[""; 0]).unwrap().to_string(); + assert_eq!(url, "http://localhost:8080/bar/nested"); + + assert!(rmap.url_for(&req, "missing", &["u123"]).is_err()); + } } diff --git a/src/service.rs b/src/service.rs index 81424a654..061c3e044 100644 --- a/src/service.rs +++ b/src/service.rs @@ -831,6 +831,7 @@ mod tests { let req = ServiceRequest::from_parts(req, pl); svc.call(req) }) + .route("/", web::get().to(|| async { "" })) .service( web::resource("/resource1/{name}/index.html").route(web::get().to(index)), ), From 68ad81f9891fa95252755580dac1da9169035f56 Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Thu, 20 Jan 2022 01:30:05 +0000 Subject: [PATCH 2/5] remove debug logs --- src/config.rs | 10 ++-------- src/middleware/logger.rs | 2 -- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/src/config.rs b/src/config.rs index 9fe75df97..77fba18ed 100644 --- a/src/config.rs +++ b/src/config.rs @@ -102,14 +102,8 @@ impl AppService { InitError = (), > + 'static, { - dbg!(rdef.pattern()); - - self.services.push(( - rdef, - boxed::factory(factory.into_factory()), - guards, - dbg!(nested), - )); + self.services + .push((rdef, boxed::factory(factory.into_factory()), guards, nested)); } } diff --git a/src/middleware/logger.rs b/src/middleware/logger.rs index 969cb0c10..63055ecba 100644 --- a/src/middleware/logger.rs +++ b/src/middleware/logger.rs @@ -700,7 +700,6 @@ mod tests { Ok(()) }; let s = format!("{}", FormatDisplay(&render)); - println!("{}", s); assert!(s.contains("/test/route/yeah")); } @@ -794,7 +793,6 @@ mod tests { Ok(()) }; let s = format!("{}", FormatDisplay(&render)); - println!("{}", s); assert!(s.contains("192.0.2.60")); } From f227e880d78b6f04ea0c57d588c1ed306ba1eed7 Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Thu, 20 Jan 2022 01:53:02 +0000 Subject: [PATCH 3/5] refactor route codegen to be cleaner --- actix-web-codegen/src/lib.rs | 124 ++++++++++++++++------------------- src/request.rs | 3 +- 2 files changed, 59 insertions(+), 68 deletions(-) diff --git a/actix-web-codegen/src/lib.rs b/actix-web-codegen/src/lib.rs index 480fd2e4b..38e3cc379 100644 --- a/actix-web-codegen/src/lib.rs +++ b/actix-web-codegen/src/lib.rs @@ -45,7 +45,12 @@ //! } //! ``` //! -//! [actix-web attributes docs]: https://docs.rs/actix-web/*/actix_web/#attributes +//! # Multiple Path Handlers +//! There are no macros to generate multi-path handlers. Let us know in [this issue]. +//! +//! [this issue]: https://github.com/actix/actix-web/issues/1709 +//! +//! [actix-web attributes docs]: https://docs.rs/actix-web/latest/actix_web/#attributes //! [GET]: macro@get //! [POST]: macro@post //! [PUT]: macro@put @@ -73,24 +78,23 @@ mod route; /// ``` /// /// # Attributes -/// - `"path"` - Raw literal string with path for which to register handler. -/// - `name = "resource_name"` - Specifies resource name for the handler. If not set, the function +/// - `"path"`: Raw literal string with path for which to register handler. +/// - `name = "resource_name"`: Specifies resource name for the handler. If not set, the function /// name of handler is used. -/// - `method = "HTTP_METHOD"` - Registers HTTP method to provide guard for. Upper-case string, +/// - `method = "HTTP_METHOD"`: Registers HTTP method to provide guard for. Upper-case string, /// "GET", "POST" for example. -/// - `guard = "function_name"` - Registers function as guard using `actix_web::guard::fn_guard` -/// - `wrap = "Middleware"` - Registers a resource middleware. +/// - `guard = "function_name"`: Registers function as guard using `actix_web::guard::fn_guard`. +/// - `wrap = "Middleware"`: Registers a resource middleware. /// /// # Notes /// Function name can be specified as any expression that is going to be accessible to the generate /// code, e.g `my_guard` or `my_module::my_guard`. /// -/// # Example -/// +/// # Examples /// ``` /// # use actix_web::HttpResponse; /// # use actix_web_codegen::route; -/// #[route("/test", method="GET", method="HEAD")] +/// #[route("/test", method = "GET", method = "HEAD")] /// async fn example() -> HttpResponse { /// HttpResponse::Ok().finish() /// } @@ -100,69 +104,55 @@ pub fn route(args: TokenStream, input: TokenStream) -> TokenStream { route::with_method(None, args, input) } -macro_rules! doc_comment { - ($x:expr; $($tt:tt)*) => { - #[doc = $x] - $($tt)* - }; -} - macro_rules! method_macro { - ( - $($variant:ident, $method:ident,)+ - ) => { - $(doc_comment! { -concat!(" -Creates route handler with `actix_web::guard::", stringify!($variant), "`. - -# Syntax -```plain -#[", stringify!($method), r#"("path"[, attributes])] -``` - -# Attributes -- `"path"` - Raw literal string with path for which to register handler. -- `name="resource_name"` - Specifies resource name for the handler. If not set, the function name of handler is used. -- `guard="function_name"` - Registers function as guard using `actix_web::guard::fn_guard`. -- `wrap="Middleware"` - Registers a resource middleware. - -# Notes -Function name can be specified as any expression that is going to be accessible to the generate -code, e.g `my_guard` or `my_module::my_guard`. - -# Example - -``` -# use actix_web::HttpResponse; -# use actix_web_codegen::"#, stringify!($method), "; -#[", stringify!($method), r#"("/")] -async fn example() -> HttpResponse { - HttpResponse::Ok().finish() -} -``` -"#); - #[proc_macro_attribute] - pub fn $method(args: TokenStream, input: TokenStream) -> TokenStream { - route::with_method(Some(route::MethodType::$variant), args, input) - } - })+ + ($variant:ident, $method:ident) => { + #[doc = concat!("Creates route handler with `actix_web::guard::", stringify!($variant), "`.")] + /// + /// # Syntax + /// ```plain + #[doc = concat!("#[", stringify!($method), r#"("path"[, attributes])]"#)] + /// ``` + /// + /// # Attributes + /// - `"path"`: Raw literal string with path for which to register handler. + /// - `name = "resource_name"`: Specifies resource name for the handler. If not set, the + /// function name of handler is used. + /// - `guard = "function_name"`: Registers function as guard. + /// using `actix_web::guard::fn_guard`. + /// - `wrap = "Middleware"`: Registers a resource middleware. + /// + /// # Notes + /// Function name can be specified as any expression that is going to be accessible to the generate + /// code, e.g `my_guard` or `my_module::my_guard`. + /// + /// # Example + /// ``` + /// # use actix_web::HttpResponse; + #[doc = concat!("# use actix_web_codegen::", stringify!($method), ";")] + #[doc = concat!("#[", stringify!($method), r#"("/")]"#)] + /// async fn example() -> HttpResponse { + /// HttpResponse::Ok().finish() + /// } + /// ``` + #[proc_macro_attribute] + pub fn $method(args: TokenStream, input: TokenStream) -> TokenStream { + route::with_method(Some(route::MethodType::$variant), args, input) + } }; } -method_macro! { - Get, get, - Post, post, - Put, put, - Delete, delete, - Head, head, - Connect, connect, - Options, options, - Trace, trace, - Patch, patch, -} - -/// Marks async main function as the actix system entry-point. +method_macro!(Get, get); +method_macro!(Post, post); +method_macro!(Put, put); +method_macro!(Delete, delete); +method_macro!(Head, head); +method_macro!(Connect, connect); +method_macro!(Options, options); +method_macro!(Trace, trace); +method_macro!(Patch, patch); +/// Marks async main function as the Actix Web system entry-point. +/// /// # Examples /// ``` /// #[actix_web::main] diff --git a/src/request.rs b/src/request.rs index 61b820950..b3db5ffbd 100644 --- a/src/request.rs +++ b/src/request.rs @@ -899,8 +899,9 @@ mod tests { test::call_service(&srv, TestRequest::with_uri("/foo/nested").to_request()).await; assert_eq!(foo_resp.status(), StatusCode::OK); let body = read_body(foo_resp).await; - // XXX: body equals http://localhost:8080/bar/nested + // `body` equals http://localhost:8080/bar/nested // because nested from /bar overrides /foo's + // to do this any other way would require something like a custom tree search assert_eq!(body, "http://localhost:8080/bar/nested"); let bar_resp = From c9599163466c070a0b42cf6e8836c78b3636dda2 Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Thu, 20 Jan 2022 01:54:57 +0000 Subject: [PATCH 4/5] fmt codegen --- actix-web-codegen/src/lib.rs | 63 ++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 32 deletions(-) diff --git a/actix-web-codegen/src/lib.rs b/actix-web-codegen/src/lib.rs index 38e3cc379..79ed342d2 100644 --- a/actix-web-codegen/src/lib.rs +++ b/actix-web-codegen/src/lib.rs @@ -106,38 +106,37 @@ pub fn route(args: TokenStream, input: TokenStream) -> TokenStream { macro_rules! method_macro { ($variant:ident, $method:ident) => { - #[doc = concat!("Creates route handler with `actix_web::guard::", stringify!($variant), "`.")] - /// - /// # Syntax - /// ```plain - #[doc = concat!("#[", stringify!($method), r#"("path"[, attributes])]"#)] - /// ``` - /// - /// # Attributes - /// - `"path"`: Raw literal string with path for which to register handler. - /// - `name = "resource_name"`: Specifies resource name for the handler. If not set, the - /// function name of handler is used. - /// - `guard = "function_name"`: Registers function as guard. - /// using `actix_web::guard::fn_guard`. - /// - `wrap = "Middleware"`: Registers a resource middleware. - /// - /// # Notes - /// Function name can be specified as any expression that is going to be accessible to the generate - /// code, e.g `my_guard` or `my_module::my_guard`. - /// - /// # Example - /// ``` - /// # use actix_web::HttpResponse; - #[doc = concat!("# use actix_web_codegen::", stringify!($method), ";")] - #[doc = concat!("#[", stringify!($method), r#"("/")]"#)] - /// async fn example() -> HttpResponse { - /// HttpResponse::Ok().finish() - /// } - /// ``` - #[proc_macro_attribute] - pub fn $method(args: TokenStream, input: TokenStream) -> TokenStream { - route::with_method(Some(route::MethodType::$variant), args, input) - } +#[doc = concat!("Creates route handler with `actix_web::guard::", stringify!($variant), "`.")] +/// +/// # Syntax +/// ```plain +#[doc = concat!("#[", stringify!($method), r#"("path"[, attributes])]"#)] +/// ``` +/// +/// # Attributes +/// - `"path"`: Raw literal string with path for which to register handler. +/// - `name = "resource_name"`: Specifies resource name for the handler. If not set, the function +/// name of handler is used. +/// - `guard = "function_name"`: Registers function as guard using `actix_web::guard::fn_guard`. +/// - `wrap = "Middleware"`: Registers a resource middleware. +/// +/// # Notes +/// Function name can be specified as any expression that is going to be accessible to the +/// generate code, e.g `my_guard` or `my_module::my_guard`. +/// +/// # Example +/// ``` +/// # use actix_web::HttpResponse; +#[doc = concat!("# use actix_web_codegen::", stringify!($method), ";")] +#[doc = concat!("#[", stringify!($method), r#"("/")]"#)] +/// async fn example() -> HttpResponse { +/// HttpResponse::Ok().finish() +/// } +/// ``` +#[proc_macro_attribute] +pub fn $method(args: TokenStream, input: TokenStream) -> TokenStream { + route::with_method(Some(route::MethodType::$variant), args, input) +} }; } From bc89f0bfc23a0bb7978fc128b947c56f13fa3d03 Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Fri, 21 Jan 2022 16:56:33 +0000 Subject: [PATCH 5/5] s/example/examples --- actix-files/src/lib.rs | 2 +- actix-web-codegen/src/lib.rs | 2 +- awc/src/ws.rs | 2 +- examples/basic.rs | 2 +- src/http/header/date.rs | 2 +- src/http/header/expires.rs | 2 +- src/http/header/if_modified_since.rs | 2 +- src/http/header/if_unmodified_since.rs | 2 +- src/http/header/last_modified.rs | 2 +- src/middleware/logger.rs | 2 +- src/request_data.rs | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/actix-files/src/lib.rs b/actix-files/src/lib.rs index af404721c..43b06a858 100644 --- a/actix-files/src/lib.rs +++ b/actix-files/src/lib.rs @@ -2,7 +2,7 @@ //! //! Provides a non-blocking service for serving static files from disk. //! -//! # Example +//! # Examples //! ``` //! use actix_web::App; //! use actix_files::Files; diff --git a/actix-web-codegen/src/lib.rs b/actix-web-codegen/src/lib.rs index 79ed342d2..f41e1ce38 100644 --- a/actix-web-codegen/src/lib.rs +++ b/actix-web-codegen/src/lib.rs @@ -124,7 +124,7 @@ macro_rules! method_macro { /// Function name can be specified as any expression that is going to be accessible to the /// generate code, e.g `my_guard` or `my_module::my_guard`. /// -/// # Example +/// # Examples /// ``` /// # use actix_web::HttpResponse; #[doc = concat!("# use actix_web_codegen::", stringify!($method), ";")] diff --git a/awc/src/ws.rs b/awc/src/ws.rs index f3ee02d43..d8ed4c879 100644 --- a/awc/src/ws.rs +++ b/awc/src/ws.rs @@ -2,7 +2,7 @@ //! //! Type definitions required to use [`awc::Client`](super::Client) as a WebSocket client. //! -//! # Example +//! # Examples //! //! ```no_run //! use awc::{Client, ws}; diff --git a/examples/basic.rs b/examples/basic.rs index 598d13a40..494470676 100644 --- a/examples/basic.rs +++ b/examples/basic.rs @@ -24,7 +24,7 @@ async fn main() -> std::io::Result<()> { App::new() .wrap(middleware::DefaultHeaders::new().add(("X-Version", "0.2"))) .wrap(middleware::Compress::default()) - .wrap(middleware::Logger::default()) + .wrap(middleware::Logger::default().log_target("1234")) .service(index) .service(no_params) .service( diff --git a/src/http/header/date.rs b/src/http/header/date.rs index 4063deab1..f62740211 100644 --- a/src/http/header/date.rs +++ b/src/http/header/date.rs @@ -16,7 +16,7 @@ crate::http::header::common_header! { /// # Example Values /// * `Tue, 15 Nov 1994 08:12:31 GMT` /// - /// # Example + /// # Examples /// /// ``` /// use std::time::SystemTime; diff --git a/src/http/header/expires.rs b/src/http/header/expires.rs index 5b6c65c53..55fe5acc5 100644 --- a/src/http/header/expires.rs +++ b/src/http/header/expires.rs @@ -19,7 +19,7 @@ crate::http::header::common_header! { /// # Example Values /// * `Thu, 01 Dec 1994 16:00:00 GMT` /// - /// # Example + /// # Examples /// /// ``` /// use std::time::{SystemTime, Duration}; diff --git a/src/http/header/if_modified_since.rs b/src/http/header/if_modified_since.rs index 14d6c3553..897210944 100644 --- a/src/http/header/if_modified_since.rs +++ b/src/http/header/if_modified_since.rs @@ -18,7 +18,7 @@ crate::http::header::common_header! { /// # Example Values /// * `Sat, 29 Oct 1994 19:43:31 GMT` /// - /// # Example + /// # Examples /// /// ``` /// use std::time::{SystemTime, Duration}; diff --git a/src/http/header/if_unmodified_since.rs b/src/http/header/if_unmodified_since.rs index 0df6d7ba0..2ee3160b4 100644 --- a/src/http/header/if_unmodified_since.rs +++ b/src/http/header/if_unmodified_since.rs @@ -18,7 +18,7 @@ crate::http::header::common_header! { /// # Example Values /// * `Sat, 29 Oct 1994 19:43:31 GMT` /// - /// # Example + /// # Examples /// /// ``` /// use std::time::{SystemTime, Duration}; diff --git a/src/http/header/last_modified.rs b/src/http/header/last_modified.rs index e15443ed1..59e649bea 100644 --- a/src/http/header/last_modified.rs +++ b/src/http/header/last_modified.rs @@ -17,7 +17,7 @@ crate::http::header::common_header! { /// # Example Values /// * `Sat, 29 Oct 1994 19:43:31 GMT` /// - /// # Example + /// # Examples /// /// ``` /// use std::time::{SystemTime, Duration}; diff --git a/src/middleware/logger.rs b/src/middleware/logger.rs index 63055ecba..d68e1a122 100644 --- a/src/middleware/logger.rs +++ b/src/middleware/logger.rs @@ -124,7 +124,7 @@ impl Logger { /// /// It is convention to print "-" to indicate no output instead of an empty string. /// - /// # Example + /// # Examples /// ``` /// # use actix_web::http::{header::HeaderValue}; /// # use actix_web::middleware::Logger; diff --git a/src/request_data.rs b/src/request_data.rs index 68103a7e9..719e6551f 100644 --- a/src/request_data.rs +++ b/src/request_data.rs @@ -24,7 +24,7 @@ use crate::{ /// re-insert the cloned data back into the extensions map. A `DerefMut` impl is intentionally not /// provided to make this potential foot-gun more obvious. /// -/// # Example +/// # Examples /// ```no_run /// # use actix_web::{web, HttpResponse, HttpRequest, Responder, HttpMessage as _}; ///