mirror of
https://github.com/fafhrd91/actix-web
synced 2025-01-19 06:04:40 +01:00
non exhaustive content encoding (#2377)
This commit is contained in:
parent
ddc8c16cb3
commit
93112644d3
@ -99,7 +99,7 @@ regex = "1.4"
|
|||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
serde_urlencoded = "0.7"
|
serde_urlencoded = "0.7"
|
||||||
smallvec = "1.6"
|
smallvec = "1.6.1"
|
||||||
socket2 = "0.4.0"
|
socket2 = "0.4.0"
|
||||||
time = { version = "0.2.23", default-features = false, features = ["std"] }
|
time = { version = "0.2.23", default-features = false, features = ["std"] }
|
||||||
url = "2.1"
|
url = "2.1"
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
## Unreleased - 2021-xx-xx
|
## Unreleased - 2021-xx-xx
|
||||||
### Changed
|
### Changed
|
||||||
|
* `ContentEncoding` is now marked `#[non_exhaustive]`. [#2377]
|
||||||
* Minimum supported Rust version (MSRV) is now 1.51.
|
* Minimum supported Rust version (MSRV) is now 1.51.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
@ -12,12 +13,14 @@
|
|||||||
[#2364]: https://github.com/actix/actix-web/pull/2364
|
[#2364]: https://github.com/actix/actix-web/pull/2364
|
||||||
[#2375]: https://github.com/actix/actix-web/pull/2375
|
[#2375]: https://github.com/actix/actix-web/pull/2375
|
||||||
[#2344]: https://github.com/actix/actix-web/pull/2344
|
[#2344]: https://github.com/actix/actix-web/pull/2344
|
||||||
|
[#2377]: https://github.com/actix/actix-web/pull/2377
|
||||||
|
|
||||||
|
|
||||||
## 3.0.0-beta.8 - 2021-08-09
|
## 3.0.0-beta.8 - 2021-08-09
|
||||||
### Fixed
|
### Fixed
|
||||||
* Potential HTTP request smuggling vulnerabilities. [RUSTSEC-2021-0081](https://github.com/rustsec/advisory-db/pull/977)
|
* Potential HTTP request smuggling vulnerabilities. [RUSTSEC-2021-0081](https://github.com/rustsec/advisory-db/pull/977)
|
||||||
|
|
||||||
|
|
||||||
## 3.0.0-beta.8 - 2021-06-26
|
## 3.0.0-beta.8 - 2021-06-26
|
||||||
### Changed
|
### Changed
|
||||||
* Change compression algorithm features flags. [#2250]
|
* Change compression algorithm features flags. [#2250]
|
||||||
|
@ -73,7 +73,7 @@ rand = "0.8"
|
|||||||
regex = "1.3"
|
regex = "1.3"
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
sha-1 = "0.9"
|
sha-1 = "0.9"
|
||||||
smallvec = "1.6"
|
smallvec = "1.6.1"
|
||||||
time = { version = "0.2.23", default-features = false, features = ["std"] }
|
time = { version = "0.2.23", default-features = false, features = ["std"] }
|
||||||
tokio = { version = "1.2", features = ["sync"] }
|
tokio = { version = "1.2", features = ["sync"] }
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
//! Stream decoders.
|
//! Stream decoders.
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
convert::TryFrom,
|
|
||||||
future::Future,
|
future::Future,
|
||||||
io::{self, Write as _},
|
io::{self, Write as _},
|
||||||
pin::Pin,
|
pin::Pin,
|
||||||
@ -81,7 +80,7 @@ where
|
|||||||
let encoding = headers
|
let encoding = headers
|
||||||
.get(&CONTENT_ENCODING)
|
.get(&CONTENT_ENCODING)
|
||||||
.and_then(|val| val.to_str().ok())
|
.and_then(|val| val.to_str().ok())
|
||||||
.and_then(|x| ContentEncoding::try_from(x).ok())
|
.and_then(|x| x.parse().ok())
|
||||||
.unwrap_or(ContentEncoding::Identity);
|
.unwrap_or(ContentEncoding::Identity);
|
||||||
|
|
||||||
Self::new(stream, encoding)
|
Self::new(stream, encoding)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use std::{convert::TryFrom, error, fmt, str::FromStr};
|
use std::{convert::TryFrom, str::FromStr};
|
||||||
|
|
||||||
|
use derive_more::{Display, Error};
|
||||||
use http::header::InvalidHeaderValue;
|
use http::header::InvalidHeaderValue;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -11,19 +12,13 @@ use crate::{
|
|||||||
/// Error return when a content encoding is unknown.
|
/// Error return when a content encoding is unknown.
|
||||||
///
|
///
|
||||||
/// Example: 'compress'
|
/// Example: 'compress'
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Display, Error)]
|
||||||
|
#[display(fmt = "unsupported content encoding")]
|
||||||
pub struct ContentEncodingParseError;
|
pub struct ContentEncodingParseError;
|
||||||
|
|
||||||
impl fmt::Display for ContentEncodingParseError {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(f, "Unsupported content encoding")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl error::Error for ContentEncodingParseError {}
|
|
||||||
|
|
||||||
/// Represents a supported content encoding.
|
/// Represents a supported content encoding.
|
||||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
|
#[non_exhaustive]
|
||||||
pub enum ContentEncoding {
|
pub enum ContentEncoding {
|
||||||
/// Automatically select encoding based on encoding negotiation.
|
/// Automatically select encoding based on encoding negotiation.
|
||||||
Auto,
|
Auto,
|
||||||
|
@ -41,9 +41,9 @@ type HttpNewService = BoxServiceFactory<(), ServiceRequest, ServiceResponse, Err
|
|||||||
/// fn main() {
|
/// fn main() {
|
||||||
/// let app = App::new().service(
|
/// let app = App::new().service(
|
||||||
/// web::scope("/{project_id}/")
|
/// web::scope("/{project_id}/")
|
||||||
/// .service(web::resource("/path1").to(|| async { HttpResponse::Ok() }))
|
/// .service(web::resource("/path1").to(|| async { "OK" }))
|
||||||
/// .service(web::resource("/path2").route(web::get().to(|| HttpResponse::Ok())))
|
/// .service(web::resource("/path2").route(web::get().to(|| HttpResponse::Ok())))
|
||||||
/// .service(web::resource("/path3").route(web::head().to(|| HttpResponse::MethodNotAllowed())))
|
/// .service(web::resource("/path3").route(web::head().to(HttpResponse::MethodNotAllowed)))
|
||||||
/// );
|
/// );
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -56,7 +56,7 @@ pub fn default_service(
|
|||||||
/// async fn test_init_service() {
|
/// async fn test_init_service() {
|
||||||
/// let app = test::init_service(
|
/// let app = test::init_service(
|
||||||
/// App::new()
|
/// App::new()
|
||||||
/// .service(web::resource("/test").to(|| async { HttpResponse::Ok() }))
|
/// .service(web::resource("/test").to(|| async { "OK" }))
|
||||||
/// ).await;
|
/// ).await;
|
||||||
///
|
///
|
||||||
/// // Create request object
|
/// // Create request object
|
||||||
|
@ -30,7 +30,7 @@ use crate::{
|
|||||||
///
|
///
|
||||||
/// # Extractor
|
/// # Extractor
|
||||||
/// To extract typed data from a request body, the inner type `T` must implement the
|
/// To extract typed data from a request body, the inner type `T` must implement the
|
||||||
/// [`serde::Deserialize`] trait.
|
/// [`DeserializeOwned`] trait.
|
||||||
///
|
///
|
||||||
/// Use [`FormConfig`] to configure extraction process.
|
/// Use [`FormConfig`] to configure extraction process.
|
||||||
///
|
///
|
||||||
|
@ -97,19 +97,13 @@ impl<T> ops::DerefMut for Json<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> fmt::Display for Json<T>
|
impl<T: fmt::Display> fmt::Display for Json<T> {
|
||||||
where
|
|
||||||
T: fmt::Display,
|
|
||||||
{
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
fmt::Display::fmt(&self.0, f)
|
fmt::Display::fmt(&self.0, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Serialize for Json<T>
|
impl<T: Serialize> Serialize for Json<T> {
|
||||||
where
|
|
||||||
T: Serialize,
|
|
||||||
{
|
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
S: serde::Serializer,
|
S: serde::Serializer,
|
||||||
@ -133,10 +127,7 @@ impl<T: Serialize> Responder for Json<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// See [here](#extractor) for example of usage as an extractor.
|
/// See [here](#extractor) for example of usage as an extractor.
|
||||||
impl<T> FromRequest for Json<T>
|
impl<T: DeserializeOwned + 'static> FromRequest for Json<T> {
|
||||||
where
|
|
||||||
T: DeserializeOwned + 'static,
|
|
||||||
{
|
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
type Future = JsonExtractFut<T>;
|
type Future = JsonExtractFut<T>;
|
||||||
type Config = JsonConfig;
|
type Config = JsonConfig;
|
||||||
@ -166,10 +157,7 @@ pub struct JsonExtractFut<T> {
|
|||||||
err_handler: JsonErrorHandler,
|
err_handler: JsonErrorHandler,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Future for JsonExtractFut<T>
|
impl<T: DeserializeOwned + 'static> Future for JsonExtractFut<T> {
|
||||||
where
|
|
||||||
T: DeserializeOwned + 'static,
|
|
||||||
{
|
|
||||||
type Output = Result<Json<T>, Error>;
|
type Output = Result<Json<T>, Error>;
|
||||||
|
|
||||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
@ -311,10 +299,7 @@ pub enum JsonBody<T> {
|
|||||||
|
|
||||||
impl<T> Unpin for JsonBody<T> {}
|
impl<T> Unpin for JsonBody<T> {}
|
||||||
|
|
||||||
impl<T> JsonBody<T>
|
impl<T: DeserializeOwned> JsonBody<T> {
|
||||||
where
|
|
||||||
T: DeserializeOwned + 'static,
|
|
||||||
{
|
|
||||||
/// Create a new future to decode a JSON request payload.
|
/// Create a new future to decode a JSON request payload.
|
||||||
#[allow(clippy::borrow_interior_mutable_const)]
|
#[allow(clippy::borrow_interior_mutable_const)]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
@ -395,10 +380,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Future for JsonBody<T>
|
impl<T: DeserializeOwned + 'static> Future for JsonBody<T> {
|
||||||
where
|
|
||||||
T: DeserializeOwned + 'static,
|
|
||||||
{
|
|
||||||
type Output = Result<T, JsonPayloadError>;
|
type Output = Result<T, JsonPayloadError>;
|
||||||
|
|
||||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
|
@ -3,14 +3,14 @@
|
|||||||
use std::{fmt, ops, sync::Arc};
|
use std::{fmt, ops, sync::Arc};
|
||||||
|
|
||||||
use actix_utils::future::{err, ok, Ready};
|
use actix_utils::future::{err, ok, Ready};
|
||||||
use serde::de;
|
use serde::de::DeserializeOwned;
|
||||||
|
|
||||||
use crate::{dev::Payload, error::QueryPayloadError, Error, FromRequest, HttpRequest};
|
use crate::{dev::Payload, error::QueryPayloadError, Error, FromRequest, HttpRequest};
|
||||||
|
|
||||||
/// Extract typed information from the request's query.
|
/// Extract typed information from the request's query.
|
||||||
///
|
///
|
||||||
/// To extract typed data from the URL query string, the inner type `T` must implement the
|
/// To extract typed data from the URL query string, the inner type `T` must implement the
|
||||||
/// [`serde::Deserialize`] trait.
|
/// [`DeserializeOwned`] trait.
|
||||||
///
|
///
|
||||||
/// Use [`QueryConfig`] to configure extraction process.
|
/// Use [`QueryConfig`] to configure extraction process.
|
||||||
///
|
///
|
||||||
@ -50,14 +50,14 @@ use crate::{dev::Payload, error::QueryPayloadError, Error, FromRequest, HttpRequ
|
|||||||
/// "OK".to_string()
|
/// "OK".to_string()
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// // Or use `.0`, which is equivalent to `.into_inner()`.
|
/// // Or use destructuring, which is equivalent to `.into_inner()`.
|
||||||
/// #[get("/debug2")]
|
/// #[get("/debug2")]
|
||||||
/// async fn debug2(info: web::Query<AuthRequest>) -> String {
|
/// async fn debug2(web::Query(info): web::Query<AuthRequest>) -> String {
|
||||||
/// dbg!("Authorization object={:?}", info.0);
|
/// dbg!("Authorization object = {:?}", info);
|
||||||
/// "OK".to_string()
|
/// "OK".to_string()
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct Query<T>(pub T);
|
pub struct Query<T>(pub T);
|
||||||
|
|
||||||
impl<T> Query<T> {
|
impl<T> Query<T> {
|
||||||
@ -65,8 +65,10 @@ impl<T> Query<T> {
|
|||||||
pub fn into_inner(self) -> T {
|
pub fn into_inner(self) -> T {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Deserialize `T` from a URL encoded query parameter string.
|
impl<T: DeserializeOwned> Query<T> {
|
||||||
|
/// Deserialize a `T` from the URL encoded query parameter string.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use std::collections::HashMap;
|
/// # use std::collections::HashMap;
|
||||||
@ -76,10 +78,7 @@ impl<T> Query<T> {
|
|||||||
/// assert_eq!(numbers.get("two"), Some(&2));
|
/// assert_eq!(numbers.get("two"), Some(&2));
|
||||||
/// assert!(numbers.get("three").is_none());
|
/// assert!(numbers.get("three").is_none());
|
||||||
/// ```
|
/// ```
|
||||||
pub fn from_query(query_str: &str) -> Result<Self, QueryPayloadError>
|
pub fn from_query(query_str: &str) -> Result<Self, QueryPayloadError> {
|
||||||
where
|
|
||||||
T: de::DeserializeOwned,
|
|
||||||
{
|
|
||||||
serde_urlencoded::from_str::<T>(query_str)
|
serde_urlencoded::from_str::<T>(query_str)
|
||||||
.map(Self)
|
.map(Self)
|
||||||
.map_err(QueryPayloadError::Deserialize)
|
.map_err(QueryPayloadError::Deserialize)
|
||||||
@ -107,10 +106,7 @@ impl<T: fmt::Display> fmt::Display for Query<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// See [here](#usage) for example of usage as an extractor.
|
/// See [here](#usage) for example of usage as an extractor.
|
||||||
impl<T> FromRequest for Query<T>
|
impl<T: DeserializeOwned> FromRequest for Query<T> {
|
||||||
where
|
|
||||||
T: de::DeserializeOwned,
|
|
||||||
{
|
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
type Future = Ready<Result<Self, Error>>;
|
type Future = Ready<Result<Self, Error>>;
|
||||||
type Config = QueryConfig;
|
type Config = QueryConfig;
|
||||||
@ -165,7 +161,7 @@ where
|
|||||||
/// let query_cfg = web::QueryConfig::default()
|
/// let query_cfg = web::QueryConfig::default()
|
||||||
/// // use custom error handler
|
/// // use custom error handler
|
||||||
/// .error_handler(|err, req| {
|
/// .error_handler(|err, req| {
|
||||||
/// error::InternalError::from_response(err, HttpResponse::Conflict().into()).into()
|
/// error::InternalError::from_response(err, HttpResponse::Conflict().finish()).into()
|
||||||
/// });
|
/// });
|
||||||
///
|
///
|
||||||
/// App::new()
|
/// App::new()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user