Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Added RequestContextStore, RequestContext and SignedPrivateCookieJar #633

Draft
wants to merge 43 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
e59c252
Added RequestContextStore, RequestContext and SignedPrivateCookieJar
yinho999 Jul 1, 2024
73b0738
Added Cookie Map as inner driver of request context.
yinho999 Jul 7, 2024
c683b1c
Minor refactor
yinho999 Jul 7, 2024
cdd62d2
Merge remote-tracking branch 'origin/master' into requestcontext
yinho999 Jul 15, 2024
77d0f18
Added drive actions and init request context layer
yinho999 Jul 17, 2024
39e5ab7
added driver testing
yinho999 Jul 18, 2024
f0b9207
Request id will no longer initialized in tracing layer but request id…
yinho999 Jul 19, 2024
815b562
Request id will no longer initialized in tracing layer but request id…
yinho999 Jul 19, 2024
3b07485
Added request context middleware, refactored request context and tes…
yinho999 Jul 21, 2024
22122b1
Merge remote-tracking branch 'origin/master' into requestcontext
yinho999 Aug 10, 2024
47261bc
Fixed test
yinho999 Aug 11, 2024
b4ead0c
Merge remote-tracking branch 'origin/master' into requestcontext
yinho999 Aug 11, 2024
b5d10b1
refactor: replace `RequestId` with `LocoRequestId` across request con…
yinho999 Aug 11, 2024
9b05a67
refactor: replace `RequestId` with `LocoRequestId` across request con…
yinho999 Aug 11, 2024
c326037
feat: add request context management and tests
yinho999 Aug 11, 2024
55d7ac8
Cargo clippy
yinho999 Aug 11, 2024
e9e0355
example cargo clippy
yinho999 Aug 11, 2024
aa08161
refactor: simplify `RequestContext` usage by implementing `Deref` and…
yinho999 Aug 13, 2024
8ef8e39
feat: enhance `RequestContext` with session management methods
yinho999 Aug 14, 2024
96dfdad
Merge remote-tracking branch 'origin/master' into requestcontext
yinho999 Aug 16, 2024
41b3253
feat: enhance session management with custom session store and config…
yinho999 Aug 17, 2024
16368e2
Merge branch 'master' into requestcontext
yinho999 Aug 20, 2024
b8684a1
Merge remote-tracking branch 'origin/master' into requestcontext
yinho999 Sep 6, 2024
c7778bc
impl: enhance request context layer with tracing and session support
yinho999 Sep 7, 2024
adbf72e
refactor: optimize imports and improve session management in app_rout…
yinho999 Sep 9, 2024
95312b4
Merge branch 'master' into requestcontext
yinho999 Sep 25, 2024
715a765
refactor: update import paths in mysession controller and tests
yinho999 Sep 25, 2024
f71d820
cargo fmt
yinho999 Sep 25, 2024
8f53ee0
feat: enhance session management with configurable cookie attributes
yinho999 Sep 30, 2024
3799d35
Merge branch 'refs/heads/master' into requestcontext
yinho999 Oct 12, 2024
b1470a0
refactor: update cookie handling to use session config and remove har…
yinho999 Oct 13, 2024
c31b842
Refactored for new middleware design and fixed test in demo app and f…
yinho999 Oct 14, 2024
3fefbec
Merge branch 'refs/heads/master' into requestcontext
yinho999 Oct 14, 2024
9aa4cbc
Merge branch 'master' into requestcontext
yinho999 Oct 15, 2024
0104015
Fixed option error
yinho999 Oct 23, 2024
fad6290
Merge branch 'master' into requestcontext
yinho999 Oct 23, 2024
9709afa
Merge remote-tracking branch 'origin/master' into requestcontext
yinho999 Nov 1, 2024
538a4e7
Merge remote-tracking branch 'origin/requestcontext' into requestcontext
yinho999 Nov 1, 2024
edd9fca
Reorder imports in scheduler tests module for better organization
yinho999 Nov 1, 2024
8575966
Merge branch 'master' into requestcontext
yinho999 Dec 5, 2024
fad4bfb
Added cookie size validator
yinho999 Dec 5, 2024
1e4ff90
Added request context testing and also fixed existed tests
yinho999 Dec 8, 2024
660cdfc
Merge branch 'master' into requestcontext
yinho999 Dec 11, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ toml = "0.8"
async-trait = { workspace = true }

axum = { workspace = true }
axum-extra = { version = "0.9", features = ["cookie"] }
axum-extra = { version = "0.9", features = ["cookie", "cookie-private"] }
regex = { workspace = true }
fs-err = "2.11.0"
# mailer
Expand Down Expand Up @@ -133,6 +133,9 @@ object_store = { version = "0.11.0", default-features = false }
# cache
moka = { version = "0.12.7", features = ["sync"], optional = true }

# sessions
tower-sessions = "0.12"

