mirror of
https://github.com/fafhrd91/actix-web
synced 2025-01-18 13:51:50 +01:00
cookie is optional
This commit is contained in:
parent
00b7dc7887
commit
c5c7b244be
@ -31,8 +31,8 @@ before_cache: |
|
|||||||
|
|
||||||
script:
|
script:
|
||||||
- cargo clean
|
- cargo clean
|
||||||
- cargo build --features="ssl"
|
- cargo build --all-features
|
||||||
- cargo test --features="ssl"
|
- cargo test --all-features
|
||||||
|
|
||||||
# Upload docs
|
# Upload docs
|
||||||
after_success:
|
after_success:
|
||||||
|
24
Cargo.toml
24
Cargo.toml
@ -7,20 +7,20 @@ readme = "README.md"
|
|||||||
keywords = ["http", "web", "framework", "async", "futures"]
|
keywords = ["http", "web", "framework", "async", "futures"]
|
||||||
homepage = "https://actix.rs"
|
homepage = "https://actix.rs"
|
||||||
repository = "https://github.com/actix/actix-http.git"
|
repository = "https://github.com/actix/actix-http.git"
|
||||||
documentation = "https://actix.rs/api/actix-http/stable/actix_http/"
|
documentation = "https://docs.rs/actix-http/"
|
||||||
categories = ["network-programming", "asynchronous",
|
categories = ["network-programming", "asynchronous",
|
||||||
"web-programming::http-server",
|
"web-programming::http-server",
|
||||||
"web-programming::websocket"]
|
"web-programming::websocket"]
|
||||||
license = "Apache-2.0"
|
license = "MIT/Apache-2.0"
|
||||||
exclude = [".gitignore", ".travis.yml", ".cargo/config", "appveyor.yml"]
|
exclude = [".gitignore", ".travis.yml", ".cargo/config", "appveyor.yml"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
features = ["session"]
|
features = ["ssl", "fail", "cookie"]
|
||||||
|
|
||||||
[badges]
|
[badges]
|
||||||
travis-ci = { repository = "actix/actix-http", branch = "master" }
|
travis-ci = { repository = "actix/actix-http", branch = "master" }
|
||||||
appveyor = { repository = "fafhrd91/actix-http-b1qsn" }
|
# appveyor = { repository = "fafhrd91/actix-http-b1qsn" }
|
||||||
codecov = { repository = "actix/actix-http", branch = "master", service = "github" }
|
codecov = { repository = "actix/actix-http", branch = "master", service = "github" }
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
@ -28,13 +28,15 @@ name = "actix_http"
|
|||||||
path = "src/lib.rs"
|
path = "src/lib.rs"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["fail"]
|
default = []
|
||||||
|
|
||||||
# openssl
|
# openssl
|
||||||
ssl = ["openssl", "actix-connect/ssl"]
|
ssl = ["openssl", "actix-connect/ssl"]
|
||||||
|
|
||||||
# failure integration. it is on by default, it will be off in future versions
|
# cookies integration
|
||||||
# actix itself does not use failure anymore
|
cookies = ["cookie"]
|
||||||
|
|
||||||
|
# failure integration. actix does not use failure anymore
|
||||||
fail = ["failure"]
|
fail = ["failure"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
@ -49,7 +51,6 @@ backtrace = "0.3"
|
|||||||
bitflags = "1.0"
|
bitflags = "1.0"
|
||||||
bytes = "0.4"
|
bytes = "0.4"
|
||||||
byteorder = "1.2"
|
byteorder = "1.2"
|
||||||
cookie = { version="0.11", features=["percent-encode"] }
|
|
||||||
derive_more = "0.14"
|
derive_more = "0.14"
|
||||||
encoding = "0.2"
|
encoding = "0.2"
|
||||||
futures = "0.1"
|
futures = "0.1"
|
||||||
@ -76,11 +77,10 @@ tokio-timer = "0.2"
|
|||||||
tokio-current-thread = "0.1"
|
tokio-current-thread = "0.1"
|
||||||
trust-dns-resolver = { version="0.11.0-alpha.2", default-features = false }
|
trust-dns-resolver = { version="0.11.0-alpha.2", default-features = false }
|
||||||
|
|
||||||
# openssl
|
# optional deps
|
||||||
openssl = { version="0.10", optional = true }
|
cookie = { version="0.11", features=["percent-encode"], optional = true }
|
||||||
|
|
||||||
# failure is optional
|
|
||||||
failure = { version = "0.1.5", optional = true }
|
failure = { version = "0.1.5", optional = true }
|
||||||
|
openssl = { version="0.10", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
actix-rt = "0.2.0"
|
actix-rt = "0.2.0"
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fmt::Write as FmtWrite;
|
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
use actix_service::Service;
|
use actix_service::Service;
|
||||||
use bytes::{BufMut, Bytes, BytesMut};
|
use bytes::{BufMut, Bytes, BytesMut};
|
||||||
|
#[cfg(feature = "cookies")]
|
||||||
use cookie::{Cookie, CookieJar};
|
use cookie::{Cookie, CookieJar};
|
||||||
use futures::future::{err, Either};
|
use futures::future::{err, Either};
|
||||||
use futures::{Future, Stream};
|
use futures::{Future, Stream};
|
||||||
use percent_encoding::{percent_encode, USERINFO_ENCODE_SET};
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde_json;
|
use serde_json;
|
||||||
|
|
||||||
@ -58,6 +57,7 @@ impl ClientRequest<()> {
|
|||||||
ClientRequestBuilder {
|
ClientRequestBuilder {
|
||||||
head: Some(RequestHead::default()),
|
head: Some(RequestHead::default()),
|
||||||
err: None,
|
err: None,
|
||||||
|
#[cfg(feature = "cookies")]
|
||||||
cookies: None,
|
cookies: None,
|
||||||
default_headers: true,
|
default_headers: true,
|
||||||
}
|
}
|
||||||
@ -235,6 +235,7 @@ where
|
|||||||
pub struct ClientRequestBuilder {
|
pub struct ClientRequestBuilder {
|
||||||
head: Option<RequestHead>,
|
head: Option<RequestHead>,
|
||||||
err: Option<HttpError>,
|
err: Option<HttpError>,
|
||||||
|
#[cfg(feature = "cookies")]
|
||||||
cookies: Option<CookieJar>,
|
cookies: Option<CookieJar>,
|
||||||
default_headers: bool,
|
default_headers: bool,
|
||||||
}
|
}
|
||||||
@ -441,6 +442,7 @@ impl ClientRequestBuilder {
|
|||||||
self.header(header::CONTENT_LENGTH, wrt.get_mut().take().freeze())
|
self.header(header::CONTENT_LENGTH, wrt.get_mut().take().freeze())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "cookies")]
|
||||||
/// Set a cookie
|
/// Set a cookie
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
@ -560,20 +562,28 @@ impl ClientRequestBuilder {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused_mut)]
|
||||||
let mut head = self.head.take().expect("cannot reuse request builder");
|
let mut head = self.head.take().expect("cannot reuse request builder");
|
||||||
|
|
||||||
// set cookies
|
#[cfg(feature = "cookies")]
|
||||||
if let Some(ref mut jar) = self.cookies {
|
{
|
||||||
let mut cookie = String::new();
|
use percent_encoding::{percent_encode, USERINFO_ENCODE_SET};
|
||||||
for c in jar.delta() {
|
use std::fmt::Write;
|
||||||
let name = percent_encode(c.name().as_bytes(), USERINFO_ENCODE_SET);
|
|
||||||
let value = percent_encode(c.value().as_bytes(), USERINFO_ENCODE_SET);
|
// set cookies
|
||||||
let _ = write!(&mut cookie, "; {}={}", name, value);
|
if let Some(ref mut jar) = self.cookies {
|
||||||
|
let mut cookie = String::new();
|
||||||
|
for c in jar.delta() {
|
||||||
|
let name = percent_encode(c.name().as_bytes(), USERINFO_ENCODE_SET);
|
||||||
|
let value =
|
||||||
|
percent_encode(c.value().as_bytes(), USERINFO_ENCODE_SET);
|
||||||
|
let _ = write!(&mut cookie, "; {}={}", name, value);
|
||||||
|
}
|
||||||
|
head.headers.insert(
|
||||||
|
header::COOKIE,
|
||||||
|
HeaderValue::from_str(&cookie.as_str()[2..]).unwrap(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
head.headers.insert(
|
|
||||||
header::COOKIE,
|
|
||||||
HeaderValue::from_str(&cookie.as_str()[2..]).unwrap(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
Ok(ClientRequest { head, body })
|
Ok(ClientRequest { head, body })
|
||||||
}
|
}
|
||||||
@ -646,6 +656,7 @@ impl ClientRequestBuilder {
|
|||||||
ClientRequestBuilder {
|
ClientRequestBuilder {
|
||||||
head: self.head.take(),
|
head: self.head.take(),
|
||||||
err: self.err.take(),
|
err: self.err.take(),
|
||||||
|
#[cfg(feature = "cookies")]
|
||||||
cookies: self.cookies.take(),
|
cookies: self.cookies.take(),
|
||||||
default_headers: self.default_headers,
|
default_headers: self.default_headers,
|
||||||
}
|
}
|
||||||
|
17
src/error.rs
17
src/error.rs
@ -8,6 +8,7 @@ use std::{fmt, io, result};
|
|||||||
// use actix::MailboxError;
|
// use actix::MailboxError;
|
||||||
use actix_utils::timeout::TimeoutError;
|
use actix_utils::timeout::TimeoutError;
|
||||||
use backtrace::Backtrace;
|
use backtrace::Backtrace;
|
||||||
|
#[cfg(feature = "cookies")]
|
||||||
use cookie;
|
use cookie;
|
||||||
use derive_more::{Display, From};
|
use derive_more::{Display, From};
|
||||||
use futures::Canceled;
|
use futures::Canceled;
|
||||||
@ -19,7 +20,8 @@ use serde_json::error::Error as JsonError;
|
|||||||
use serde_urlencoded::ser::Error as FormError;
|
use serde_urlencoded::ser::Error as FormError;
|
||||||
use tokio_timer::Error as TimerError;
|
use tokio_timer::Error as TimerError;
|
||||||
|
|
||||||
// re-exports
|
// re-export for convinience
|
||||||
|
#[cfg(feature = "cookies")]
|
||||||
pub use cookie::ParseError as CookieParseError;
|
pub use cookie::ParseError as CookieParseError;
|
||||||
|
|
||||||
use crate::body::Body;
|
use crate::body::Body;
|
||||||
@ -322,6 +324,7 @@ impl ResponseError for PayloadError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Return `BadRequest` for `cookie::ParseError`
|
/// Return `BadRequest` for `cookie::ParseError`
|
||||||
|
#[cfg(feature = "cookies")]
|
||||||
impl ResponseError for cookie::ParseError {
|
impl ResponseError for cookie::ParseError {
|
||||||
fn error_response(&self) -> Response {
|
fn error_response(&self) -> Response {
|
||||||
Response::new(StatusCode::BAD_REQUEST)
|
Response::new(StatusCode::BAD_REQUEST)
|
||||||
@ -889,7 +892,6 @@ mod failure_integration {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use cookie::ParseError as CookieParseError;
|
|
||||||
use http::{Error as HttpError, StatusCode};
|
use http::{Error as HttpError, StatusCode};
|
||||||
use httparse;
|
use httparse;
|
||||||
use std::error::Error as StdError;
|
use std::error::Error as StdError;
|
||||||
@ -900,14 +902,19 @@ mod tests {
|
|||||||
let resp: Response = ParseError::Incomplete.error_response();
|
let resp: Response = ParseError::Incomplete.error_response();
|
||||||
assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
|
assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
|
||||||
|
|
||||||
let resp: Response = CookieParseError::EmptyName.error_response();
|
|
||||||
assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
|
|
||||||
|
|
||||||
let err: HttpError = StatusCode::from_u16(10000).err().unwrap().into();
|
let err: HttpError = StatusCode::from_u16(10000).err().unwrap().into();
|
||||||
let resp: Response = err.error_response();
|
let resp: Response = err.error_response();
|
||||||
assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
|
assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "cookies")]
|
||||||
|
#[test]
|
||||||
|
fn test_cookie_parse() {
|
||||||
|
use cookie::ParseError as CookieParseError;
|
||||||
|
let resp: Response = CookieParseError::EmptyName.error_response();
|
||||||
|
assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_as_response() {
|
fn test_as_response() {
|
||||||
let orig = io::Error::new(io::ErrorKind::Other, "other");
|
let orig = io::Error::new(io::ErrorKind::Other, "other");
|
||||||
|
@ -613,13 +613,12 @@ mod tests {
|
|||||||
let mut sys = actix_rt::System::new("test");
|
let mut sys = actix_rt::System::new("test");
|
||||||
let _ = sys.block_on(lazy(|| {
|
let _ = sys.block_on(lazy(|| {
|
||||||
let buf = Buffer::new("GET /test HTTP/1\r\n\r\n");
|
let buf = Buffer::new("GET /test HTTP/1\r\n\r\n");
|
||||||
let readbuf = BytesMut::new();
|
|
||||||
|
|
||||||
let mut h1 = Dispatcher::new(
|
let mut h1 = Dispatcher::new(
|
||||||
buf,
|
buf,
|
||||||
ServiceConfig::default(),
|
ServiceConfig::default(),
|
||||||
CloneableService::new(
|
CloneableService::new(
|
||||||
(|req| ok::<_, Error>(Response::Ok().finish())).into_service(),
|
(|_| ok::<_, Error>(Response::Ok().finish())).into_service(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
assert!(h1.poll().is_ok());
|
assert!(h1.poll().is_ok());
|
||||||
|
@ -1,18 +1,23 @@
|
|||||||
use std::cell::{Ref, RefMut};
|
use std::cell::{Ref, RefMut};
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
use cookie::Cookie;
|
|
||||||
use encoding::all::UTF_8;
|
use encoding::all::UTF_8;
|
||||||
use encoding::label::encoding_from_whatwg_label;
|
use encoding::label::encoding_from_whatwg_label;
|
||||||
use encoding::EncodingRef;
|
use encoding::EncodingRef;
|
||||||
use http::{header, HeaderMap};
|
use http::{header, HeaderMap};
|
||||||
use mime::Mime;
|
use mime::Mime;
|
||||||
|
|
||||||
use crate::error::{ContentTypeError, CookieParseError, ParseError};
|
use crate::error::{ContentTypeError, ParseError};
|
||||||
use crate::extensions::Extensions;
|
use crate::extensions::Extensions;
|
||||||
use crate::header::Header;
|
use crate::header::Header;
|
||||||
use crate::payload::Payload;
|
use crate::payload::Payload;
|
||||||
|
|
||||||
|
#[cfg(feature = "cookies")]
|
||||||
|
use crate::error::CookieParseError;
|
||||||
|
#[cfg(feature = "cookies")]
|
||||||
|
use cookie::Cookie;
|
||||||
|
|
||||||
|
#[cfg(feature = "cookies")]
|
||||||
struct Cookies(Vec<Cookie<'static>>);
|
struct Cookies(Vec<Cookie<'static>>);
|
||||||
|
|
||||||
/// Trait that implements general purpose operations on http messages
|
/// Trait that implements general purpose operations on http messages
|
||||||
@ -105,6 +110,7 @@ pub trait HttpMessage: Sized {
|
|||||||
|
|
||||||
/// Load request cookies.
|
/// Load request cookies.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[cfg(feature = "cookies")]
|
||||||
fn cookies(&self) -> Result<Ref<Vec<Cookie<'static>>>, CookieParseError> {
|
fn cookies(&self) -> Result<Ref<Vec<Cookie<'static>>>, CookieParseError> {
|
||||||
if self.extensions().get::<Cookies>().is_none() {
|
if self.extensions().get::<Cookies>().is_none() {
|
||||||
let mut cookies = Vec::new();
|
let mut cookies = Vec::new();
|
||||||
@ -125,6 +131,7 @@ pub trait HttpMessage: Sized {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Return request cookie.
|
/// Return request cookie.
|
||||||
|
#[cfg(feature = "cookies")]
|
||||||
fn cookie(&self, name: &str) -> Option<Cookie<'static>> {
|
fn cookie(&self, name: &str) -> Option<Cookie<'static>> {
|
||||||
if let Ok(cookies) = self.cookies() {
|
if let Ok(cookies) = self.cookies() {
|
||||||
for cookie in cookies.iter() {
|
for cookie in cookies.iter() {
|
||||||
|
@ -113,6 +113,7 @@ pub mod http {
|
|||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub use http::uri::PathAndQuery;
|
pub use http::uri::PathAndQuery;
|
||||||
|
|
||||||
|
#[cfg(feature = "cookies")]
|
||||||
pub use cookie::{Cookie, CookieBuilder};
|
pub use cookie::{Cookie, CookieBuilder};
|
||||||
|
|
||||||
/// Various http headers
|
/// Various http headers
|
||||||
|
@ -3,6 +3,7 @@ use std::io::Write;
|
|||||||
use std::{fmt, str};
|
use std::{fmt, str};
|
||||||
|
|
||||||
use bytes::{BufMut, Bytes, BytesMut};
|
use bytes::{BufMut, Bytes, BytesMut};
|
||||||
|
#[cfg(feature = "cookies")]
|
||||||
use cookie::{Cookie, CookieJar};
|
use cookie::{Cookie, CookieJar};
|
||||||
use futures::future::{ok, FutureResult, IntoFuture};
|
use futures::future::{ok, FutureResult, IntoFuture};
|
||||||
use futures::Stream;
|
use futures::Stream;
|
||||||
@ -128,6 +129,7 @@ impl<B> Response<B> {
|
|||||||
|
|
||||||
/// Get an iterator for the cookies set by this response
|
/// Get an iterator for the cookies set by this response
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[cfg(feature = "cookies")]
|
||||||
pub fn cookies(&self) -> CookieIter {
|
pub fn cookies(&self) -> CookieIter {
|
||||||
CookieIter {
|
CookieIter {
|
||||||
iter: self.head.headers.get_all(header::SET_COOKIE).iter(),
|
iter: self.head.headers.get_all(header::SET_COOKIE).iter(),
|
||||||
@ -136,6 +138,7 @@ impl<B> Response<B> {
|
|||||||
|
|
||||||
/// Add a cookie to this response
|
/// Add a cookie to this response
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[cfg(feature = "cookies")]
|
||||||
pub fn add_cookie(&mut self, cookie: &Cookie) -> Result<(), HttpError> {
|
pub fn add_cookie(&mut self, cookie: &Cookie) -> Result<(), HttpError> {
|
||||||
let h = &mut self.head.headers;
|
let h = &mut self.head.headers;
|
||||||
HeaderValue::from_str(&cookie.to_string())
|
HeaderValue::from_str(&cookie.to_string())
|
||||||
@ -148,6 +151,7 @@ impl<B> Response<B> {
|
|||||||
/// Remove all cookies with the given name from this response. Returns
|
/// Remove all cookies with the given name from this response. Returns
|
||||||
/// the number of cookies removed.
|
/// the number of cookies removed.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[cfg(feature = "cookies")]
|
||||||
pub fn del_cookie(&mut self, name: &str) -> usize {
|
pub fn del_cookie(&mut self, name: &str) -> usize {
|
||||||
let h = &mut self.head.headers;
|
let h = &mut self.head.headers;
|
||||||
let vals: Vec<HeaderValue> = h
|
let vals: Vec<HeaderValue> = h
|
||||||
@ -267,10 +271,12 @@ impl IntoFuture for Response {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "cookies")]
|
||||||
pub struct CookieIter<'a> {
|
pub struct CookieIter<'a> {
|
||||||
iter: header::ValueIter<'a, HeaderValue>,
|
iter: header::ValueIter<'a, HeaderValue>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "cookies")]
|
||||||
impl<'a> Iterator for CookieIter<'a> {
|
impl<'a> Iterator for CookieIter<'a> {
|
||||||
type Item = Cookie<'a>;
|
type Item = Cookie<'a>;
|
||||||
|
|
||||||
@ -292,6 +298,7 @@ impl<'a> Iterator for CookieIter<'a> {
|
|||||||
pub struct ResponseBuilder {
|
pub struct ResponseBuilder {
|
||||||
head: Option<Message<ResponseHead>>,
|
head: Option<Message<ResponseHead>>,
|
||||||
err: Option<HttpError>,
|
err: Option<HttpError>,
|
||||||
|
#[cfg(feature = "cookies")]
|
||||||
cookies: Option<CookieJar>,
|
cookies: Option<CookieJar>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -304,6 +311,7 @@ impl ResponseBuilder {
|
|||||||
ResponseBuilder {
|
ResponseBuilder {
|
||||||
head: Some(head),
|
head: Some(head),
|
||||||
err: None,
|
err: None,
|
||||||
|
#[cfg(feature = "cookies")]
|
||||||
cookies: None,
|
cookies: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -503,6 +511,7 @@ impl ResponseBuilder {
|
|||||||
/// .finish()
|
/// .finish()
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
#[cfg(feature = "cookies")]
|
||||||
pub fn cookie<'c>(&mut self, cookie: Cookie<'c>) -> &mut Self {
|
pub fn cookie<'c>(&mut self, cookie: Cookie<'c>) -> &mut Self {
|
||||||
if self.cookies.is_none() {
|
if self.cookies.is_none() {
|
||||||
let mut jar = CookieJar::new();
|
let mut jar = CookieJar::new();
|
||||||
@ -530,6 +539,7 @@ impl ResponseBuilder {
|
|||||||
/// builder.finish()
|
/// builder.finish()
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
#[cfg(feature = "cookies")]
|
||||||
pub fn del_cookie<'a>(&mut self, cookie: &Cookie<'a>) -> &mut Self {
|
pub fn del_cookie<'a>(&mut self, cookie: &Cookie<'a>) -> &mut Self {
|
||||||
{
|
{
|
||||||
if self.cookies.is_none() {
|
if self.cookies.is_none() {
|
||||||
@ -582,15 +592,20 @@ impl ResponseBuilder {
|
|||||||
return Response::from(Error::from(e)).into_body();
|
return Response::from(Error::from(e)).into_body();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused_mut)]
|
||||||
let mut response = self.head.take().expect("cannot reuse response builder");
|
let mut response = self.head.take().expect("cannot reuse response builder");
|
||||||
if let Some(ref jar) = self.cookies {
|
|
||||||
for cookie in jar.delta() {
|
#[cfg(feature = "cookies")]
|
||||||
match HeaderValue::from_str(&cookie.to_string()) {
|
{
|
||||||
Ok(val) => {
|
if let Some(ref jar) = self.cookies {
|
||||||
let _ = response.headers.append(header::SET_COOKIE, val);
|
for cookie in jar.delta() {
|
||||||
}
|
match HeaderValue::from_str(&cookie.to_string()) {
|
||||||
Err(e) => return Response::from(Error::from(e)).into_body(),
|
Ok(val) => {
|
||||||
};
|
let _ = response.headers.append(header::SET_COOKIE, val);
|
||||||
|
}
|
||||||
|
Err(e) => return Response::from(Error::from(e)).into_body(),
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -654,6 +669,7 @@ impl ResponseBuilder {
|
|||||||
ResponseBuilder {
|
ResponseBuilder {
|
||||||
head: self.head.take(),
|
head: self.head.take(),
|
||||||
err: self.err.take(),
|
err: self.err.take(),
|
||||||
|
#[cfg(feature = "cookies")]
|
||||||
cookies: self.cookies.take(),
|
cookies: self.cookies.take(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -674,7 +690,9 @@ fn parts<'a>(
|
|||||||
impl<B> From<Response<B>> for ResponseBuilder {
|
impl<B> From<Response<B>> for ResponseBuilder {
|
||||||
fn from(res: Response<B>) -> ResponseBuilder {
|
fn from(res: Response<B>) -> ResponseBuilder {
|
||||||
// If this response has cookies, load them into a jar
|
// If this response has cookies, load them into a jar
|
||||||
|
#[cfg(feature = "cookies")]
|
||||||
let mut jar: Option<CookieJar> = None;
|
let mut jar: Option<CookieJar> = None;
|
||||||
|
#[cfg(feature = "cookies")]
|
||||||
for c in res.cookies() {
|
for c in res.cookies() {
|
||||||
if let Some(ref mut j) = jar {
|
if let Some(ref mut j) = jar {
|
||||||
j.add_original(c.into_owned());
|
j.add_original(c.into_owned());
|
||||||
@ -688,6 +706,7 @@ impl<B> From<Response<B>> for ResponseBuilder {
|
|||||||
ResponseBuilder {
|
ResponseBuilder {
|
||||||
head: Some(res.head),
|
head: Some(res.head),
|
||||||
err: None,
|
err: None,
|
||||||
|
#[cfg(feature = "cookies")]
|
||||||
cookies: jar,
|
cookies: jar,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -697,17 +716,22 @@ impl<B> From<Response<B>> for ResponseBuilder {
|
|||||||
impl<'a> From<&'a ResponseHead> for ResponseBuilder {
|
impl<'a> From<&'a ResponseHead> for ResponseBuilder {
|
||||||
fn from(head: &'a ResponseHead) -> ResponseBuilder {
|
fn from(head: &'a ResponseHead) -> ResponseBuilder {
|
||||||
// If this response has cookies, load them into a jar
|
// If this response has cookies, load them into a jar
|
||||||
|
#[cfg(feature = "cookies")]
|
||||||
let mut jar: Option<CookieJar> = None;
|
let mut jar: Option<CookieJar> = None;
|
||||||
let cookies = CookieIter {
|
|
||||||
iter: head.headers.get_all(header::SET_COOKIE).iter(),
|
#[cfg(feature = "cookies")]
|
||||||
};
|
{
|
||||||
for c in cookies {
|
let cookies = CookieIter {
|
||||||
if let Some(ref mut j) = jar {
|
iter: head.headers.get_all(header::SET_COOKIE).iter(),
|
||||||
j.add_original(c.into_owned());
|
};
|
||||||
} else {
|
for c in cookies {
|
||||||
let mut j = CookieJar::new();
|
if let Some(ref mut j) = jar {
|
||||||
j.add_original(c.into_owned());
|
j.add_original(c.into_owned());
|
||||||
jar = Some(j);
|
} else {
|
||||||
|
let mut j = CookieJar::new();
|
||||||
|
j.add_original(c.into_owned());
|
||||||
|
jar = Some(j);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -721,6 +745,7 @@ impl<'a> From<&'a ResponseHead> for ResponseBuilder {
|
|||||||
ResponseBuilder {
|
ResponseBuilder {
|
||||||
head: Some(msg),
|
head: Some(msg),
|
||||||
err: None,
|
err: None,
|
||||||
|
#[cfg(feature = "cookies")]
|
||||||
cookies: jar,
|
cookies: jar,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -802,14 +827,9 @@ impl From<BytesMut> for Response {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use time::Duration;
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::body::Body;
|
use crate::body::Body;
|
||||||
use crate::http;
|
|
||||||
use crate::http::header::{HeaderValue, CONTENT_TYPE, COOKIE};
|
use crate::http::header::{HeaderValue, CONTENT_TYPE, COOKIE};
|
||||||
use crate::httpmessage::HttpMessage;
|
|
||||||
use crate::test::TestRequest;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_debug() {
|
fn test_debug() {
|
||||||
@ -822,8 +842,11 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg(feature = "cookies")]
|
||||||
fn test_response_cookies() {
|
fn test_response_cookies() {
|
||||||
let req = TestRequest::default()
|
use crate::httpmessage::HttpMessage;
|
||||||
|
|
||||||
|
let req = crate::test::TestRequest::default()
|
||||||
.header(COOKIE, "cookie1=value1")
|
.header(COOKIE, "cookie1=value1")
|
||||||
.header(COOKIE, "cookie2=value2")
|
.header(COOKIE, "cookie2=value2")
|
||||||
.finish();
|
.finish();
|
||||||
@ -831,11 +854,11 @@ mod tests {
|
|||||||
|
|
||||||
let resp = Response::Ok()
|
let resp = Response::Ok()
|
||||||
.cookie(
|
.cookie(
|
||||||
http::Cookie::build("name", "value")
|
crate::http::Cookie::build("name", "value")
|
||||||
.domain("www.rust-lang.org")
|
.domain("www.rust-lang.org")
|
||||||
.path("/test")
|
.path("/test")
|
||||||
.http_only(true)
|
.http_only(true)
|
||||||
.max_age(Duration::days(1))
|
.max_age(time::Duration::days(1))
|
||||||
.finish(),
|
.finish(),
|
||||||
)
|
)
|
||||||
.del_cookie(&cookies[0])
|
.del_cookie(&cookies[0])
|
||||||
@ -856,16 +879,17 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg(feature = "cookies")]
|
||||||
fn test_update_response_cookies() {
|
fn test_update_response_cookies() {
|
||||||
let mut r = Response::Ok()
|
let mut r = Response::Ok()
|
||||||
.cookie(http::Cookie::new("original", "val100"))
|
.cookie(crate::http::Cookie::new("original", "val100"))
|
||||||
.finish();
|
.finish();
|
||||||
|
|
||||||
r.add_cookie(&http::Cookie::new("cookie2", "val200"))
|
r.add_cookie(&crate::http::Cookie::new("cookie2", "val200"))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
r.add_cookie(&http::Cookie::new("cookie2", "val250"))
|
r.add_cookie(&crate::http::Cookie::new("cookie2", "val250"))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
r.add_cookie(&http::Cookie::new("cookie3", "val300"))
|
r.add_cookie(&crate::http::Cookie::new("cookie3", "val300"))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(r.cookies().count(), 4);
|
assert_eq!(r.cookies().count(), 4);
|
||||||
@ -1016,11 +1040,14 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg(feature = "cookies")]
|
||||||
fn test_into_builder() {
|
fn test_into_builder() {
|
||||||
|
use crate::httpmessage::HttpMessage;
|
||||||
|
|
||||||
let mut resp: Response = "test".into();
|
let mut resp: Response = "test".into();
|
||||||
assert_eq!(resp.status(), StatusCode::OK);
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
|
|
||||||
resp.add_cookie(&http::Cookie::new("cookie1", "val100"))
|
resp.add_cookie(&crate::http::Cookie::new("cookie1", "val100"))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let mut builder: ResponseBuilder = resp.into();
|
let mut builder: ResponseBuilder = resp.into();
|
||||||
|
57
src/test.rs
57
src/test.rs
@ -1,12 +1,11 @@
|
|||||||
//! Test Various helpers for Actix applications to use during testing.
|
//! Test Various helpers for Actix applications to use during testing.
|
||||||
use std::fmt::Write as FmtWrite;
|
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
|
#[cfg(feature = "cookies")]
|
||||||
use cookie::{Cookie, CookieJar};
|
use cookie::{Cookie, CookieJar};
|
||||||
use http::header::{self, HeaderName, HeaderValue};
|
use http::header::HeaderName;
|
||||||
use http::{HeaderMap, HttpTryFrom, Method, Uri, Version};
|
use http::{HeaderMap, HttpTryFrom, Method, Uri, Version};
|
||||||
use percent_encoding::{percent_encode, USERINFO_ENCODE_SET};
|
|
||||||
|
|
||||||
use crate::header::{Header, IntoHeaderValue};
|
use crate::header::{Header, IntoHeaderValue};
|
||||||
use crate::payload::Payload;
|
use crate::payload::Payload;
|
||||||
@ -46,6 +45,7 @@ struct Inner {
|
|||||||
method: Method,
|
method: Method,
|
||||||
uri: Uri,
|
uri: Uri,
|
||||||
headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
#[cfg(feature = "cookies")]
|
||||||
cookies: CookieJar,
|
cookies: CookieJar,
|
||||||
payload: Option<Payload>,
|
payload: Option<Payload>,
|
||||||
}
|
}
|
||||||
@ -57,6 +57,7 @@ impl Default for TestRequest {
|
|||||||
uri: Uri::from_str("/").unwrap(),
|
uri: Uri::from_str("/").unwrap(),
|
||||||
version: Version::HTTP_11,
|
version: Version::HTTP_11,
|
||||||
headers: HeaderMap::new(),
|
headers: HeaderMap::new(),
|
||||||
|
#[cfg(feature = "cookies")]
|
||||||
cookies: CookieJar::new(),
|
cookies: CookieJar::new(),
|
||||||
payload: None,
|
payload: None,
|
||||||
}))
|
}))
|
||||||
@ -126,6 +127,7 @@ impl TestRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Set cookie for this request
|
/// Set cookie for this request
|
||||||
|
#[cfg(feature = "cookies")]
|
||||||
pub fn cookie<'a>(&mut self, cookie: Cookie<'a>) -> &mut Self {
|
pub fn cookie<'a>(&mut self, cookie: Cookie<'a>) -> &mut Self {
|
||||||
parts(&mut self.0).cookies.add(cookie.into_owned());
|
parts(&mut self.0).cookies.add(cookie.into_owned());
|
||||||
self
|
self
|
||||||
@ -145,38 +147,39 @@ impl TestRequest {
|
|||||||
|
|
||||||
/// Complete request creation and generate `Request` instance
|
/// Complete request creation and generate `Request` instance
|
||||||
pub fn finish(&mut self) -> Request {
|
pub fn finish(&mut self) -> Request {
|
||||||
let Inner {
|
let inner = self.0.take().expect("cannot reuse test request builder");;
|
||||||
method,
|
|
||||||
uri,
|
|
||||||
version,
|
|
||||||
headers,
|
|
||||||
payload,
|
|
||||||
cookies,
|
|
||||||
} = self.0.take().expect("cannot reuse test request builder");;
|
|
||||||
|
|
||||||
let mut req = if let Some(pl) = payload {
|
let mut req = if let Some(pl) = inner.payload {
|
||||||
Request::with_payload(pl)
|
Request::with_payload(pl)
|
||||||
} else {
|
} else {
|
||||||
Request::with_payload(crate::h1::Payload::empty().into())
|
Request::with_payload(crate::h1::Payload::empty().into())
|
||||||
};
|
};
|
||||||
|
|
||||||
let head = req.head_mut();
|
let head = req.head_mut();
|
||||||
head.uri = uri;
|
head.uri = inner.uri;
|
||||||
head.method = method;
|
head.method = inner.method;
|
||||||
head.version = version;
|
head.version = inner.version;
|
||||||
head.headers = headers;
|
head.headers = inner.headers;
|
||||||
|
|
||||||
let mut cookie = String::new();
|
#[cfg(feature = "cookies")]
|
||||||
for c in cookies.delta() {
|
{
|
||||||
let name = percent_encode(c.name().as_bytes(), USERINFO_ENCODE_SET);
|
use std::fmt::Write as FmtWrite;
|
||||||
let value = percent_encode(c.value().as_bytes(), USERINFO_ENCODE_SET);
|
|
||||||
let _ = write!(&mut cookie, "; {}={}", name, value);
|
use http::header::{self, HeaderValue};
|
||||||
}
|
use percent_encoding::{percent_encode, USERINFO_ENCODE_SET};
|
||||||
if !cookie.is_empty() {
|
|
||||||
head.headers.insert(
|
let mut cookie = String::new();
|
||||||
header::COOKIE,
|
for c in inner.cookies.delta() {
|
||||||
HeaderValue::from_str(&cookie.as_str()[2..]).unwrap(),
|
let name = percent_encode(c.name().as_bytes(), USERINFO_ENCODE_SET);
|
||||||
);
|
let value = percent_encode(c.value().as_bytes(), USERINFO_ENCODE_SET);
|
||||||
|
let _ = write!(&mut cookie, "; {}={}", name, value);
|
||||||
|
}
|
||||||
|
if !cookie.is_empty() {
|
||||||
|
head.headers.insert(
|
||||||
|
header::COOKIE,
|
||||||
|
HeaderValue::from_str(&cookie.as_str()[2..]).unwrap(),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
req
|
req
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
//! Http client request
|
//! Http client request
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
|
#[cfg(feature = "cookies")]
|
||||||
use cookie::Cookie;
|
use cookie::Cookie;
|
||||||
use http::header::{HeaderName, HeaderValue};
|
use http::header::{HeaderName, HeaderValue};
|
||||||
use http::{Error as HttpError, HttpTryFrom};
|
use http::{Error as HttpError, HttpTryFrom};
|
||||||
@ -50,6 +51,7 @@ impl Connect {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "cookies")]
|
||||||
/// Set cookie for handshake request
|
/// Set cookie for handshake request
|
||||||
pub fn cookie(mut self, cookie: Cookie) -> Self {
|
pub fn cookie(mut self, cookie: Cookie) -> Self {
|
||||||
self.request.cookie(cookie);
|
self.request.cookie(cookie);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user