mirror of
https://github.com/actix/actix-extras.git
synced 2024-11-28 09:42:40 +01:00
add nested scope support
This commit is contained in:
parent
70d0c5c700
commit
48e05a2d87
@ -69,9 +69,11 @@ impl<S: 'static> HttpApplication<S> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if m {
|
if m {
|
||||||
let path: &'static str = unsafe {
|
let prefix_len = inner.prefix + prefix.len();
|
||||||
&*(&req.path()[inner.prefix + prefix.len()..] as *const _)
|
let path: &'static str =
|
||||||
};
|
unsafe { &*(&req.path()[prefix_len..] as *const _) };
|
||||||
|
|
||||||
|
req.set_prefix_len(prefix_len as u16);
|
||||||
if path.is_empty() {
|
if path.is_empty() {
|
||||||
req.match_info_mut().add("tail", "/");
|
req.match_info_mut().add("tail", "/");
|
||||||
} else {
|
} else {
|
||||||
@ -881,8 +883,9 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let req = TestRequest::with_uri("/app/test").finish();
|
let req = TestRequest::with_uri("/app/test").finish();
|
||||||
let resp = app.run(req);
|
let resp = app.run(req.clone());
|
||||||
assert_eq!(resp.as_response().unwrap().status(), StatusCode::OK);
|
assert_eq!(resp.as_response().unwrap().status(), StatusCode::OK);
|
||||||
|
assert_eq!(req.prefix_len(), 9);
|
||||||
|
|
||||||
let req = TestRequest::with_uri("/app/test/").finish();
|
let req = TestRequest::with_uri("/app/test/").finish();
|
||||||
let resp = app.run(req);
|
let resp = app.run(req);
|
||||||
|
@ -25,20 +25,27 @@ use router::{Resource, Router};
|
|||||||
use server::helpers::SharedHttpInnerMessage;
|
use server::helpers::SharedHttpInnerMessage;
|
||||||
use uri::Url as InnerUrl;
|
use uri::Url as InnerUrl;
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
pub(crate) struct MessageFlags: u8 {
|
||||||
|
const QUERY = 0b0000_0001;
|
||||||
|
const KEEPALIVE = 0b0000_0010;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct HttpInnerMessage {
|
pub struct HttpInnerMessage {
|
||||||
pub version: Version,
|
pub version: Version,
|
||||||
pub method: Method,
|
pub method: Method,
|
||||||
pub(crate) url: InnerUrl,
|
pub(crate) url: InnerUrl,
|
||||||
|
pub(crate) flags: MessageFlags,
|
||||||
pub headers: HeaderMap,
|
pub headers: HeaderMap,
|
||||||
pub extensions: Extensions,
|
pub extensions: Extensions,
|
||||||
pub params: Params<'static>,
|
pub params: Params<'static>,
|
||||||
pub cookies: Option<Vec<Cookie<'static>>>,
|
pub cookies: Option<Vec<Cookie<'static>>>,
|
||||||
pub query: Params<'static>,
|
pub query: Params<'static>,
|
||||||
pub query_loaded: bool,
|
|
||||||
pub addr: Option<SocketAddr>,
|
pub addr: Option<SocketAddr>,
|
||||||
pub payload: Option<Payload>,
|
pub payload: Option<Payload>,
|
||||||
pub info: Option<ConnectionInfo<'static>>,
|
pub info: Option<ConnectionInfo<'static>>,
|
||||||
pub keep_alive: bool,
|
pub prefix: u16,
|
||||||
resource: RouterResource,
|
resource: RouterResource,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,15 +62,15 @@ impl Default for HttpInnerMessage {
|
|||||||
url: InnerUrl::default(),
|
url: InnerUrl::default(),
|
||||||
version: Version::HTTP_11,
|
version: Version::HTTP_11,
|
||||||
headers: HeaderMap::with_capacity(16),
|
headers: HeaderMap::with_capacity(16),
|
||||||
|
flags: MessageFlags::empty(),
|
||||||
params: Params::new(),
|
params: Params::new(),
|
||||||
query: Params::new(),
|
query: Params::new(),
|
||||||
query_loaded: false,
|
|
||||||
addr: None,
|
addr: None,
|
||||||
cookies: None,
|
cookies: None,
|
||||||
payload: None,
|
payload: None,
|
||||||
extensions: Extensions::new(),
|
extensions: Extensions::new(),
|
||||||
info: None,
|
info: None,
|
||||||
keep_alive: true,
|
prefix: 0,
|
||||||
resource: RouterResource::Notset,
|
resource: RouterResource::Notset,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -73,7 +80,7 @@ impl HttpInnerMessage {
|
|||||||
/// Checks if a connection should be kept alive.
|
/// Checks if a connection should be kept alive.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn keep_alive(&self) -> bool {
|
pub fn keep_alive(&self) -> bool {
|
||||||
self.keep_alive
|
self.flags.contains(MessageFlags::KEEPALIVE)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -83,10 +90,10 @@ impl HttpInnerMessage {
|
|||||||
self.params.clear();
|
self.params.clear();
|
||||||
self.addr = None;
|
self.addr = None;
|
||||||
self.info = None;
|
self.info = None;
|
||||||
self.query_loaded = false;
|
self.flags = MessageFlags::empty();
|
||||||
self.cookies = None;
|
self.cookies = None;
|
||||||
self.payload = None;
|
self.payload = None;
|
||||||
self.keep_alive = true;
|
self.prefix = 0;
|
||||||
self.resource = RouterResource::Notset;
|
self.resource = RouterResource::Notset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -115,12 +122,12 @@ impl HttpRequest<()> {
|
|||||||
payload,
|
payload,
|
||||||
params: Params::new(),
|
params: Params::new(),
|
||||||
query: Params::new(),
|
query: Params::new(),
|
||||||
query_loaded: false,
|
|
||||||
extensions: Extensions::new(),
|
extensions: Extensions::new(),
|
||||||
cookies: None,
|
cookies: None,
|
||||||
addr: None,
|
addr: None,
|
||||||
info: None,
|
info: None,
|
||||||
keep_alive: true,
|
prefix: 0,
|
||||||
|
flags: MessageFlags::empty(),
|
||||||
resource: RouterResource::Notset,
|
resource: RouterResource::Notset,
|
||||||
}),
|
}),
|
||||||
None,
|
None,
|
||||||
@ -234,12 +241,13 @@ impl<S> HttpRequest<S> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn prefix_len(&self) -> usize {
|
pub fn prefix_len(&self) -> u16 {
|
||||||
if let Some(router) = self.router() {
|
self.as_ref().prefix as u16
|
||||||
router.prefix().len()
|
}
|
||||||
} else {
|
|
||||||
0
|
#[doc(hidden)]
|
||||||
}
|
pub fn set_prefix_len(&mut self, len: u16) {
|
||||||
|
self.as_mut().prefix = len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read the Request Uri.
|
/// Read the Request Uri.
|
||||||
@ -367,14 +375,16 @@ impl<S> HttpRequest<S> {
|
|||||||
self.as_mut().addr = addr;
|
self.as_mut().addr = addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[deprecated(since = "0.6.0", note = "please use `Query<T>` extractor")]
|
||||||
/// Get a reference to the Params object.
|
/// Get a reference to the Params object.
|
||||||
/// Params is a container for url query parameters.
|
/// Params is a container for url query parameters.
|
||||||
pub fn query(&self) -> &Params {
|
pub fn query(&self) -> &Params {
|
||||||
if !self.as_ref().query_loaded {
|
if !self.as_ref().flags.contains(MessageFlags::QUERY) {
|
||||||
|
self.as_mut().flags.insert(MessageFlags::QUERY);
|
||||||
let params: &mut Params =
|
let params: &mut Params =
|
||||||
unsafe { mem::transmute(&mut self.as_mut().query) };
|
unsafe { mem::transmute(&mut self.as_mut().query) };
|
||||||
params.clear();
|
params.clear();
|
||||||
self.as_mut().query_loaded = true;
|
|
||||||
for (key, val) in form_urlencoded::parse(self.query_string().as_ref()) {
|
for (key, val) in form_urlencoded::parse(self.query_string().as_ref()) {
|
||||||
params.add(key, val);
|
params.add(key, val);
|
||||||
}
|
}
|
||||||
@ -443,7 +453,7 @@ impl<S> HttpRequest<S> {
|
|||||||
|
|
||||||
/// Checks if a connection should be kept alive.
|
/// Checks if a connection should be kept alive.
|
||||||
pub fn keep_alive(&self) -> bool {
|
pub fn keep_alive(&self) -> bool {
|
||||||
self.as_ref().keep_alive()
|
self.as_ref().flags.contains(MessageFlags::KEEPALIVE)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if request requires connection upgrade
|
/// Check if request requires connection upgrade
|
||||||
|
16
src/param.rs
16
src/param.rs
@ -42,6 +42,22 @@ impl<'a> Params<'a> {
|
|||||||
self.0.push((name.into(), value.into()));
|
self.0.push((name.into(), value.into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set<N, V>(&mut self, name: N, value: V)
|
||||||
|
where
|
||||||
|
N: Into<Cow<'a, str>>,
|
||||||
|
V: Into<Cow<'a, str>>,
|
||||||
|
{
|
||||||
|
let name = name.into();
|
||||||
|
let value = value.into();
|
||||||
|
for item in &mut self.0 {
|
||||||
|
if item.0 == name {
|
||||||
|
item.1 = value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.0.push((name, value));
|
||||||
|
}
|
||||||
|
|
||||||
/// Check if there are any matched patterns
|
/// Check if there are any matched patterns
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.0.is_empty()
|
self.0.is_empty()
|
||||||
|
@ -84,6 +84,7 @@ impl Router {
|
|||||||
for (idx, pattern) in self.0.patterns.iter().enumerate() {
|
for (idx, pattern) in self.0.patterns.iter().enumerate() {
|
||||||
if pattern.match_with_params(route_path, req.match_info_mut()) {
|
if pattern.match_with_params(route_path, req.match_info_mut()) {
|
||||||
req.set_resource(idx);
|
req.set_resource(idx);
|
||||||
|
req.set_prefix_len(self.0.prefix_len as u16);
|
||||||
return Some(idx);
|
return Some(idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
146
src/scope.rs
146
src/scope.rs
@ -14,6 +14,7 @@ use middleware::{Finished as MiddlewareFinished, Middleware,
|
|||||||
use resource::ResourceHandler;
|
use resource::ResourceHandler;
|
||||||
use router::Resource;
|
use router::Resource;
|
||||||
|
|
||||||
|
type Route<S> = UnsafeCell<Box<RouteHandler<S>>>;
|
||||||
type ScopeResources<S> = Rc<Vec<(Resource, Rc<UnsafeCell<ResourceHandler<S>>>)>>;
|
type ScopeResources<S> = Rc<Vec<(Resource, Rc<UnsafeCell<ResourceHandler<S>>>)>>;
|
||||||
|
|
||||||
/// Resources scope
|
/// Resources scope
|
||||||
@ -42,7 +43,7 @@ type ScopeResources<S> = Rc<Vec<(Resource, Rc<UnsafeCell<ResourceHandler<S>>>)>>
|
|||||||
/// * /app/path3 - `HEAD` requests
|
/// * /app/path3 - `HEAD` requests
|
||||||
///
|
///
|
||||||
pub struct Scope<S: 'static> {
|
pub struct Scope<S: 'static> {
|
||||||
handler: Option<UnsafeCell<Box<RouteHandler<S>>>>,
|
nested: Vec<(String, Route<S>)>,
|
||||||
middlewares: Rc<Vec<Box<Middleware<S>>>>,
|
middlewares: Rc<Vec<Box<Middleware<S>>>>,
|
||||||
default: Rc<UnsafeCell<ResourceHandler<S>>>,
|
default: Rc<UnsafeCell<ResourceHandler<S>>>,
|
||||||
resources: ScopeResources<S>,
|
resources: ScopeResources<S>,
|
||||||
@ -57,17 +58,14 @@ impl<S: 'static> Default for Scope<S> {
|
|||||||
impl<S: 'static> Scope<S> {
|
impl<S: 'static> Scope<S> {
|
||||||
pub fn new() -> Scope<S> {
|
pub fn new() -> Scope<S> {
|
||||||
Scope {
|
Scope {
|
||||||
handler: None,
|
nested: Vec::new(),
|
||||||
resources: Rc::new(Vec::new()),
|
resources: Rc::new(Vec::new()),
|
||||||
middlewares: Rc::new(Vec::new()),
|
middlewares: Rc::new(Vec::new()),
|
||||||
default: Rc::new(UnsafeCell::new(ResourceHandler::default_not_found())),
|
default: Rc::new(UnsafeCell::new(ResourceHandler::default_not_found())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create scope with new state.
|
/// Create nested scope with new state.
|
||||||
///
|
|
||||||
/// Scope can have only one nested scope with new state. Every call
|
|
||||||
/// destroys previously created scope with state.
|
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # extern crate actix_web;
|
/// # extern crate actix_web;
|
||||||
@ -82,28 +80,78 @@ impl<S: 'static> Scope<S> {
|
|||||||
/// fn main() {
|
/// fn main() {
|
||||||
/// let app = App::new()
|
/// let app = App::new()
|
||||||
/// .scope("/app", |scope| {
|
/// .scope("/app", |scope| {
|
||||||
/// scope.with_state(AppState, |scope| {
|
/// scope.with_state("/state2", AppState, |scope| {
|
||||||
/// scope.resource("/test1", |r| r.f(index))
|
/// scope.resource("/test1", |r| r.f(index))
|
||||||
/// })
|
/// })
|
||||||
/// });
|
/// });
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn with_state<F, T: 'static>(mut self, state: T, f: F) -> Scope<S>
|
pub fn with_state<F, T: 'static>(mut self, path: &str, state: T, f: F) -> Scope<S>
|
||||||
where
|
where
|
||||||
F: FnOnce(Scope<T>) -> Scope<T>,
|
F: FnOnce(Scope<T>) -> Scope<T>,
|
||||||
{
|
{
|
||||||
let scope = Scope {
|
let scope = Scope {
|
||||||
handler: None,
|
nested: Vec::new(),
|
||||||
resources: Rc::new(Vec::new()),
|
resources: Rc::new(Vec::new()),
|
||||||
middlewares: Rc::new(Vec::new()),
|
middlewares: Rc::new(Vec::new()),
|
||||||
default: Rc::new(UnsafeCell::new(ResourceHandler::default_not_found())),
|
default: Rc::new(UnsafeCell::new(ResourceHandler::default_not_found())),
|
||||||
};
|
};
|
||||||
let scope = f(scope);
|
let scope = f(scope);
|
||||||
|
|
||||||
self.handler = Some(UnsafeCell::new(Box::new(Wrapper {
|
let mut path = path.trim().trim_right_matches('/').to_owned();
|
||||||
|
if !path.is_empty() && !path.starts_with('/') {
|
||||||
|
path.insert(0, '/')
|
||||||
|
}
|
||||||
|
|
||||||
|
let handler = UnsafeCell::new(Box::new(Wrapper {
|
||||||
scope,
|
scope,
|
||||||
state: Rc::new(state),
|
state: Rc::new(state),
|
||||||
})));
|
}));
|
||||||
|
self.nested.push((path, handler));
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create nested scope.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # extern crate actix_web;
|
||||||
|
/// use actix_web::{App, HttpRequest};
|
||||||
|
///
|
||||||
|
/// struct AppState;
|
||||||
|
///
|
||||||
|
/// fn index(req: HttpRequest<AppState>) -> &'static str {
|
||||||
|
/// "Welcome!"
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn main() {
|
||||||
|
/// let app = App::with_state(AppState)
|
||||||
|
/// .scope("/app", |scope| {
|
||||||
|
/// scope.nested("/v1", |scope| {
|
||||||
|
/// scope.resource("/test1", |r| r.f(index))
|
||||||
|
/// })
|
||||||
|
/// });
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub fn nested<F>(mut self, path: &str, f: F) -> Scope<S>
|
||||||
|
where
|
||||||
|
F: FnOnce(Scope<S>) -> Scope<S>,
|
||||||
|
{
|
||||||
|
let scope = Scope {
|
||||||
|
nested: Vec::new(),
|
||||||
|
resources: Rc::new(Vec::new()),
|
||||||
|
middlewares: Rc::new(Vec::new()),
|
||||||
|
default: Rc::new(UnsafeCell::new(ResourceHandler::default_not_found())),
|
||||||
|
};
|
||||||
|
let scope = f(scope);
|
||||||
|
|
||||||
|
let mut path = path.trim().trim_right_matches('/').to_owned();
|
||||||
|
if !path.is_empty() && !path.starts_with('/') {
|
||||||
|
path.insert(0, '/')
|
||||||
|
}
|
||||||
|
|
||||||
|
self.nested
|
||||||
|
.push((path, UnsafeCell::new(Box::new(scope))));
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -249,24 +297,46 @@ impl<S: 'static> RouteHandler<S> for Scope<S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// nested scope
|
// nested scopes
|
||||||
if let Some(ref handler) = self.handler {
|
for &(ref prefix, ref handler) in &self.nested {
|
||||||
let hnd: &mut RouteHandler<_> = unsafe { (&mut *(handler.get())).as_mut() };
|
let len = req.prefix_len() as usize;
|
||||||
hnd.handle(req)
|
let m = {
|
||||||
} else {
|
let path = &req.path()[len..];
|
||||||
// default handler
|
path.starts_with(prefix)
|
||||||
let default = unsafe { &mut *self.default.as_ref().get() };
|
&& (path.len() == prefix.len()
|
||||||
if self.middlewares.is_empty() {
|
|| path.split_at(prefix.len()).1.starts_with('/'))
|
||||||
default.handle(req, None)
|
};
|
||||||
} else {
|
|
||||||
Reply::async(Compose::new(
|
if m {
|
||||||
req,
|
let prefix_len = len + prefix.len();
|
||||||
Rc::clone(&self.middlewares),
|
let path: &'static str =
|
||||||
Rc::clone(&self.default),
|
unsafe { &*(&req.path()[prefix_len..] as *const _) };
|
||||||
None,
|
|
||||||
))
|
req.set_prefix_len(prefix_len as u16);
|
||||||
|
if path.is_empty() {
|
||||||
|
req.match_info_mut().set("tail", "/");
|
||||||
|
} else {
|
||||||
|
req.match_info_mut().set("tail", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
let hnd: &mut RouteHandler<_> =
|
||||||
|
unsafe { (&mut *(handler.get())).as_mut() };
|
||||||
|
return hnd.handle(req);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// default handler
|
||||||
|
let default = unsafe { &mut *self.default.as_ref().get() };
|
||||||
|
if self.middlewares.is_empty() {
|
||||||
|
default.handle(req, None)
|
||||||
|
} else {
|
||||||
|
Reply::async(Compose::new(
|
||||||
|
req,
|
||||||
|
Rc::clone(&self.middlewares),
|
||||||
|
Rc::clone(&self.default),
|
||||||
|
None,
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -646,13 +716,31 @@ mod tests {
|
|||||||
|
|
||||||
let mut app = App::new()
|
let mut app = App::new()
|
||||||
.scope("/app", |scope| {
|
.scope("/app", |scope| {
|
||||||
scope.with_state(State, |scope| {
|
scope.with_state("/t1", State, |scope| {
|
||||||
scope.resource("/path1", |r| r.f(|_| HttpResponse::Created()))
|
scope.resource("/path1", |r| r.f(|_| HttpResponse::Created()))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.finish();
|
.finish();
|
||||||
|
|
||||||
let req = TestRequest::with_uri("/app/path1").finish();
|
let req = TestRequest::with_uri("/app/t1/path1").finish();
|
||||||
|
let resp = app.run(req);
|
||||||
|
assert_eq!(
|
||||||
|
resp.as_response().unwrap().status(),
|
||||||
|
StatusCode::CREATED
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_nested_scope() {
|
||||||
|
let mut app = App::new()
|
||||||
|
.scope("/app", |scope| {
|
||||||
|
scope.nested("/t1", |scope| {
|
||||||
|
scope.resource("/path1", |r| r.f(|_| HttpResponse::Created()))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.finish();
|
||||||
|
|
||||||
|
let req = TestRequest::with_uri("/app/t1/path1").finish();
|
||||||
let resp = app.run(req);
|
let resp = app.run(req);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
resp.as_response().unwrap().status(),
|
resp.as_response().unwrap().status(),
|
||||||
|
@ -9,6 +9,7 @@ use super::settings::WorkerSettings;
|
|||||||
use error::ParseError;
|
use error::ParseError;
|
||||||
use http::header::{HeaderName, HeaderValue};
|
use http::header::{HeaderName, HeaderValue};
|
||||||
use http::{header, HttpTryFrom, Method, Uri, Version};
|
use http::{header, HttpTryFrom, Method, Uri, Version};
|
||||||
|
use httprequest::MessageFlags;
|
||||||
use uri::Url;
|
use uri::Url;
|
||||||
|
|
||||||
const MAX_BUFFER_SIZE: usize = 131_072;
|
const MAX_BUFFER_SIZE: usize = 131_072;
|
||||||
@ -128,7 +129,9 @@ impl H1Decoder {
|
|||||||
let msg = settings.get_http_message();
|
let msg = settings.get_http_message();
|
||||||
{
|
{
|
||||||
let msg_mut = msg.get_mut();
|
let msg_mut = msg.get_mut();
|
||||||
msg_mut.keep_alive = version != Version::HTTP_10;
|
msg_mut
|
||||||
|
.flags
|
||||||
|
.set(MessageFlags::KEEPALIVE, version != Version::HTTP_10);
|
||||||
|
|
||||||
for header in headers[..headers_len].iter() {
|
for header in headers[..headers_len].iter() {
|
||||||
if let Ok(name) = HeaderName::from_bytes(header.name.as_bytes()) {
|
if let Ok(name) = HeaderName::from_bytes(header.name.as_bytes()) {
|
||||||
@ -165,7 +168,7 @@ impl H1Decoder {
|
|||||||
}
|
}
|
||||||
// connection keep-alive state
|
// connection keep-alive state
|
||||||
header::CONNECTION => {
|
header::CONNECTION => {
|
||||||
msg_mut.keep_alive = if let Ok(conn) = value.to_str() {
|
let ka = if let Ok(conn) = value.to_str() {
|
||||||
if version == Version::HTTP_10
|
if version == Version::HTTP_10
|
||||||
&& conn.contains("keep-alive")
|
&& conn.contains("keep-alive")
|
||||||
{
|
{
|
||||||
@ -178,6 +181,7 @@ impl H1Decoder {
|
|||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
};
|
};
|
||||||
|
msg_mut.flags.set(MessageFlags::KEEPALIVE, ka);
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
#![allow(deprecated)]
|
||||||
extern crate actix;
|
extern crate actix;
|
||||||
extern crate actix_web;
|
extern crate actix_web;
|
||||||
extern crate bytes;
|
extern crate bytes;
|
||||||
|
Loading…
Reference in New Issue
Block a user