# Scheduler
tokio-cron-scheduler = { version = "0.11.0", features = ["signal"] }
english-to-cron = { version = "0.1.2" }
Expand Down
Empty file added docs/sessions.md
Empty file.
2 changes: 1 addition & 1 deletion examples/demo/config/development.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ logger:
# <snip id="configuration-server">
server:
# Port on which the server will listen. the server binding is 0.0.0.0:{PORT}
port: {{ get_env(name="NODE_PORT", default=5150) }}
port: {{get_env(name="NODE_PORT", default=5150)}}
# The UI hostname or IP address that mailers will point to.
host: http://localhost
# </snip>
Expand Down
15 changes: 15 additions & 0 deletions examples/demo/config/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,21 @@ server:
enable: true
cors:
enable: true
request_context:
enable: true
session_config:
name: session
http_only: true
same_site:
type: Lax
expiry: 3600
secure: false
path: /
# domain: ""
session_store:
type: Cookie
value:
private_key: [ 219, 25, 129, 200, 66, 52, 72, 66, 249, 60, 206, 40, 77, 150, 2, 8, 30, 192, 221, 5, 243, 74, 17, 172, 109, 96, 218, 46, 235, 118, 131, 150, 224, 205, 55, 147, 45, 151, 245, 23, 250, 48, 133, 115, 105, 252, 193, 15, 162, 167, 77, 189, 169, 91, 205, 172, 120, 254, 136, 111, 167, 161, 255, 107 ]
# Set the value of the [`Access-Control-Allow-Origin`][mdn] header
# allow_origins:
# - https://loco.rs
Expand Down
18 changes: 16 additions & 2 deletions examples/demo/config/teste2e.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,21 @@ server:
enable: true
# Duration time in milliseconds.
timeout: 5000

request_context:
enable: true
session_config:
name: session
http_only: true
same_site:
type: Lax
expiry: 3600
secure: false
path: /
# domain: ""
session_store:
type: Cookie
value:
private_key: [ 219, 25, 129, 200, 66, 52, 72, 66, 249, 60, 206, 40, 77, 150, 2, 8, 30, 192, 221, 5, 243, 74, 17, 172, 109, 96, 218, 46, 235, 118, 131, 150, 224, 205, 55, 147, 45, 151, 245, 23, 250, 48, 133, 115, 105, 252, 193, 15, 162, 167, 77, 189, 169, 91, 205, 172, 120, 254, 136, 111, 167, 161, 255, 107 ]
# Worker Configuration
workers:
# specifies the worker mode. Options:
Expand Down Expand Up @@ -77,7 +91,7 @@ mailer:
# Database Configuration
database:
# Database connection URI
uri: {{get_env(name="DATABASE_URL", default="postgres://localhost:5432/loco_app")}}
uri: {{get_env(name="DATABASE_URL", default="postgres://loco:loco@localhost:5432/loco_app_test")}}
# When enabled, the sql query will be logged.
enable_logging: false
# Set the timeout duration when acquiring a connection.
Expand Down
48 changes: 46 additions & 2 deletions examples/demo/src/controllers/mysession.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
#![allow(clippy::unused_async)]

use axum::{debug_handler, Extension};
use axum_session::{Session, SessionNullPool};
use loco_rs::prelude::*;
use loco_rs::{prelude::*, request_context::RequestContext};

const REQUEST_CONTEXT_DATA_KEY: &str = "alan";

/// Get a session
///
Expand All @@ -11,6 +15,46 @@ pub async fn get_session(_session: Session<SessionNullPool>) -> Result<Response>
format::empty()
}

/// Set a request context
///
/// # Errors
///
/// This function will return an error if result fails
#[debug_handler]
pub async fn create_request_context(mut req: RequestContext) -> Result<Response> {
let data = "turing".to_string();
req.insert(REQUEST_CONTEXT_DATA_KEY, data.clone()).await?;
tracing::info!(
"Request Context data set - Key: {:?}, Value: {:?}",
REQUEST_CONTEXT_DATA_KEY,
data
);
Ok(data.into_response())
}

/// Get a request context
///
/// # Errors
///
/// This function will return an error if result fails
#[debug_handler]
pub async fn get_request_context(mut req: Extension<RequestContext>) -> Result<Response> {
let data = req
.get::<String>(REQUEST_CONTEXT_DATA_KEY)
.await?
.unwrap_or_default();
tracing::info!(
"Request Context data retrieved - Key: {:?}, Value: {:?}",
REQUEST_CONTEXT_DATA_KEY,
data
);
Ok(data.into_response())
}

