summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Scott <sam.scott89@gmail.com>2020-06-03 10:26:45 -0400
committerGitHub <noreply@github.com>2020-06-03 10:26:45 -0400
commit77cb6730f9265591dad141f4f9b840069c9cd2b9 (patch)
tree6c4cd170f74d0c789e1059a91514d04dc06decba
parentd5c2d3e44a5cbe2311111fb56bfe6bed8fabd961 (diff)
Support actix-web v2 (#30)
* update dependencies - actix-web v2 - percent encoding v2.1 - rust 2018 edition - remove rustfmt no longer supported rules * ci: add feature build matrix * fix actix unit tests Co-authored-by: Mario Reder <mreder1289@gmail.com>
-rw-r--r--.travis.yml9
-rw-r--r--Cargo.toml18
-rw-r--r--README.md2
-rw-r--r--rustfmt.toml3
-rw-r--r--src/actix.rs25
-rw-r--r--src/de/mod.rs2
-rw-r--r--src/de/parse.rs40
-rw-r--r--src/lib.rs4
-rw-r--r--src/ser.rs2
-rw-r--r--tests/test_actix.rs143
-rw-r--r--tests/test_deserialize.rs2
-rw-r--r--tests/test_serialize.rs3
12 files changed, 139 insertions, 114 deletions
diff --git a/.travis.yml b/.travis.yml
index 6e09135..f698d07 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,4 +5,11 @@ rust:
- nightly
matrix:
allow_failures:
- - rust: nightly \ No newline at end of file
+ - rust: nightly
+env:
+ - ARGS="--verbose"
+ - ARGS="--verbose --features=actix"
+
+script:
+ - cargo build $ARGS
+ - cargo test $ARGS
diff --git a/Cargo.toml b/Cargo.toml
index 3b296e0..38467a2 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,5 +1,6 @@
[package]
authors = ["Sam Scott <me@samjs.co.uk>"]
+edition = "2018"
categories = ["encoding", "web-programming"]
description = "Querystrings for Serde"
documentation = "https://docs.rs/serde_qs"
@@ -8,7 +9,7 @@ license = "MIT/Apache-2.0"
name = "serde_qs"
repository = "https://github.com/samscott89/serde_qs"
readme = "README.md"
-version = "0.5.1"
+version = "0.6.0"
[badges]
@@ -16,21 +17,22 @@ version = "0.5.1"
repository = "samscott89/serde_qs"
[dependencies]
-actix-web = { version ="1.0.0", optional = true }
-data-encoding = "2.1.2"
-error-chain = "0.12.0"
+actix-web = { version = "2.0", optional = true }
+data-encoding = "2.2.1"
+error-chain = "0.12.2"
+futures = { version = "0.3", optional = true }
percent-encoding = "2.1.0"
-serde = "1.0.85"
+serde = "1.0.111"
[dev-dependencies]
-csv = "1.0.5"
+csv = "1.1.3"
rand = "0.7.3"
-serde_derive = "1.0.85"
+serde_derive = "1.0.111"
serde_urlencoded = "0.6.1"
[features]
default = []
-actix = ["actix-web"]
+actix = ["actix-web", "futures"]
[package.metadata.docs.rs]
features = [ "actix" ]
diff --git a/README.md b/README.md
index af5df70..7b30fff 100644
--- a/README.md
+++ b/README.md
@@ -33,7 +33,7 @@ This crate works with Cargo and can be found on
```toml
[dependencies]
-serde_qs = "0.5"
+serde_qs = "0.6"
```
[crates.io]: https://crates.io/crates/serde_qs
diff --git a/rustfmt.toml b/rustfmt.toml
index 70b05df..e696b4e 100644
--- a/rustfmt.toml
+++ b/rustfmt.toml
@@ -1,7 +1,6 @@
match_block_trailing_comma = true
max_width = 80
newline_style = "Unix"
-reorder_imported_names = true
reorder_imports = true
use_try_shorthand = true
-where_trailing_comma = true
+trailing_comma = "Vertical"
diff --git a/src/actix.rs b/src/actix.rs
index fa7e105..70dc6e1 100644
--- a/src/actix.rs
+++ b/src/actix.rs
@@ -2,12 +2,14 @@
//!
//! Enable with the `actix` feature.
+use crate::de::Config as QsConfig;
+use crate::error::Error as QsError;
+
use actix_web::dev::Payload;
use actix_web::{
Error as ActixError, FromRequest, HttpRequest, HttpResponse, ResponseError,
};
-use de::Config as QsConfig;
-use error::Error as QsError;
+use futures::future::{ready, Ready};
use serde::de;
use std::fmt;
use std::fmt::{Debug, Display};
@@ -28,7 +30,7 @@ impl ResponseError for QsError {
/// ```rust
/// #[macro_use] extern crate serde_derive;
/// extern crate actix_web;
-/// use actix_web::{web, App};
+/// use actix_web::{web, App, HttpResponse};
/// use serde_qs::actix::QsQuery;
///
/// #[derive(Deserialize)]
@@ -38,7 +40,7 @@ impl ResponseError for QsError {
///
/// // Use `QsQuery` extractor for query information.
/// // The correct request for this handler would be `/users?id[]=1124&id[]=88"`
-/// fn filter_users(info: QsQuery<UsersFilter>) -> String {
+/// fn filter_users(info: QsQuery<UsersFilter>) -> HttpResponse {
/// info.id.iter().map(|i| i.to_string()).collect::<Vec<String>>().join(", ").into()
/// }
///
@@ -88,7 +90,7 @@ where
T: de::DeserializeOwned,
{
type Error = ActixError;
- type Future = Result<Self, ActixError>;
+ type Future = Ready<Result<Self, ActixError>>;
type Config = QsQueryConfig;
#[inline]
@@ -103,7 +105,7 @@ where
.map(|c| &c.qs_config)
.unwrap_or(&default_qsconfig);
- qsconfig
+ let res = qsconfig
.deserialize_str::<T>(req.query_string())
.map(|val| Ok(QsQuery(val)))
.unwrap_or_else(move |e| {
@@ -114,7 +116,8 @@ where
};
Err(e)
- })
+ });
+ ready(res)
}
}
@@ -133,13 +136,13 @@ where
/// }
///
/// /// deserialize `Info` from request's querystring
-/// fn index(info: QsQuery<Info>) -> String {
-/// format!("Welcome {}!", info.username)
+/// fn index(info: QsQuery<Info>) -> HttpResponse {
+/// format!("Welcome {}!", info.username).into()
/// }
///
/// fn main() {
/// let app = App::new().service(
-/// web::resource("/index.html").data(
+/// web::resource("/index.html").app_data(
/// // change query extractor configuration
/// QsQuery::<Info>::configure(|cfg| {
/// cfg.error_handler(|err, req| { // <- create custom error response
@@ -155,7 +158,7 @@ where
pub struct QsQueryConfig {
ehandler:
- Option<Arc<Fn(QsError, &HttpRequest) -> ActixError + Send + Sync>>,
+ Option<Arc<dyn Fn(QsError, &HttpRequest) -> ActixError + Send + Sync>>,
qs_config: QsConfig,
}
diff --git a/src/de/mod.rs b/src/de/mod.rs
index a82a37b..923c4b9 100644
--- a/src/de/mod.rs
+++ b/src/de/mod.rs
@@ -38,7 +38,7 @@
mod parse;
-use error::*;
+use crate::error::*;
use serde::de;
use serde::de::IntoDeserializer;
diff --git a/src/de/parse.rs b/src/de/parse.rs
index 6f10ac3..c23aa7e 100644
--- a/src/de/parse.rs
+++ b/src/de/parse.rs
@@ -1,6 +1,5 @@
use super::*;
-use percent_encoding;
use serde::de;
use std::borrow::Cow;
@@ -206,7 +205,7 @@ fn replace_plus(input: &[u8]) -> Cow<[u8]> {
}
Cow::Owned(replaced)
- }
+ },
}
}
@@ -235,25 +234,26 @@ impl<'a> Parser<'a> {
/// present.
fn collect_str(&mut self) -> Result<Cow<'a, str>> {
let replaced = replace_plus(&self.inner[self.acc.0..self.acc.1 - 1]);
- let ret:Result<Cow<'a, str>> = match percent_encoding::percent_decode(&replaced).decode_utf8()? {
- Cow::Borrowed(_) => {
- match replaced {
- Cow::Borrowed(_) => {
- // In this case, neither method made replacements, so we
- // reuse the original bytes
- let res = str::from_utf8(&self.inner[self.acc.0..self.acc.1 - 1])?;
- Ok(Cow::Borrowed(res))
- },
- Cow::Owned(owned) => {
- let res = String::from_utf8(owned)?;
- Ok(Cow::Owned(res))
+ let ret: Result<Cow<'a, str>> =
+ match percent_encoding::percent_decode(&replaced).decode_utf8()? {
+ Cow::Borrowed(_) => {
+ match replaced {
+ Cow::Borrowed(_) => {
+ // In this case, neither method made replacements, so we
+ // reuse the original bytes
+ let res = str::from_utf8(
+ &self.inner[self.acc.0..self.acc.1 - 1],
+ )?;
+ Ok(Cow::Borrowed(res))
+ },
+ Cow::Owned(owned) => {
+ let res = String::from_utf8(owned)?;
+ Ok(Cow::Owned(res))
+ },
}
- }
- },
- Cow::Owned(owned) => {
- Ok(Cow::Owned(owned))
- }
- };
+ },
+ Cow::Owned(owned) => Ok(Cow::Owned(owned)),
+ };
self.clear_acc();
ret.map_err(Error::from)
}
diff --git a/src/lib.rs b/src/lib.rs
index bfbb9c3..3dae164 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -202,12 +202,8 @@
while_true
)]
-#[cfg(feature = "actix")]
-extern crate actix_web;
-extern crate data_encoding;
#[macro_use]
extern crate error_chain;
-extern crate percent_encoding;
#[macro_use]
extern crate serde;
diff --git a/src/ser.rs b/src/ser.rs
index 9086ad2..618b148 100644
--- a/src/ser.rs
+++ b/src/ser.rs
@@ -4,7 +4,7 @@ use data_encoding::BASE64URL_NOPAD as BASE64;
use percent_encoding::{percent_encode, AsciiSet, NON_ALPHANUMERIC};
use serde::ser;
-use error::*;
+use crate::error::*;
use std::borrow::Cow;
use std::fmt::Display;
diff --git a/tests/test_actix.rs b/tests/test_actix.rs
index 532fa7c..34969d4 100644
--- a/tests/test_actix.rs
+++ b/tests/test_actix.rs
@@ -44,84 +44,99 @@ struct CommonParams {
#[test]
fn test_default_error_handler() {
- let req = TestRequest::with_uri("/test").to_srv_request();
- let (req, mut pl) = req.into_parts();
-
- let e = QsQuery::<Query>::from_request(&req, &mut pl).unwrap_err();
- assert_eq!(
- e.as_response_error().error_response().status(),
- StatusCode::BAD_REQUEST
- );
+ futures::executor::block_on(async {
+ let req = TestRequest::with_uri("/test").to_srv_request();
+ let (req, mut pl) = req.into_parts();
+
+ let e = QsQuery::<Query>::from_request(&req, &mut pl)
+ .await
+ .unwrap_err();
+ assert_eq!(
+ e.as_response_error().error_response().status(),
+ StatusCode::BAD_REQUEST
+ );
+ })
}
#[test]
fn test_custom_error_handler() {
- let req = TestRequest::with_uri("/test")
- .data(QsQueryConfig::default().error_handler(|e, _| {
- let resp = HttpResponse::UnprocessableEntity().finish();
- InternalError::from_response(e, resp).into()
- }))
- .to_srv_request();
-
- let (req, mut pl) = req.into_parts();
- let query = QsQuery::<Query>::from_request(&req, &mut pl);
-
- assert!(query.is_err());
- assert_eq!(
- query
- .unwrap_err()
- .as_response_error()
- .error_response()
- .status(),
- StatusCode::UNPROCESSABLE_ENTITY
- );
+ futures::executor::block_on(async {
+ let req = TestRequest::with_uri("/test")
+ .app_data(QsQueryConfig::default().error_handler(|e, _| {
+ let resp = HttpResponse::UnprocessableEntity().finish();
+ dbg!(&resp);
+ InternalError::from_response(e, resp).into()
+ }))
+ .to_srv_request();
+
+ let (req, mut pl) = req.into_parts();
+ let query = QsQuery::<Query>::from_request(&req, &mut pl).await;
+
+ assert!(query.is_err());
+ assert_eq!(
+ query
+ .unwrap_err()
+ .as_response_error()
+ .error_response()
+ .status(),
+ StatusCode::UNPROCESSABLE_ENTITY
+ );
+ })
}
#[test]
fn test_composite_querystring_extractor() {
- let req = TestRequest::with_uri(
- "/test?foo=1&bars[]=0&bars[]=1&limit=100&offset=50&remaining=true",
- )
- .to_srv_request();
- let (req, mut pl) = req.into_parts();
-
- let s = QsQuery::<Query>::from_request(&req, &mut pl).unwrap();
- assert_eq!(s.foo, 1);
- assert_eq!(s.bars, vec![0, 1]);
- assert_eq!(s.common.limit, 100);
- assert_eq!(s.common.offset, 50);
- assert_eq!(s.common.remaining, true);
+ futures::executor::block_on(async {
+ let req = TestRequest::with_uri(
+ "/test?foo=1&bars[]=0&bars[]=1&limit=100&offset=50&remaining=true",
+ )
+ .to_srv_request();
+ let (req, mut pl) = req.into_parts();
+
+ let s = QsQuery::<Query>::from_request(&req, &mut pl).await.unwrap();
+ assert_eq!(s.foo, 1);
+ assert_eq!(s.bars, vec![0, 1]);
+ assert_eq!(s.common.limit, 100);
+ assert_eq!(s.common.offset, 50);
+ assert_eq!(s.common.remaining, true);
+ })
}
#[test]
fn test_default_qs_config() {
- let req = TestRequest::with_uri(
- "/test?foo=1&bars%5B%5D=3&limit=100&offset=50&remaining=true",
- )
- .to_srv_request();
- let (req, mut pl) = req.into_parts();
-
- let e = QsQuery::<Query>::from_request(&req, &mut pl).unwrap_err();
- assert_eq!(
- e.as_response_error().error_response().status(),
- StatusCode::BAD_REQUEST
- );
+ futures::executor::block_on(async {
+ let req = TestRequest::with_uri(
+ "/test?foo=1&bars%5B%5D=3&limit=100&offset=50&remaining=true",
+ )
+ .to_srv_request();
+ let (req, mut pl) = req.into_parts();
+
+ let e = QsQuery::<Query>::from_request(&req, &mut pl)
+ .await
+ .unwrap_err();
+ assert_eq!(
+ e.as_response_error().error_response().status(),
+ StatusCode::BAD_REQUEST
+ );
+ })
}
#[test]
fn test_custom_qs_config() {
- let req = TestRequest::with_uri(
- "/test?foo=1&bars%5B%5D=3&limit=100&offset=50&remaining=true",
- )
- .data(QsQueryConfig::default().qs_config(QsConfig::new(5, false)))
- .to_srv_request();
-
- let (req, mut pl) = req.into_parts();
-
- let s = QsQuery::<Query>::from_request(&req, &mut pl).unwrap();
- assert_eq!(s.foo, 1);
- assert_eq!(s.bars, vec![3]);
- assert_eq!(s.common.limit, 100);
- assert_eq!(s.common.offset, 50);
- assert_eq!(s.common.remaining, true);
+ futures::executor::block_on(async {
+ let req = TestRequest::with_uri(
+ "/test?foo=1&bars%5B%5D=3&limit=100&offset=50&remaining=true",
+ )
+ .app_data(QsQueryConfig::default().qs_config(QsConfig::new(5, false)))
+ .to_srv_request();
+
+ let (req, mut pl) = req.into_parts();
+
+ let s = QsQuery::<Query>::from_request(&req, &mut pl).await.unwrap();
+ assert_eq!(s.foo, 1);
+ assert_eq!(s.bars, vec![3]);
+ assert_eq!(s.common.limit, 100);
+ assert_eq!(s.common.offset, 50);
+ assert_eq!(s.common.remaining, true);
+ })
}
diff --git a/tests/test_deserialize.rs b/tests/test_deserialize.rs
index beede63..4e02823 100644
--- a/tests/test_deserialize.rs
+++ b/tests/test_deserialize.rs
@@ -609,4 +609,4 @@ fn deserialize_plus() {
let test: Test = serde_qs::from_str("email=a%2Bb%40c.com").unwrap();
assert_eq!(test.email, "a+b@c.com");
-} \ No newline at end of file
+}
diff --git a/tests/test_serialize.rs b/tests/test_serialize.rs
index 8adae57..f650beb 100644
--- a/tests/test_serialize.rs
+++ b/tests/test_serialize.rs
@@ -5,6 +5,7 @@ extern crate serde_qs as qs;
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
struct Address {
city: String,
+ street: String,
postcode: String,
}
@@ -25,6 +26,7 @@ fn serialize_struct() {
phone: 12345,
address: Address {
city: "Carrot City".to_string(),
+ street: "Special-Street* No. 11".to_string(),
postcode: "12345".to_string(),
},
user_ids: vec![1, 2, 3, 4],
@@ -34,6 +36,7 @@ fn serialize_struct() {
qs::to_string(&params).unwrap(),
"\
id=42&name=Acme&phone=12345&address[city]=Carrot+City&\
+ address[street]=Special-Street*+No.+11&\
address[postcode]=12345&user_ids[0]=1&user_ids[1]=2&\
user_ids[2]=3&user_ids[3]=4"
);