diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index b2ae1bac0..f58372afd 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -31,7 +31,7 @@ jobs: uses: actions-rs/cargo@v1 with: command: check - args: --all --bins --examples + args: --all --bins --examples --features logger - name: check avoid-dev-deps uses: actions-rs/cargo@v1 @@ -44,7 +44,7 @@ jobs: uses: actions-rs/cargo@v1 with: command: check - args: --all --bins --examples --tests --features unstable + args: --all --bins --examples --tests --features unstable,logger - name: check no-default-features uses: actions-rs/cargo@v1 @@ -62,13 +62,13 @@ jobs: uses: actions-rs/cargo@v1 with: command: test - args: --all + args: --all --features logger - name: tests unstable uses: actions-rs/cargo@v1 with: command: test - args: --all --features unstable + args: --all --features unstable,logger check_fmt_and_docs: name: Checking fmt, clippy, and docs @@ -82,7 +82,7 @@ jobs: rustc --version - name: clippy - run: cargo clippy --tests --examples -- -D warnings + run: cargo clippy --tests --examples --features logger -- -D warnings - name: fmt run: cargo fmt --all -- --check diff --git a/Cargo.toml b/Cargo.toml index 3a0f7ee91..9b647b11d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ rustdoc-args = ["--cfg", "feature=\"docs\""] default = ["h1-server"] cookies = ["http-types/cookies"] h1-server = ["async-h1"] -logger = ["femme"] +logger = [] docs = ["unstable"] sessions = ["async-session", "cookies"] sse = ["async-sse"] @@ -39,7 +39,6 @@ async-session = { version = "3.0", optional = true } async-sse = { version = "5.1.0", optional = true } async-std = { version = "1.6.5", features = ["unstable"] } async-trait = "0.1.41" -femme = { version = "2.1.1", optional = true } futures-util = "0.3.6" http-client = { version = "6.1.0", default-features = false } http-types = { version = "2.11.0", default-features = false, features = ["fs"] } @@ -54,7 +53,9 @@ regex = "1.5.5" [dev-dependencies] async-std = { version = "1.6.5", features = ["unstable", "attributes"] } criterion = "0.3.3" +femme = "2.1.1" juniper = "0.14.2" +kv-log-macro = "1.0.7" lazy_static = "1.4.0" logtest = "2.0.0" portpicker = "0.1.0" diff --git a/README.md b/README.md index 69b5bc81c..24f90e2ce 100644 --- a/README.md +++ b/README.md @@ -133,7 +133,7 @@ team. Use at your own risk. ### Auth * [tide-http-auth](https://github.com/chrisdickinson/tide-http-auth) * [tide-openidconnect](https://github.com/malyn/tide-openidconnect) -* [tide-jwt](htps://github.com/nyxtom/tide-jwt) +* [tide-jwt](https://github.com/nyxtom/tide-jwt) ### Testing * [tide-testing](https://github.com/jbr/tide-testing) @@ -148,6 +148,7 @@ team. Use at your own risk. * [tide-compressed-sse](https://github.com/Yarn/tide_compressed_sse) * [tide-websockets](https://github.com/http-rs/tide-websockets) * [tide-csrf](https://github.com/malyn/tide-csrf) +* [tide-flash](https://github.com/nyxtom/tide-flash) ### Session Stores * [async-redis-session](https://github.com/jbr/async-redis-session) diff --git a/examples/catflap.rs b/examples/catflap.rs index c3be1e67b..91c141c16 100644 --- a/examples/catflap.rs +++ b/examples/catflap.rs @@ -2,7 +2,7 @@ #[async_std::main] async fn main() -> Result<(), std::io::Error> { use std::{env, net::TcpListener, os::unix::io::FromRawFd}; - tide::log::start(); + femme::start(); let mut app = tide::new(); app.with(tide::log::LogMiddleware::new()); app.at("/").get(|_| async { Ok(CHANGE_THIS_TEXT) }); diff --git a/examples/chunked.rs b/examples/chunked.rs index 6ea80539d..aa1f21936 100644 --- a/examples/chunked.rs +++ b/examples/chunked.rs @@ -2,7 +2,7 @@ use tide::Body; #[async_std::main] async fn main() -> Result<(), std::io::Error> { - tide::log::start(); + femme::start(); let mut app = tide::new(); app.with(tide::log::LogMiddleware::new()); app.at("/").get(|_| async { diff --git a/examples/concurrent_listeners.rs b/examples/concurrent_listeners.rs index 2cb9bdb01..af9884203 100644 --- a/examples/concurrent_listeners.rs +++ b/examples/concurrent_listeners.rs @@ -2,7 +2,7 @@ use tide::Request; #[async_std::main] async fn main() -> Result<(), std::io::Error> { - tide::log::start(); + femme::start(); let mut app = tide::new(); app.with(tide::log::LogMiddleware::new()); diff --git a/examples/cookies.rs b/examples/cookies.rs index 34a1cbd30..2f86b21df 100644 --- a/examples/cookies.rs +++ b/examples/cookies.rs @@ -21,7 +21,7 @@ async fn remove_cookie(_req: Request) -> tide::Result { #[async_std::main] async fn main() -> Result<(), std::io::Error> { - tide::log::start(); + femme::start(); let mut app = tide::new(); app.with(tide::log::LogMiddleware::new()); diff --git a/examples/error_handling.rs b/examples/error_handling.rs index f5eecb476..7073f5f15 100644 --- a/examples/error_handling.rs +++ b/examples/error_handling.rs @@ -5,7 +5,7 @@ use tide::{Body, Request, Response, Result, StatusCode}; #[async_std::main] async fn main() -> Result<()> { - tide::log::start(); + femme::start(); let mut app = tide::new(); app.with(tide::log::LogMiddleware::new()); diff --git a/examples/hello.rs b/examples/hello.rs index d66475315..39e2089b7 100644 --- a/examples/hello.rs +++ b/examples/hello.rs @@ -1,6 +1,6 @@ #[async_std::main] async fn main() -> Result<(), std::io::Error> { - tide::log::start(); + femme::start(); let mut app = tide::new(); app.with(tide::log::LogMiddleware::new()); diff --git a/examples/json.rs b/examples/json.rs index e1c4030a8..49d2d45a7 100644 --- a/examples/json.rs +++ b/examples/json.rs @@ -9,7 +9,7 @@ struct Cat { #[async_std::main] async fn main() -> tide::Result<()> { - tide::log::start(); + femme::start(); let mut app = tide::new(); app.with(tide::log::LogMiddleware::new()); diff --git a/examples/middleware.rs b/examples/middleware.rs index 17eec31b9..5dacc2067 100644 --- a/examples/middleware.rs +++ b/examples/middleware.rs @@ -1,6 +1,7 @@ use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; +use kv_log_macro::trace; use tide::http::mime; use tide::utils::{After, Before}; use tide::{Middleware, Next, Request, Response, Result, StatusCode}; @@ -25,7 +26,7 @@ impl UserDatabase { // it would likely be closely tied to a specific application async fn user_loader(mut request: Request, next: Next) -> Result { if let Some(user) = request.state::().find_user().await { - tide::log::trace!("user loaded", {user: user.name}); + trace!("user loaded", {user: user.name}); request.set_ext(user); Ok(next.run(request).await) // this middleware only needs to run before the endpoint, so @@ -57,7 +58,7 @@ struct RequestCount(usize); impl Middleware for RequestCounterMiddleware { async fn handle(&self, mut req: Request, next: Next) -> Result { let count = self.requests_counted.fetch_add(1, Ordering::Relaxed); - tide::log::trace!("request counter", { count: count }); + trace!("request counter", { count: count }); req.set_ext(RequestCount(count)); let mut res = next.run(req).await; @@ -84,7 +85,7 @@ const INTERNAL_SERVER_ERROR_HTML_PAGE: &str = " #[async_std::main] async fn main() -> Result<()> { - tide::log::start(); + femme::start(); let mut app = tide::with_state(UserDatabase::default()); app.with(After(|response: Response| async move { diff --git a/examples/nested.rs b/examples/nested.rs index b9eece738..c87acde54 100644 --- a/examples/nested.rs +++ b/examples/nested.rs @@ -1,6 +1,6 @@ #[async_std::main] async fn main() -> Result<(), std::io::Error> { - tide::log::start(); + femme::start(); let mut app = tide::new(); app.with(tide::log::LogMiddleware::new()); app.at("/").get(|_| async { Ok("Root") }); diff --git a/examples/redirect.rs b/examples/redirect.rs index c0ab4c64a..e9ded4b8e 100644 --- a/examples/redirect.rs +++ b/examples/redirect.rs @@ -2,7 +2,7 @@ use tide::{Redirect, Response, StatusCode}; #[async_std::main] async fn main() -> Result<(), std::io::Error> { - tide::log::start(); + femme::start(); let mut app = tide::new(); app.with(tide::log::LogMiddleware::new()); app.at("/").get(|_| async { Ok("Root") }); diff --git a/examples/sessions.rs b/examples/sessions.rs index c27c8eccc..5e7cc6497 100644 --- a/examples/sessions.rs +++ b/examples/sessions.rs @@ -1,6 +1,6 @@ #[async_std::main] async fn main() -> Result<(), std::io::Error> { - tide::log::start(); + femme::start(); let mut app = tide::new(); app.with(tide::log::LogMiddleware::new()); diff --git a/examples/state.rs b/examples/state.rs index d188dacc3..e2f98389a 100644 --- a/examples/state.rs +++ b/examples/state.rs @@ -16,7 +16,7 @@ impl State { #[async_std::main] async fn main() -> tide::Result<()> { - tide::log::start(); + femme::start(); let mut app = tide::with_state(State::new()); app.with(tide::log::LogMiddleware::new()); app.at("/").get(|req: tide::Request| async move { diff --git a/examples/static_file.rs b/examples/static_file.rs index 6cd80a6a7..8a961eef2 100644 --- a/examples/static_file.rs +++ b/examples/static_file.rs @@ -1,6 +1,6 @@ #[async_std::main] async fn main() -> Result<(), std::io::Error> { - tide::log::start(); + femme::start(); let mut app = tide::new(); app.with(tide::log::LogMiddleware::new()); app.at("/").get(|_| async { Ok("visit /src/*") }); diff --git a/examples/upload.rs b/examples/upload.rs index 5824f1dc3..fcf90cdee 100644 --- a/examples/upload.rs +++ b/examples/upload.rs @@ -3,6 +3,7 @@ use std::path::Path; use std::sync::Arc; use async_std::{fs::OpenOptions, io}; +use kv_log_macro::info; use tempfile::TempDir; use tide::prelude::*; use tide::{Body, Request, Response, StatusCode}; @@ -26,7 +27,7 @@ impl TempDirState { #[async_std::main] async fn main() -> Result<(), IoError> { - tide::log::start(); + femme::start(); let mut app = tide::with_state(TempDirState::try_new()?); app.with(tide::log::LogMiddleware::new()); @@ -49,7 +50,7 @@ async fn main() -> Result<(), IoError> { let bytes_written = io::copy(req, file).await?; - tide::log::info!("file written", { + info!("file written", { bytes: bytes_written, path: fs_path.canonicalize()?.to_str() }); diff --git a/src/fs/serve_dir.rs b/src/fs/serve_dir.rs index d7581ee9d..f2a9b9b12 100644 --- a/src/fs/serve_dir.rs +++ b/src/fs/serve_dir.rs @@ -1,7 +1,7 @@ -use crate::log; use crate::{Body, Endpoint, Request, Response, Result, StatusCode}; use async_std::path::PathBuf as AsyncPathBuf; +use kv_log_macro::{info, warn}; use std::path::{Path, PathBuf}; use std::{ffi::OsStr, io}; @@ -37,17 +37,17 @@ impl Endpoint for ServeDir { } } - log::info!("Requested file: {:?}", file_path); + info!("Requested file: {:?}", file_path); let file_path = AsyncPathBuf::from(file_path); if !file_path.starts_with(&self.dir) { - log::warn!("Unauthorized attempt to read: {:?}", file_path); + warn!("Unauthorized attempt to read: {:?}", file_path); Ok(Response::new(StatusCode::Forbidden)) } else { match Body::from_file(&file_path).await { Ok(body) => Ok(Response::builder(StatusCode::Ok).body(body).build()), Err(e) if e.kind() == io::ErrorKind::NotFound => { - log::warn!("File not found: {:?}", &file_path); + warn!("File not found: {:?}", &file_path); Ok(Response::new(StatusCode::NotFound)) } Err(e) => Err(e.into()), diff --git a/src/fs/serve_file.rs b/src/fs/serve_file.rs index 8aa9c8624..754da6267 100644 --- a/src/fs/serve_file.rs +++ b/src/fs/serve_file.rs @@ -1,10 +1,10 @@ -use crate::log; use crate::{Body, Endpoint, Request, Response, Result, StatusCode}; use std::io; use std::path::Path; use async_std::path::PathBuf as AsyncPathBuf; use async_trait::async_trait; +use kv_log_macro::warn; pub(crate) struct ServeFile { path: AsyncPathBuf, @@ -26,7 +26,7 @@ impl Endpoint for ServeFile { match Body::from_file(&self.path).await { Ok(body) => Ok(Response::builder(StatusCode::Ok).body(body).build()), Err(e) if e.kind() == io::ErrorKind::NotFound => { - log::warn!("File not found: {:?}", &self.path); + warn!("File not found: {:?}", &self.path); Ok(Response::new(StatusCode::NotFound)) } Err(e) => Err(e.into()), diff --git a/src/lib.rs b/src/lib.rs index d6e980af8..cdd6a8a99 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,9 +32,7 @@ //! //! #[async_std::main] //! async fn main() -> tide::Result<()> { -//! tide::log::start(); //! let mut app = tide::new(); -//! app.with(tide::log::LogMiddleware::new()); //! app.at("/orders/shoes").post(order_shoes); //! app.listen("127.0.0.1:8080").await?; //! Ok(()) diff --git a/src/listener/concurrent_listener.rs b/src/listener/concurrent_listener.rs index 1a774b961..be3c7a92f 100644 --- a/src/listener/concurrent_listener.rs +++ b/src/listener/concurrent_listener.rs @@ -13,7 +13,6 @@ use futures_util::stream::{futures_unordered::FuturesUnordered, StreamExt}; /// ```rust /// fn main() -> Result<(), std::io::Error> { /// async_std::task::block_on(async { -/// tide::log::start(); /// let mut app = tide::new(); /// app.at("/").get(|_| async { Ok("Hello, world!") }); /// diff --git a/src/listener/failover_listener.rs b/src/listener/failover_listener.rs index cceb2d230..8b418c25c 100644 --- a/src/listener/failover_listener.rs +++ b/src/listener/failover_listener.rs @@ -4,6 +4,7 @@ use crate::Server; use std::fmt::{self, Debug, Display, Formatter}; use async_std::io; +use kv_log_macro::info; use crate::listener::ListenInfo; @@ -15,7 +16,6 @@ use crate::listener::ListenInfo; /// ```rust /// fn main() -> Result<(), std::io::Error> { /// async_std::task::block_on(async { -/// tide::log::start(); /// let mut app = tide::new(); /// app.at("/").get(|_| async { Ok("Hello, world!") }); /// @@ -103,7 +103,7 @@ impl Listener for FailoverListener { return Ok(()); } Err(e) => { - crate::log::info!("unable to bind", { + info!("unable to bind", { listener: listener.to_string(), error: e.to_string() }); diff --git a/src/listener/tcp_listener.rs b/src/listener/tcp_listener.rs index 90f2dde45..51cfc104a 100644 --- a/src/listener/tcp_listener.rs +++ b/src/listener/tcp_listener.rs @@ -1,13 +1,14 @@ use super::{is_transient_error, ListenInfo}; use crate::listener::Listener; -use crate::{log, Server}; +use crate::Server; use std::fmt::{self, Display, Formatter}; use async_std::net::{self, SocketAddr, TcpStream}; use async_std::prelude::*; use async_std::{io, task}; +use kv_log_macro::error; /// This represents a tide [Listener](crate::listener::Listener) that /// wraps an [async_std::net::TcpListener]. It is implemented as an @@ -56,7 +57,7 @@ fn handle_tcp(app: Server, stream: TcpStream) { }); if let Err(error) = fut.await { - log::error!("async-h1 error", { error: error.to_string() }); + error!("async-h1 error", { error: error.to_string() }); } }); } @@ -102,7 +103,7 @@ impl Listener for TcpListener { Err(ref e) if is_transient_error(e) => continue, Err(error) => { let delay = std::time::Duration::from_millis(500); - crate::log::error!("Error: {}. Pausing for {:?}.", error, delay); + error!("Error: {}. Pausing for {:?}.", error, delay); task::sleep(delay).await; continue; } diff --git a/src/listener/unix_listener.rs b/src/listener/unix_listener.rs index ec32bb6dd..6d4a716f7 100644 --- a/src/listener/unix_listener.rs +++ b/src/listener/unix_listener.rs @@ -1,7 +1,7 @@ use super::{is_transient_error, ListenInfo}; use crate::listener::Listener; -use crate::{log, Server}; +use crate::Server; use std::fmt::{self, Display, Formatter}; @@ -9,6 +9,7 @@ use async_std::os::unix::net::{self, SocketAddr, UnixStream}; use async_std::path::PathBuf; use async_std::prelude::*; use async_std::{io, task}; +use kv_log_macro::error; /// This represents a tide [Listener](crate::listener::Listener) that /// wraps an [async_std::os::unix::net::UnixListener]. It is implemented as an @@ -57,7 +58,7 @@ fn handle_unix(app: Server, stream: UnixStream) { }); if let Err(error) = fut.await { - log::error!("async-h1 error", { error: error.to_string() }); + error!("async-h1 error", { error: error.to_string() }); } }); } @@ -100,7 +101,7 @@ impl Listener for UnixListener { Err(ref e) if is_transient_error(e) => continue, Err(error) => { let delay = std::time::Duration::from_millis(500); - crate::log::error!("Error: {}. Pausing for {:?}.", error, delay); + error!("Error: {}. Pausing for {:?}.", error, delay); task::sleep(delay).await; continue; } diff --git a/src/log/middleware.rs b/src/log/middleware.rs index 2cfe9002d..323ab6f1e 100644 --- a/src/log/middleware.rs +++ b/src/log/middleware.rs @@ -1,4 +1,5 @@ -use crate::log; +use kv_log_macro::{error, info, warn}; + use crate::{Middleware, Next, Request}; /// Log all incoming requests and responses. @@ -34,7 +35,7 @@ impl LogMiddleware { let path = req.url().path().to_owned(); let method = req.method().to_string(); - log::info!("<-- Request received", { + info!("<-- Request received", { method: method, path: path, }); @@ -43,7 +44,7 @@ impl LogMiddleware { let status = response.status(); if status.is_server_error() { if let Some(error) = response.error() { - log::error!("Internal error --> Response sent", { + error!("Internal error --> Response sent", { message: format!("{:?}", error), error_type: error.type_name(), method: method, @@ -52,7 +53,7 @@ impl LogMiddleware { duration: format!("{:?}", start.elapsed()), }); } else { - log::error!("Internal error --> Response sent", { + error!("Internal error --> Response sent", { method: method, path: path, status: format!("{} - {}", status as u16, status.canonical_reason()), @@ -61,7 +62,7 @@ impl LogMiddleware { } } else if status.is_client_error() { if let Some(error) = response.error() { - log::warn!("Client error --> Response sent", { + warn!("Client error --> Response sent", { message: format!("{:?}", error), error_type: error.type_name(), method: method, @@ -70,7 +71,7 @@ impl LogMiddleware { duration: format!("{:?}", start.elapsed()), }); } else { - log::warn!("Client error --> Response sent", { + warn!("Client error --> Response sent", { method: method, path: path, status: format!("{} - {}", status as u16, status.canonical_reason()), @@ -78,7 +79,7 @@ impl LogMiddleware { }); } } else { - log::info!("--> Response sent", { + info!("--> Response sent", { method: method, path: path, status: format!("{} - {}", status as u16, status.canonical_reason()), diff --git a/src/log/mod.rs b/src/log/mod.rs index 8f74ac2dc..f41430239 100644 --- a/src/log/mod.rs +++ b/src/log/mod.rs @@ -1,41 +1,5 @@ -//! Event logging types. -//! -//! # Examples -//! -//! ```no_run -//! use tide::log; -//! -//! log::start(); -//! -//! log::info!("Hello cats"); -//! log::debug!("{} wants tuna", "Nori"); -//! log::error!("We're out of tuna!"); -//! log::info!("{} are hungry", "cats", { -//! cat_1: "Chashu", -//! cat_2: "Nori", -//! }); -//! ``` - -pub use kv_log_macro::{debug, error, info, log, trace, warn}; -pub use kv_log_macro::{max_level, Level}; +//! Support for logging in tide; see [`LogMiddleware`]. mod middleware; -#[cfg(feature = "logger")] -pub use femme::LevelFilter; - pub use middleware::LogMiddleware; - -/// Start logging. -#[cfg(feature = "logger")] -pub fn start() { - femme::start(); - crate::log::info!("Logger started", { level: "Info" }); -} - -/// Start logging with a log level. -#[cfg(feature = "logger")] -pub fn with_level(level: LevelFilter) { - femme::with_level(level); - crate::log::info!("Logger started", { level: format!("{}", level) }); -} diff --git a/src/route.rs b/src/route.rs index 989a24dcb..d277c1669 100644 --- a/src/route.rs +++ b/src/route.rs @@ -4,8 +4,9 @@ use std::path::Path; use std::sync::Arc; use crate::fs::{ServeDir, ServeFile}; -use crate::{log, Next}; -use crate::{router::Router, Endpoint, Middleware}; +use crate::{router::Router, Endpoint, Middleware, Next}; + +use kv_log_macro::trace; /// A handle to a route. /// @@ -77,7 +78,7 @@ impl<'a> Route<'a> { /// Apply the given middleware to the current route. pub fn with(&mut self, middleware: impl Middleware) -> &mut Self { - log::trace!( + trace!( "Adding middleware {} to route {:?}", middleware.name(), self.path diff --git a/src/server.rs b/src/server.rs index 68bcb4c91..ad196702c 100644 --- a/src/server.rs +++ b/src/server.rs @@ -2,14 +2,14 @@ use async_std::io; use async_std::sync::Arc; +use kv_log_macro::{info, trace}; #[cfg(feature = "cookies")] use crate::cookies; use crate::listener::{Listener, ToListener}; -use crate::middleware::Middleware; +use crate::middleware::{Middleware, Next}; use crate::router::{Router, Selection}; use crate::state::StateMiddleware; -use crate::{log, Next}; use crate::{Endpoint, Request, Route}; /// An HTTP server. @@ -171,7 +171,7 @@ impl Server { /// Middleware can only be added at the "top level" of an application, and is processed in the /// order in which it is applied. pub fn with(&mut self, middleware: impl Middleware) -> &mut Self { - log::trace!("Adding middleware {}", middleware.name()); + trace!("Adding middleware {}", middleware.name()); let m = Arc::get_mut(&mut self.middleware) .expect("Registering middleware is not possible after the Server has started"); m.push(Arc::new(middleware)); @@ -199,7 +199,7 @@ impl Server { let mut listener = listener.to_listener()?; listener.bind(self).await?; for info in listener.info().iter() { - log::info!("Server listening on {}", info); + info!("Server listening on {}", info); } listener.accept().await?; Ok(()) diff --git a/src/sessions/middleware.rs b/src/sessions/middleware.rs index 2fd01e3c2..fcd041567 100644 --- a/src/sessions/middleware.rs +++ b/src/sessions/middleware.rs @@ -11,6 +11,7 @@ use async_session::{ hmac::{Hmac, Mac, NewMac}, sha2::Sha256, }; +use kv_log_macro::error; const BASE64_DIGEST_LEN: usize = 44; @@ -54,6 +55,7 @@ pub struct SessionMiddleware { cookie_domain: Option, session_ttl: Option, save_unchanged: bool, + secure: Option, same_site_policy: SameSite, key: Key, } @@ -66,6 +68,7 @@ impl std::fmt::Debug for SessionMiddleware { .field("cookie_name", &self.cookie_name) .field("cookie_domain", &self.cookie_domain) .field("session_ttl", &self.session_ttl) + .field("secure", &self.secure) .field("same_site_policy", &self.same_site_policy) .field("key", &"..") .field("save_unchanged", &self.save_unchanged) @@ -90,14 +93,17 @@ where session.expire_in(ttl); } - let secure_cookie = request.url().scheme() == "https"; + let mut secure_cookie = request.url().scheme() == "https"; + if let Some(secure) = self.secure { + secure_cookie = secure; + } request.set_ext(session.clone()); let mut response = next.run(request).await; if session.is_destroyed() { if let Err(e) = self.store.destroy_session(session).await { - crate::log::error!("unable to destroy session", { error: e.to_string() }); + error!("unable to destroy session", { error: e.to_string() }); } if let Some(mut cookie) = cookie { @@ -139,6 +145,7 @@ impl SessionMiddleware { /// * cookie path: "/" /// * cookie name: "tide.sid" /// * session ttl: one day + /// * secure: request.scheme == 'https' /// * same site: strict /// * save unchanged: enabled /// @@ -159,6 +166,7 @@ impl SessionMiddleware { /// .with_cookie_name("custom.cookie.name") /// .with_cookie_path("/some/path") /// .with_cookie_domain("www.rust-lang.org") + /// .with_secure(true) /// .with_same_site_policy(SameSite::Lax) /// .with_session_ttl(Some(Duration::from_secs(1))) /// .without_save_unchanged(), @@ -171,6 +179,7 @@ impl SessionMiddleware { cookie_path: "/".into(), cookie_name: "tide.sid".into(), cookie_domain: None, + secure: None, same_site_policy: SameSite::Lax, session_ttl: Some(Duration::from_secs(24 * 60 * 60)), key: Key::derive_from(secret), @@ -216,6 +225,14 @@ impl SessionMiddleware { self } + /// Sets the secure attribute of the cookie. + /// Defaults to true if the incoming request scheme is 'https' + /// Can optionally be set to true or false to override + pub fn with_secure(mut self, secure: bool) -> Self { + self.secure = Some(secure); + self + } + /// Sets the same site policy for the session cookie. Defaults to /// SameSite::Lax. See [incrementally better /// cookies](https://tools.ietf.org/html/draft-west-cookie-incrementalism-01) diff --git a/tests/sessions.rs b/tests/sessions.rs index b1eaa3183..8066f0cc9 100644 --- a/tests/sessions.rs +++ b/tests/sessions.rs @@ -64,7 +64,8 @@ async fn test_customized_sessions() -> tide::Result<()> { .with_cookie_name("custom.cookie.name") .with_cookie_path("/nested") .with_cookie_domain("www.rust-lang.org") - .with_same_site_policy(SameSite::Strict) + .with_secure(true) + .with_same_site_policy(SameSite::Lax) .with_session_ttl(Some(Duration::from_secs(1))) .without_save_unchanged(), ); @@ -99,7 +100,8 @@ async fn test_customized_sessions() -> tide::Result<()> { assert!(cookies.get("tide.sid").is_none()); let cookie = &cookies["custom.cookie.name"]; assert_eq!(cookie.http_only(), Some(true)); - assert_eq!(cookie.same_site(), Some(SameSite::Strict)); + assert_eq!(cookie.secure(), Some(true)); + assert_eq!(cookie.same_site(), Some(SameSite::Lax)); assert_eq!(cookie.path(), Some("/nested")); assert_eq!(cookie.domain(), Some("www.rust-lang.org")); let cookie_value = cookie.value().to_string();