mirror of https://github.com/fafhrd91/actix-web
fix feature resolving
This commit is contained in:
parent
adc94f505d
commit
3f6350a4b6
|
@ -1,3 +1,7 @@
|
|||
[alias]
|
||||
chk = "hack check --workspace --all-features --tests --examples"
|
||||
lint = "hack --clean-per-run clippy --workspace --tests --examples"
|
||||
ci-min = "hack check --workspace --no-default-features"
|
||||
ci-min-test = "hack check --workspace --no-default-features --tests --examples"
|
||||
ci-default = "hack check --workspace"
|
||||
ci-full = "check --workspace --bins --examples --tests"
|
||||
|
|
35
Cargo.toml
35
Cargo.toml
|
@ -16,7 +16,7 @@ edition = "2018"
|
|||
|
||||
[package.metadata.docs.rs]
|
||||
# features that docs.rs will build with
|
||||
features = ["openssl", "rustls", "compress", "secure-cookies"]
|
||||
features = ["openssl", "rustls", "compress", "cookies", "secure-cookies"]
|
||||
|
||||
[lib]
|
||||
name = "actix_web"
|
||||
|
@ -34,6 +34,7 @@ members = [
|
|||
"actix-http-test",
|
||||
"actix-test",
|
||||
]
|
||||
resolver = "2"
|
||||
|
||||
[features]
|
||||
default = ["compress", "cookies"]
|
||||
|
@ -53,22 +54,6 @@ openssl = ["actix-http/openssl", "actix-tls/accept", "actix-tls/openssl"]
|
|||
# rustls
|
||||
rustls = ["actix-http/rustls", "actix-tls/accept", "actix-tls/rustls"]
|
||||
|
||||
[[example]]
|
||||
name = "basic"
|
||||
required-features = ["compress"]
|
||||
|
||||
[[example]]
|
||||
name = "uds"
|
||||
required-features = ["compress"]
|
||||
|
||||
[[test]]
|
||||
name = "test_server"
|
||||
required-features = ["compress", "cookies"]
|
||||
|
||||
[[example]]
|
||||
name = "on_connect"
|
||||
required-features = []
|
||||
|
||||
[dependencies]
|
||||
actix-codec = "0.4.0-beta.1"
|
||||
actix-macros = "0.2.0"
|
||||
|
@ -135,6 +120,22 @@ actix-web-actors = { path = "actix-web-actors" }
|
|||
actix-web-codegen = { path = "actix-web-codegen" }
|
||||
awc = { path = "awc" }
|
||||
|
||||
[[test]]
|
||||
name = "test_server"
|
||||
required-features = ["compress", "cookies"]
|
||||
|
||||
[[example]]
|
||||
name = "basic"
|
||||
required-features = ["compress"]
|
||||
|
||||
[[example]]
|
||||
name = "uds"
|
||||
required-features = ["compress"]
|
||||
|
||||
[[example]]
|
||||
name = "on_connect"
|
||||
required-features = []
|
||||
|
||||
[[bench]]
|
||||
name = "server"
|
||||
harness = false
|
||||
|
|
|
@ -2,8 +2,13 @@
|
|||
|
||||
## Unreleased - 2021-xx-xx
|
||||
### Removed
|
||||
* `HttpMessage::cookies` and `HttpMessage::cookie`. [#????]
|
||||
* `impl ResponseError for CookieParseError`. [#????]
|
||||
* `cookies` feature flag. [#2065]
|
||||
* Top-level `cookies` mod (re-export). [#2065]
|
||||
* `HttpMessage` trait loses the `cookies` and `cookie` methods. [#2065]
|
||||
* `impl ResponseError for CookieParseError`. [#2065]
|
||||
|
||||
[#2065]: https://github.com/actix/actix-web/pull/2065
|
||||
|
||||
|
||||
## 3.0.0-beta.5 - 2021-04-02
|
||||
### Added
|
||||
|
|
|
@ -36,12 +36,12 @@ async fn main() -> io::Result<()> {
|
|||
|
||||
async fn handler(req: Request) -> Result<Response<BodyStream<Heartbeat>>, Error> {
|
||||
log::info!("handshaking");
|
||||
let res = ws::handshake(req.head())?;
|
||||
let mut res = ws::handshake(req.head())?;
|
||||
|
||||
// handshake will always fail under HTTP/2
|
||||
|
||||
log::info!("responding");
|
||||
Ok(res.set_body(BodyStream::new(Heartbeat::new(ws::Codec::new()))))
|
||||
Ok(res.message_body(BodyStream::new(Heartbeat::new(ws::Codec::new()))))
|
||||
}
|
||||
|
||||
struct Heartbeat {
|
||||
|
|
|
@ -14,9 +14,7 @@ use serde::de::value::Error as DeError;
|
|||
use serde_json::error::Error as JsonError;
|
||||
use serde_urlencoded::ser::Error as FormError;
|
||||
|
||||
use crate::body::Body;
|
||||
use crate::helpers::Writer;
|
||||
use crate::response::Response;
|
||||
use crate::{body::Body, helpers::Writer, Response, ResponseBuilder};
|
||||
|
||||
/// A specialized [`std::result::Result`]
|
||||
/// for actix web operations
|
||||
|
@ -135,12 +133,12 @@ impl From<Response> for Error {
|
|||
}
|
||||
}
|
||||
|
||||
// /// Convert ResponseBuilder to a Error
|
||||
// impl From<ResponseBuilder> for Error {
|
||||
// fn from(mut res: ResponseBuilder) -> Error {
|
||||
// InternalError::from_response("", res.finish()).into()
|
||||
// }
|
||||
// }
|
||||
/// Convert ResponseBuilder to a Error
|
||||
impl From<ResponseBuilder> for Error {
|
||||
fn from(mut res: ResponseBuilder) -> Error {
|
||||
InternalError::from_response("", res.finish()).into()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Display)]
|
||||
#[display(fmt = "UnknownError")]
|
||||
|
|
|
@ -340,14 +340,12 @@ where
|
|||
StateProj::ServiceCall(fut) => match fut.poll(cx) {
|
||||
// service call resolved. send response.
|
||||
Poll::Ready(Ok(res)) => {
|
||||
eprintln!("dispatcher ok!");
|
||||
let (res, body) = res.into().replace_body(());
|
||||
self.as_mut().send_response(res, body)?;
|
||||
}
|
||||
|
||||
// send service call error as response
|
||||
Poll::Ready(Err(err)) => {
|
||||
eprintln!("dispatcher err");
|
||||
let res = Response::from_error(err.into());
|
||||
let (res, body) = res.replace_body(());
|
||||
self.as_mut().send_response(res, body.into_body())?;
|
||||
|
|
|
@ -34,6 +34,18 @@ pub struct Response<B = Body> {
|
|||
}
|
||||
|
||||
impl Response<Body> {
|
||||
/// Create HTTP response builder with specific status.
|
||||
#[inline]
|
||||
pub fn build(status: StatusCode) -> ResponseBuilder {
|
||||
ResponseBuilder::new(status)
|
||||
}
|
||||
|
||||
/// Create HTTP response builder
|
||||
#[inline]
|
||||
pub fn build_from<T: Into<ResponseBuilder>>(source: T) -> ResponseBuilder {
|
||||
source.into()
|
||||
}
|
||||
|
||||
/// Constructs a response
|
||||
#[inline]
|
||||
pub fn new(status: StatusCode) -> Response {
|
||||
|
@ -444,6 +456,32 @@ impl ResponseBuilder {
|
|||
self
|
||||
}
|
||||
|
||||
/// This method calls provided closure with builder reference if value is `true`.
|
||||
#[doc(hidden)]
|
||||
#[deprecated = "Use an if statement."]
|
||||
pub fn if_true<F>(&mut self, value: bool, f: F) -> &mut Self
|
||||
where
|
||||
F: FnOnce(&mut ResponseBuilder),
|
||||
{
|
||||
if value {
|
||||
f(self);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// This method calls provided closure with builder reference if value is `Some`.
|
||||
#[doc(hidden)]
|
||||
#[deprecated = "Use an if-let construction."]
|
||||
pub fn if_some<T, F>(&mut self, value: Option<T>, f: F) -> &mut Self
|
||||
where
|
||||
F: FnOnce(T, &mut ResponseBuilder),
|
||||
{
|
||||
if let Some(val) = value {
|
||||
f(val, self);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Responses extensions
|
||||
#[inline]
|
||||
pub fn extensions(&self) -> Ref<'_, Extensions> {
|
||||
|
@ -692,7 +730,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_upgrade() {
|
||||
let resp = ResponseBuilder::new(StatusCode::OK)
|
||||
let resp = Response::build(StatusCode::OK)
|
||||
.upgrade("websocket")
|
||||
.finish();
|
||||
assert!(resp.upgrade());
|
||||
|
@ -704,13 +742,13 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_force_close() {
|
||||
let resp = ResponseBuilder::new(StatusCode::OK).force_close().finish();
|
||||
let resp = Response::build(StatusCode::OK).force_close().finish();
|
||||
assert!(!resp.keep_alive())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_content_type() {
|
||||
let resp = ResponseBuilder::new(StatusCode::OK)
|
||||
let resp = Response::build(StatusCode::OK)
|
||||
.content_type("text/plain")
|
||||
.body(Body::Empty);
|
||||
assert_eq!(resp.headers().get(CONTENT_TYPE).unwrap(), "text/plain")
|
||||
|
@ -731,7 +769,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_json_ct() {
|
||||
let resp = ResponseBuilder::new(StatusCode::OK)
|
||||
let resp = Response::build(StatusCode::OK)
|
||||
.insert_header((CONTENT_TYPE, "text/json"))
|
||||
.json(&vec!["v1", "v2", "v3"]);
|
||||
let ct = resp.headers().get(CONTENT_TYPE).unwrap();
|
||||
|
@ -744,7 +782,7 @@ mod tests {
|
|||
use serde_json::json;
|
||||
|
||||
let resp =
|
||||
ResponseBuilder::new(StatusCode::OK).body(json!({"test-key":"test-value"}));
|
||||
Response::build(StatusCode::OK).body(json!({"test-key":"test-value"}));
|
||||
assert_eq!(resp.body().get_ref(), br#"{"test-key":"test-value"}"#);
|
||||
}
|
||||
|
||||
|
@ -818,6 +856,24 @@ mod tests {
|
|||
assert_eq!(resp.body().get_ref(), b"test");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_into_builder() {
|
||||
let mut resp: Response = "test".into();
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
|
||||
resp.headers_mut().insert(
|
||||
HeaderName::from_static("cookie"),
|
||||
HeaderValue::from_static("cookie1=val100"),
|
||||
);
|
||||
|
||||
let mut builder: ResponseBuilder = resp.into();
|
||||
let resp = builder.status(StatusCode::BAD_REQUEST).finish();
|
||||
assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
|
||||
|
||||
let cookie = resp.headers().get_all("Cookie").next().unwrap();
|
||||
assert_eq!(cookie.to_str().unwrap(), "cookie1=val100");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn response_builder_header_insert_kv() {
|
||||
let mut res = Response::Ok();
|
||||
|
|
|
@ -9,10 +9,8 @@ use derive_more::{Display, Error, From};
|
|||
use http::{header, Method, StatusCode};
|
||||
|
||||
use crate::{
|
||||
error::ResponseError,
|
||||
header::HeaderValue,
|
||||
message::{ConnectionType, RequestHead},
|
||||
response::Response,
|
||||
error::ResponseError, header::HeaderValue, message::RequestHead, response::Response,
|
||||
ResponseBuilder,
|
||||
};
|
||||
|
||||
mod codec;
|
||||
|
@ -131,7 +129,7 @@ impl ResponseError for HandshakeError {
|
|||
}
|
||||
|
||||
/// Verify WebSocket handshake request and create handshake response.
|
||||
pub fn handshake(req: &RequestHead) -> Result<Response, HandshakeError> {
|
||||
pub fn handshake(req: &RequestHead) -> Result<ResponseBuilder, HandshakeError> {
|
||||
verify_handshake(req)?;
|
||||
Ok(handshake_response(req))
|
||||
}
|
||||
|
@ -187,39 +185,21 @@ pub fn verify_handshake(req: &RequestHead) -> Result<(), HandshakeError> {
|
|||
/// Create WebSocket handshake response.
|
||||
///
|
||||
/// This function returns handshake `Response`, ready to send to peer.
|
||||
pub fn handshake_response(req: &RequestHead) -> Response {
|
||||
pub fn handshake_response(req: &RequestHead) -> ResponseBuilder {
|
||||
let key = {
|
||||
let key = req.headers().get(header::SEC_WEBSOCKET_KEY).unwrap();
|
||||
proto::hash_key(key.as_ref())
|
||||
};
|
||||
|
||||
let mut res = Response::new(StatusCode::SWITCHING_PROTOCOLS);
|
||||
|
||||
res.head_mut().set_connection_type(ConnectionType::Upgrade);
|
||||
let headers = res.headers_mut();
|
||||
|
||||
headers.insert(header::UPGRADE, HeaderValue::from_static("websocket"));
|
||||
|
||||
headers.insert(
|
||||
header::TRANSFER_ENCODING,
|
||||
HeaderValue::from_static("chunked"),
|
||||
);
|
||||
headers.insert(
|
||||
header::SEC_WEBSOCKET_ACCEPT,
|
||||
// key is known to be header value safe ascii
|
||||
HeaderValue::from_bytes(&key).unwrap(),
|
||||
);
|
||||
|
||||
res
|
||||
|
||||
// Response::build(StatusCode::SWITCHING_PROTOCOLS)
|
||||
// .upgrade("websocket")
|
||||
// .insert_header((header::TRANSFER_ENCODING, "chunked"))
|
||||
// .insert_header((
|
||||
// header::SEC_WEBSOCKET_ACCEPT,
|
||||
// // key is known to be header value safe ascii
|
||||
// HeaderValue::from_bytes(&key).unwrap(),
|
||||
// ))
|
||||
Response::build(StatusCode::SWITCHING_PROTOCOLS)
|
||||
.upgrade("websocket")
|
||||
.insert_header((header::TRANSFER_ENCODING, "chunked"))
|
||||
.insert_header((
|
||||
header::SEC_WEBSOCKET_ACCEPT,
|
||||
// key is known to be header value safe ascii
|
||||
HeaderValue::from_bytes(&key).unwrap(),
|
||||
))
|
||||
.take()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -334,7 +314,7 @@ mod tests {
|
|||
.finish();
|
||||
assert_eq!(
|
||||
StatusCode::SWITCHING_PROTOCOLS,
|
||||
handshake_response(req.head()).status()
|
||||
handshake_response(req.head()).finish().status()
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ where
|
|||
|
||||
fn call(&self, (req, mut framed): (Request, Framed<T, h1::Codec>)) -> Self::Future {
|
||||
let fut = async move {
|
||||
let res = ws::handshake(req.head()).unwrap().set_body(());
|
||||
let res = ws::handshake(req.head()).unwrap().message_body(());
|
||||
|
||||
framed
|
||||
.send((res, body::BodySize::None).into())
|
||||
|
|
|
@ -163,7 +163,7 @@ pub fn handshake_with_protocols(
|
|||
.find(|req_p| protocols.iter().any(|p| p == req_p))
|
||||
});
|
||||
|
||||
let mut response = HttpResponseBuilder::new(StatusCode::SWITCHING_PROTOCOLS)
|
||||
let mut response = HttpResponse::build(StatusCode::SWITCHING_PROTOCOLS)
|
||||
.upgrade("websocket")
|
||||
.insert_header((
|
||||
header::SEC_WEBSOCKET_ACCEPT,
|
||||
|
|
|
@ -8,13 +8,13 @@ use futures_core::Stream;
|
|||
use serde::Serialize;
|
||||
|
||||
use actix_http::body::Body;
|
||||
#[cfg(feature = "cookies")]
|
||||
use actix_http::http::header::{self, IntoHeaderPair};
|
||||
use actix_http::http::{
|
||||
uri, ConnectionType, Error as HttpError, HeaderMap, HeaderValue, Method, Uri, Version,
|
||||
};
|
||||
use actix_http::{Error, RequestHead};
|
||||
|
||||
#[cfg(feature = "cookies")]
|
||||
use crate::cookie::{Cookie, CookieJar};
|
||||
use crate::error::{FreezeRequestError, InvalidUrl};
|
||||
use crate::frozen::FrozenClientRequest;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
//! Test helpers for actix http client to use during testing.
|
||||
use actix_http::http::header::IntoHeaderPair;
|
||||
use actix_http::http::header::{self, HeaderValue};
|
||||
use actix_http::http::{StatusCode, Version};
|
||||
use actix_http::{h1, Payload, ResponseHead};
|
||||
use bytes::Bytes;
|
||||
|
@ -90,6 +89,8 @@ impl TestResponse {
|
|||
|
||||
#[cfg(feature = "cookies")]
|
||||
for cookie in self.cookies.delta() {
|
||||
use actix_http::http::header::{self, HeaderValue};
|
||||
|
||||
head.headers.insert(
|
||||
header::SET_COOKIE,
|
||||
HeaderValue::from_str(&cookie.encoded().to_string()).unwrap(),
|
||||
|
|
|
@ -25,7 +25,7 @@ async fn test_simple() {
|
|||
HttpService::build()
|
||||
.upgrade(|(req, mut framed): (Request, Framed<_, _>)| {
|
||||
async move {
|
||||
let res = ws::handshake_response(req.head());
|
||||
let res = ws::handshake_response(req.head()).finish();
|
||||
// send handshake response
|
||||
framed
|
||||
.send(h1::Message::Item((res.drop_body(), BodySize::None)))
|
||||
|
|
|
@ -17,7 +17,7 @@ use smallvec::SmallVec;
|
|||
|
||||
use crate::{
|
||||
app_service::AppInitServiceState, config::AppConfig, error::UrlGenerationError,
|
||||
extract::FromRequest, http::header, info::ConnectionInfo, rmap::ResourceMap,
|
||||
extract::FromRequest, info::ConnectionInfo, rmap::ResourceMap,
|
||||
};
|
||||
|
||||
#[cfg(feature = "cookies")]
|
||||
|
@ -272,9 +272,11 @@ impl HttpRequest {
|
|||
/// Load request cookies.
|
||||
#[cfg(feature = "cookies")]
|
||||
pub fn cookies(&self) -> Result<Ref<'_, Vec<Cookie<'static>>>, CookieParseError> {
|
||||
use actix_http::http::header::COOKIE;
|
||||
|
||||
if self.extensions().get::<Cookies>().is_none() {
|
||||
let mut cookies = Vec::new();
|
||||
for hdr in self.headers().get_all(header::COOKIE) {
|
||||
for hdr in self.headers().get_all(COOKIE) {
|
||||
let s = str::from_utf8(hdr.as_bytes()).map_err(CookieParseError::from)?;
|
||||
for cookie_str in s.split(';').map(|s| s.trim()) {
|
||||
if !cookie_str.is_empty() {
|
||||
|
|
|
@ -3,7 +3,6 @@ use std::fmt;
|
|||
use actix_http::{
|
||||
error::InternalError,
|
||||
http::{header::IntoHeaderPair, Error as HttpError, HeaderMap, StatusCode},
|
||||
ResponseBuilder,
|
||||
};
|
||||
use bytes::{Bytes, BytesMut};
|
||||
|
||||
|
@ -73,11 +72,25 @@ impl Responder for actix_http::Response {
|
|||
}
|
||||
}
|
||||
|
||||
impl Responder for HttpResponseBuilder {
|
||||
#[inline]
|
||||
fn respond_to(mut self, _: &HttpRequest) -> HttpResponse {
|
||||
self.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl Responder for actix_http::ResponseBuilder {
|
||||
#[inline]
|
||||
fn respond_to(mut self, _: &HttpRequest) -> HttpResponse {
|
||||
HttpResponse::from(self.finish())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Responder> Responder for Option<T> {
|
||||
fn respond_to(self, req: &HttpRequest) -> HttpResponse {
|
||||
match self {
|
||||
Some(t) => t.respond_to(req),
|
||||
None => HttpResponseBuilder::new(StatusCode::NOT_FOUND).finish(),
|
||||
Some(val) => val.respond_to(req),
|
||||
None => HttpResponse::new(StatusCode::NOT_FOUND),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -95,20 +108,6 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl Responder for HttpResponseBuilder {
|
||||
#[inline]
|
||||
fn respond_to(mut self, _: &HttpRequest) -> HttpResponse {
|
||||
self.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl Responder for ResponseBuilder {
|
||||
#[inline]
|
||||
fn respond_to(mut self, _: &HttpRequest) -> HttpResponse {
|
||||
HttpResponse::from(self.finish())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Responder> Responder for (T, StatusCode) {
|
||||
fn respond_to(self, req: &HttpRequest) -> HttpResponse {
|
||||
let mut res = self.0.respond_to(req);
|
||||
|
|
16
src/test.rs
16
src/test.rs
|
@ -4,21 +4,19 @@ use std::{net::SocketAddr, rc::Rc};
|
|||
|
||||
pub use actix_http::test::TestBuffer;
|
||||
use actix_http::{
|
||||
http::{
|
||||
header::{self, HeaderValue, IntoHeaderPair},
|
||||
Method, StatusCode, Uri, Version,
|
||||
},
|
||||
http::{header::IntoHeaderPair, Method, StatusCode, Uri, Version},
|
||||
test::TestRequest as HttpTestRequest,
|
||||
Extensions, Request,
|
||||
};
|
||||
use actix_router::{Path, ResourceDef, Url};
|
||||
use actix_service::{IntoService, IntoServiceFactory, Service, ServiceFactory};
|
||||
use actix_utils::future::ok;
|
||||
use cookie::{Cookie, CookieJar};
|
||||
use futures_core::Stream;
|
||||
use futures_util::StreamExt as _;
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
|
||||
#[cfg(feature = "cookies")]
|
||||
use crate::cookie::{Cookie, CookieJar};
|
||||
use crate::{
|
||||
app_service::AppInitServiceState,
|
||||
config::AppConfig,
|
||||
|
@ -361,6 +359,7 @@ pub struct TestRequest {
|
|||
path: Path<Url>,
|
||||
peer_addr: Option<SocketAddr>,
|
||||
app_data: Extensions,
|
||||
#[cfg(feature = "cookies")]
|
||||
cookies: CookieJar,
|
||||
}
|
||||
|
||||
|
@ -373,6 +372,7 @@ impl Default for TestRequest {
|
|||
path: Path::new(Url::new(Uri::default())),
|
||||
peer_addr: None,
|
||||
app_data: Extensions::new(),
|
||||
#[cfg(feature = "cookies")]
|
||||
cookies: CookieJar::new(),
|
||||
}
|
||||
}
|
||||
|
@ -512,10 +512,14 @@ impl TestRequest {
|
|||
}
|
||||
|
||||
fn finish(&mut self) -> Request {
|
||||
// mut used when cookie feature is enabled
|
||||
#[allow(unused_mut)]
|
||||
let mut req = self.req.finish();
|
||||
|
||||
#[cfg(feature = "cookies")]
|
||||
{
|
||||
use actix_http::http::header::{HeaderValue, COOKIE};
|
||||
|
||||
let cookie: String = self
|
||||
.cookies
|
||||
.delta()
|
||||
|
@ -526,7 +530,7 @@ impl TestRequest {
|
|||
|
||||
if !cookie.is_empty() {
|
||||
req.headers_mut()
|
||||
.insert(header::COOKIE, HeaderValue::from_str(&cookie).unwrap());
|
||||
.insert(COOKIE, HeaderValue::from_str(&cookie).unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue