1
0
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:
Nikolay Kim 2019-03-23 09:40:20 -07:00
parent 00b7dc7887
commit c5c7b244be
10 changed files with 151 additions and 94 deletions

View File

@ -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:

View File

@ -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"

View File

@ -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,14 +562,21 @@ 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");
#[cfg(feature = "cookies")]
{
use percent_encoding::{percent_encode, USERINFO_ENCODE_SET};
use std::fmt::Write;
// set cookies // set cookies
if let Some(ref mut jar) = self.cookies { if let Some(ref mut jar) = self.cookies {
let mut cookie = String::new(); let mut cookie = String::new();
for c in jar.delta() { for c in jar.delta() {
let name = percent_encode(c.name().as_bytes(), USERINFO_ENCODE_SET); let name = percent_encode(c.name().as_bytes(), USERINFO_ENCODE_SET);
let value = percent_encode(c.value().as_bytes(), USERINFO_ENCODE_SET); let value =
percent_encode(c.value().as_bytes(), USERINFO_ENCODE_SET);
let _ = write!(&mut cookie, "; {}={}", name, value); let _ = write!(&mut cookie, "; {}={}", name, value);
} }
head.headers.insert( head.headers.insert(
@ -575,6 +584,7 @@ impl ClientRequestBuilder {
HeaderValue::from_str(&cookie.as_str()[2..]).unwrap(), 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,
} }

View File

@ -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");

View File

@ -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());

View File

@ -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() {

View File

@ -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

View File

@ -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,7 +592,11 @@ 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");
#[cfg(feature = "cookies")]
{
if let Some(ref jar) = self.cookies { if let Some(ref jar) = self.cookies {
for cookie in jar.delta() { for cookie in jar.delta() {
match HeaderValue::from_str(&cookie.to_string()) { match HeaderValue::from_str(&cookie.to_string()) {
@ -593,6 +607,7 @@ impl ResponseBuilder {
}; };
} }
} }
}
Response { Response {
head: response, head: response,
@ -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,7 +716,11 @@ 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;
#[cfg(feature = "cookies")]
{
let cookies = CookieIter { let cookies = CookieIter {
iter: head.headers.get_all(header::SET_COOKIE).iter(), iter: head.headers.get_all(header::SET_COOKIE).iter(),
}; };
@ -710,6 +733,7 @@ impl<'a> From<&'a ResponseHead> for ResponseBuilder {
jar = Some(j); jar = Some(j);
} }
} }
}
let mut msg: Message<ResponseHead> = Message::new(); let mut msg: Message<ResponseHead> = Message::new();
msg.version = head.version; msg.version = head.version;
@ -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();

View File

@ -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,29 +147,29 @@ 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;
#[cfg(feature = "cookies")]
{
use std::fmt::Write as FmtWrite;
use http::header::{self, HeaderValue};
use percent_encoding::{percent_encode, USERINFO_ENCODE_SET};
let mut cookie = String::new(); let mut cookie = String::new();
for c in cookies.delta() { for c in inner.cookies.delta() {
let name = percent_encode(c.name().as_bytes(), USERINFO_ENCODE_SET); let name = percent_encode(c.name().as_bytes(), USERINFO_ENCODE_SET);
let value = percent_encode(c.value().as_bytes(), USERINFO_ENCODE_SET); let value = percent_encode(c.value().as_bytes(), USERINFO_ENCODE_SET);
let _ = write!(&mut cookie, "; {}={}", name, value); let _ = write!(&mut cookie, "; {}={}", name, value);
@ -178,6 +180,7 @@ impl TestRequest {
HeaderValue::from_str(&cookie.as_str()[2..]).unwrap(), HeaderValue::from_str(&cookie.as_str()[2..]).unwrap(),
); );
} }
}
req req
} }

View File

@ -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);