pub fn routes() -> Routes {
Routes::new().prefix("mysession").add("/", get(get_session))
Routes::new()
.prefix("mysession")
.add("/", get(get_session))
.add("/request_context", post(create_request_context))
.add("/request_context", get(get_request_context))
}
2 changes: 1 addition & 1 deletion examples/demo/src/models/roles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ impl super::_entities::roles::Model {
pub async fn find_by_user(db: &DatabaseConnection, user: &users::Model) -> ModelResult<Self> {
let role = roles::Entity::find()
.inner_join(users_roles::Entity)
.filter(users_roles::Column::UsersId.eq(user.id.clone()))
.filter(users_roles::Column::UsersId.eq(user.id))
.one(db)
.await?;
role.ok_or_else(|| ModelError::EntityNotFound)
Expand Down
2 changes: 2 additions & 0 deletions examples/demo/tests/cmd/cli.trycmd
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ $ demo_app-cli routes --environment test
[GET] /mylayer/echo
[GET] /mylayer/user
[GET] /mysession
[POST] /mysession/request_context
[GET] /mysession/request_context
[GET] /notes
[POST] /notes
[GET] /notes/:id
Expand Down
1 change: 1 addition & 0 deletions examples/demo/tests/requests/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
mod auth;
mod cache;
mod mylayer;
mod mysession;
mod notes;
mod ping;
mod prepare_data;
Expand Down
70 changes: 70 additions & 0 deletions examples/demo/tests/requests/mysession.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
use axum::http::HeaderName;
use demo_app::app::App;
use serial_test::serial;
use loco_rs::testing::prelude::*;

macro_rules! configure_insta {
($($expr:expr),*) => {
let mut settings = insta::Settings::clone_current();
settings.set_prepend_module_to_snapshot(false);
settings.set_snapshot_suffix("cache");
let _guard = settings.bind_to_scope();
};
}

#[tokio::test]
#[serial]
async fn set_request_context_data() {
configure_insta!();
request::<App, _, _>(|request, _ctx| async move {
let response = request.post("/mysession/request_context").await;

// Get Cookie from response header
let headers = response.headers();
let cookie = headers.get("set-cookie");
assert_eq!(response.status_code(), 200);
assert_eq!(response.text(), "turing");
assert!(cookie.is_some());
})
.await;
}
#[tokio::test]
#[serial]
async fn get_request_context_without_setting_data() {
configure_insta!();
request::<App, _, _>(|request, _ctx| async move {
let response = request.get("/mysession/request_context").await;
// Get response body
assert_eq!(response.status_code(), 200);
assert_eq!(response.text(), "")
})
.await;
}

#[tokio::test]
#[serial]
async fn get_request_context_with_setting_data() {
configure_insta!();
request::<App, _, _>(|request, _ctx| async move {
let response = request.post("/mysession/request_context").await;
// Get Cookie from response header
let headers = response.headers();
let cookie_value = headers.get("set-cookie");
assert_eq!(response.status_code(), 200);
assert_eq!(response.text(), "turing");
assert!(cookie_value.is_some());
let data = response.text();

let response = request
.get("/mysession/request_context")
.add_header(
"cookie".parse::<HeaderName>().unwrap(),
cookie_value.unwrap().clone(),
)
.await;
// Get response body
assert_eq!(response.status_code(), 200);
assert_eq!(response.text(), data);
})
.await;
}
4 changes: 4 additions & 0 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use crate::{
},
environment::Environment,
mailer::EmailSender,
request_context::TowerSessionStore,
storage::Storage,
task::Tasks,
Result,
Expand Down Expand Up @@ -52,6 +53,8 @@ pub struct AppContext {
pub storage: Arc<Storage>,
// Cache instance for the application
pub cache: Arc<cache::Cache>,
/// Request context session store
pub session_store: Option<TowerSessionStore>,
}

/// A trait that defines hooks for customizing and extending the behavior of a
Expand Down Expand Up @@ -187,6 +190,7 @@ pub trait Hooks: Send {

// Provides the options to change Loco [`AppContext`] after initialization.
async fn after_context(ctx: AppContext) -> Result<AppContext> {
// ctx.session_store = Some(CustomSessionStore::new(MemoryStore::default()));
Ok(ctx)
}

Expand Down
2 changes: 2 additions & 0 deletions src/boot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
use std::path::PathBuf;

use axum::Router;
use colored::Colorize;
#[cfg(feature = "with-db")]
use sea_orm_migration::MigratorTrait;
use tokio::{select, signal, task::JoinHandle};
Expand Down Expand Up @@ -342,6 +343,7 @@ pub async fn create_context<H: Hooks>(environment: &Environment) -> Result<AppCo
cache: cache::Cache::new(cache::drivers::null::new()).into(),
config,
mailer,
session_store: None,
};

H::after_context(ctx).await
Expand Down
9 changes: 9 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,15 @@ pub struct RedisQueueConfig {
pub num_workers: u32,
}

/// Redis Configuration
///
/// Example (development):
/// ```yaml
/// # config/development.yaml
/// redis:
/// uri: redis://127.0.0.1/
/// dangerously_flush: false
/// ```
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct PostgresQueueConfig {
pub uri: String,
Expand Down
Loading
Loading