Merge pull request #7 from actix/master

#1292 #1327
This commit is contained in:
zzy 2020-01-29 12:14:55 +08:00 committed by GitHub
commit fbe272d21d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 67 additions and 25 deletions

View File

@ -27,26 +27,6 @@ jobs:
profile: minimal profile: minimal
override: true override: true
- name: Generate Cargo.lock
uses: actions-rs/cargo@v1
with:
command: generate-lockfile
- name: Cache cargo registry
uses: actions/cache@v1
with:
path: ~/.cargo/registry
key: ${{ matrix.version }}-x86_64-pc-windows-msvc-cargo-registry-trimmed-${{ hashFiles('**/Cargo.lock') }}
- name: Cache cargo index
uses: actions/cache@v1
with:
path: ~/.cargo/git
key: ${{ matrix.version }}-x86_64-pc-windows-msvc-cargo-index-trimmed-${{ hashFiles('**/Cargo.lock') }}
- name: Cache cargo build
uses: actions/cache@v1
with:
path: target
key: ${{ matrix.version }}-x86_64-pc-windows-msvc-cargo-build-trimmed-${{ hashFiles('**/Cargo.lock') }}
- name: Install OpenSSL - name: Install OpenSSL
run: | run: |
vcpkg integrate install vcpkg integrate install
@ -74,8 +54,5 @@ jobs:
--skip=test_expect_continue --skip=test_expect_continue
--skip=test_http10_keepalive --skip=test_http10_keepalive
--skip=test_slow_request --skip=test_slow_request
--skip=test_connection_force_close
- name: Clear the cargo caches --skip=test_connection_server_close
run: |
cargo install cargo-cache --no-default-features --features ci-autoclean
cargo-cache

View File

@ -3,6 +3,7 @@
## [Unreleased] - 2020-01-xx ## [Unreleased] - 2020-01-xx
* Update the `time` dependency to 0.2.5 * Update the `time` dependency to 0.2.5
* [#1292](https://github.com/actix/actix-web/pull/1292) Long lasting auto-prolonged session
## [0.3.0] - 2019-12-20 ## [0.3.0] - 2019-12-20

View File

@ -58,6 +58,7 @@ struct CookieSessionInner {
secure: bool, secure: bool,
http_only: bool, http_only: bool,
max_age: Option<Duration>, max_age: Option<Duration>,
expires_in: Option<Duration>,
same_site: Option<SameSite>, same_site: Option<SameSite>,
} }
@ -72,6 +73,7 @@ impl CookieSessionInner {
secure: true, secure: true,
http_only: true, http_only: true,
max_age: None, max_age: None,
expires_in: None,
same_site: None, same_site: None,
} }
} }
@ -97,6 +99,10 @@ impl CookieSessionInner {
cookie.set_domain(domain.clone()); cookie.set_domain(domain.clone());
} }
if let Some(expires_in) = self.expires_in {
cookie.set_expires(OffsetDateTime::now() + expires_in);
}
if let Some(max_age) = self.max_age { if let Some(max_age) = self.max_age {
cookie.set_max_age(max_age); cookie.set_max_age(max_age);
} }
@ -272,6 +278,17 @@ impl CookieSession {
Rc::get_mut(&mut self.0).unwrap().max_age = Some(value); Rc::get_mut(&mut self.0).unwrap().max_age = Some(value);
self self
} }
/// Sets the `expires` field in the session cookie being built.
pub fn expires_in(self, seconds: i64) -> CookieSession {
self.expires_in_time(Duration::seconds(seconds))
}
/// Sets the `expires` field in the session cookie being built.
pub fn expires_in_time(mut self, value: Duration) -> CookieSession {
Rc::get_mut(&mut self.0).unwrap().expires_in = Some(value);
self
}
} }
impl<S, B: 'static> Transform<S> for CookieSession impl<S, B: 'static> Transform<S> for CookieSession
@ -324,6 +341,7 @@ where
fn call(&mut self, mut req: ServiceRequest) -> Self::Future { fn call(&mut self, mut req: ServiceRequest) -> Self::Future {
let inner = self.inner.clone(); let inner = self.inner.clone();
let (is_new, state) = self.inner.load(&req); let (is_new, state) = self.inner.load(&req);
let prolong_expiration = self.inner.expires_in.is_some();
Session::set_session(state.into_iter(), &mut req); Session::set_session(state.into_iter(), &mut req);
let fut = self.service.call(req); let fut = self.service.call(req);
@ -335,6 +353,9 @@ where
| (SessionStatus::Renewed, Some(state)) => { | (SessionStatus::Renewed, Some(state)) => {
res.checked_expr(|res| inner.set_cookie(res, state)) res.checked_expr(|res| inner.set_cookie(res, state))
} }
(SessionStatus::Unchanged, Some(state)) if prolong_expiration => {
res.checked_expr(|res| inner.set_cookie(res, state))
}
(SessionStatus::Unchanged, _) => (SessionStatus::Unchanged, _) =>
// set a new session cookie upon first request (new client) // set a new session cookie upon first request (new client)
{ {
@ -478,4 +499,47 @@ mod tests {
let body = test::read_response(&mut app, request).await; let body = test::read_response(&mut app, request).await;
assert_eq!(body, Bytes::from_static(b"counter: 100")); assert_eq!(body, Bytes::from_static(b"counter: 100"));
} }
#[actix_rt::test]
async fn prolong_expiration() {
let mut app = test::init_service(
App::new()
.wrap(CookieSession::signed(&[0; 32]).secure(false).expires_in(60))
.service(web::resource("/").to(|ses: Session| {
async move {
let _ = ses.set("counter", 100);
"test"
}
}))
.service(
web::resource("/test/")
.to(|| async move { "no-changes-in-session" }),
),
)
.await;
let request = test::TestRequest::get().to_request();
let response = app.call(request).await.unwrap();
let expires_1 = response
.response()
.cookies()
.find(|c| c.name() == "actix-session")
.expect("Cookie is set")
.expires()
.expect("Expiration is set");
actix_rt::time::delay_for(std::time::Duration::from_secs(1)).await;
let request = test::TestRequest::with_uri("/test/").to_request();
let response = app.call(request).await.unwrap();
let expires_2 = response
.response()
.cookies()
.find(|c| c.name() == "actix-session")
.expect("Cookie is set")
.expires()
.expect("Expiration is set");
assert!(expires_2 - expires_1 >= Duration::seconds(1));
}
} }