mirror of
https://github.com/actix/actix-extras.git
synced 2024-11-23 15:51:06 +01:00
make RateLimiter non-exhaustive
This commit is contained in:
parent
cd9dc163e5
commit
6e79465362
@ -1,7 +1,8 @@
|
|||||||
# Changes
|
# Changes
|
||||||
|
|
||||||
## Unreleased - 2022-xx-xx
|
## Unreleased - 2022-xx-xx
|
||||||
|
- Implement `Default` for `RateLimiter`.
|
||||||
|
- `RateLimiter` can no longer be constructed without `::default()`.
|
||||||
|
|
||||||
## 0.3.0 - 2022-07-11
|
## 0.3.0 - 2022-07-11
|
||||||
- `Limiter::builder` now takes an `impl Into<String>`.
|
- `Limiter::builder` now takes an `impl Into<String>`.
|
||||||
@ -10,14 +11,11 @@
|
|||||||
|
|
||||||
|
|
||||||
## 0.2.0 - 2022-03-22
|
## 0.2.0 - 2022-03-22
|
||||||
- Update Actix Web dependency to v4 ecosystem. [#229]
|
- Update Actix Web dependency to v4 ecosystem.
|
||||||
- Update Tokio dependencies to v1 ecosystem. [#229]
|
- Update Tokio dependencies to v1 ecosystem.
|
||||||
- Rename `Limiter::{build => builder}()`. [#232]
|
- Rename `Limiter::{build => builder}()`.
|
||||||
- Rename `Builder::{finish => build}()`. [#232]
|
- Rename `Builder::{finish => build}()`.
|
||||||
- Exceeding the rate limit now returns a 429 Too Many Requests response. [#232]
|
- Exceeding the rate limit now returns a 429 Too Many Requests response.
|
||||||
|
|
||||||
[#229]: https://github.com/actix/actix-extras/pull/229
|
|
||||||
[#232]: https://github.com/actix/actix-extras/pull/232
|
|
||||||
|
|
||||||
|
|
||||||
## 0.1.4 - 2022-03-18
|
## 0.1.4 - 2022-03-18
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
//!
|
//!
|
||||||
//! HttpServer::new(move || {
|
//! HttpServer::new(move || {
|
||||||
//! App::new()
|
//! App::new()
|
||||||
//! .wrap(RateLimiter)
|
//! .wrap(RateLimiter::default())
|
||||||
//! .app_data(limiter.clone())
|
//! .app_data(limiter.clone())
|
||||||
//! .service(index)
|
//! .service(index)
|
||||||
//! })
|
//! })
|
||||||
|
@ -4,16 +4,16 @@ use actix_session::SessionExt as _;
|
|||||||
use actix_utils::future::{ok, Ready};
|
use actix_utils::future::{ok, Ready};
|
||||||
use actix_web::{
|
use actix_web::{
|
||||||
body::EitherBody,
|
body::EitherBody,
|
||||||
cookie::Cookie,
|
|
||||||
dev::{forward_ready, Service, ServiceRequest, ServiceResponse, Transform},
|
dev::{forward_ready, Service, ServiceRequest, ServiceResponse, Transform},
|
||||||
http::{header::COOKIE, StatusCode},
|
http::StatusCode,
|
||||||
web, Error, HttpResponse,
|
web, Error, HttpResponse,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::Limiter;
|
use crate::Limiter;
|
||||||
|
|
||||||
/// Rate limit middleware.
|
/// Rate limit middleware.
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Default)]
|
||||||
|
#[non_exhaustive]
|
||||||
pub struct RateLimiter;
|
pub struct RateLimiter;
|
||||||
|
|
||||||
impl<S, B> Transform<S, ServiceRequest> for RateLimiter
|
impl<S, B> Transform<S, ServiceRequest> for RateLimiter
|
||||||
@ -61,23 +61,26 @@ where
|
|||||||
.expect("web::Data<Limiter> should be set in app data for RateLimiter middleware")
|
.expect("web::Data<Limiter> should be set in app data for RateLimiter middleware")
|
||||||
.clone();
|
.clone();
|
||||||
|
|
||||||
let (key, fallback) = key(&req, limiter.clone());
|
let key = req.get_session().get(&limiter.session_key).unwrap_or(None);
|
||||||
|
|
||||||
let service = Rc::clone(&self.service);
|
let service = Rc::clone(&self.service);
|
||||||
|
|
||||||
let key = match key {
|
let key = match key {
|
||||||
Some(key) => key,
|
Some(key) => key,
|
||||||
None => match fallback {
|
None => {
|
||||||
Some(key) => key,
|
let fallback = req.cookie(&limiter.cookie_name).map(|c| c.to_string());
|
||||||
None => {
|
|
||||||
return Box::pin(async move {
|
match fallback {
|
||||||
service
|
Some(key) => key,
|
||||||
.call(req)
|
None => {
|
||||||
.await
|
return Box::pin(async move {
|
||||||
.map(ServiceResponse::map_into_left_body)
|
service
|
||||||
});
|
.call(req)
|
||||||
|
.await
|
||||||
|
.map(ServiceResponse::map_into_left_body)
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
@ -98,19 +101,3 @@ where
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn key(req: &ServiceRequest, limiter: web::Data<Limiter>) -> (Option<String>, Option<String>) {
|
|
||||||
let session = req.get_session();
|
|
||||||
let result: Option<String> = session.get(&limiter.session_key).unwrap_or(None);
|
|
||||||
let cookies = req.headers().get_all(COOKIE);
|
|
||||||
let cookie = cookies
|
|
||||||
.filter_map(|i| i.to_str().ok())
|
|
||||||
.find(|i| i.contains(limiter.cookie_name.as_ref()));
|
|
||||||
|
|
||||||
let fallback = match cookie {
|
|
||||||
Some(value) => Cookie::parse(value).ok().map(|i| i.to_string()),
|
|
||||||
None => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
(result, fallback)
|
|
||||||
}
|
|
||||||
|
@ -68,6 +68,7 @@ async fn session_entries() {
|
|||||||
map.contains_key("test_str");
|
map.contains_key("test_str");
|
||||||
map.contains_key("test_num");
|
map.contains_key("test_num");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[actix_web::test]
|
#[actix_web::test]
|
||||||
async fn insert_session_after_renew() {
|
async fn insert_session_after_renew() {
|
||||||
let session = test::TestRequest::default().to_srv_request().get_session();
|
let session = test::TestRequest::default().to_srv_request().get_session();
|
||||||
@ -81,6 +82,7 @@ async fn insert_session_after_renew() {
|
|||||||
session.insert("test_val1", "val1").unwrap();
|
session.insert("test_val1", "val1").unwrap();
|
||||||
assert_eq!(session.status(), SessionStatus::Renewed);
|
assert_eq!(session.status(), SessionStatus::Renewed);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[actix_web::test]
|
#[actix_web::test]
|
||||||
async fn remove_session_after_renew() {
|
async fn remove_session_after_renew() {
|
||||||
let session = test::TestRequest::default().to_srv_request().get_session();
|
let session = test::TestRequest::default().to_srv_request().get_session();
|
||||||
|
Loading…
Reference in New Issue
Block a user