From 3edc515bacccb95ce47ea46ab8ad265d248b60c4 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Wed, 27 Mar 2019 10:38:01 -0700 Subject: [PATCH] refactor RequestHead/ResponseHead --- actix-http/src/encoding/encoder.rs | 6 +- actix-http/src/h1/client.rs | 2 +- actix-http/src/h1/codec.rs | 2 +- actix-http/src/h1/decoder.rs | 27 +-- actix-http/src/h1/encoder.rs | 18 +- actix-http/src/lib.rs | 2 +- actix-http/src/message.rs | 250 +++++++++++++++++----------- actix-http/src/response.rs | 6 +- actix-http/src/ws/client/service.rs | 2 +- actix-web-actors/src/ws.rs | 2 +- awc/src/request.rs | 2 +- src/lib.rs | 2 +- src/middleware/cors.rs | 2 +- 13 files changed, 191 insertions(+), 132 deletions(-) diff --git a/actix-http/src/encoding/encoder.rs b/actix-http/src/encoding/encoder.rs index af861b9d7..fcac3a427 100644 --- a/actix-http/src/encoding/encoder.rs +++ b/actix-http/src/encoding/encoder.rs @@ -12,7 +12,7 @@ use flate2::write::{GzEncoder, ZlibEncoder}; use crate::body::{Body, BodySize, MessageBody, ResponseBody}; use crate::http::header::{ContentEncoding, CONTENT_ENCODING}; use crate::http::{HeaderValue, HttpTryFrom, StatusCode}; -use crate::{Error, Head, ResponseHead}; +use crate::{Error, ResponseHead}; use super::Writer; @@ -56,7 +56,7 @@ impl Encoder { }) } else { update_head(encoding, head); - head.no_chunking = false; + head.no_chunking(false); ResponseBody::Body(Encoder { body: EncoderBody::Other(stream), encoder: ContentEncoder::encoder(encoding), @@ -72,7 +72,7 @@ impl Encoder { }) } else { update_head(encoding, head); - head.no_chunking = false; + head.no_chunking(false); ResponseBody::Body(Encoder { body: EncoderBody::Body(stream), encoder: ContentEncoder::encoder(encoding), diff --git a/actix-http/src/h1/client.rs b/actix-http/src/h1/client.rs index fbdc8bde1..6a50c0271 100644 --- a/actix-http/src/h1/client.rs +++ b/actix-http/src/h1/client.rs @@ -129,7 +129,7 @@ impl Decoder for ClientCodec { debug_assert!(!self.inner.payload.is_some(), "Payload decoder is set"); if let Some((req, payload)) = self.inner.decoder.decode(src)? { - if let Some(ctype) = req.ctype { + if let Some(ctype) = req.ctype() { // do not use peer's keep-alive self.inner.ctype = if ctype == ConnectionType::KeepAlive { self.inner.ctype diff --git a/actix-http/src/h1/codec.rs b/actix-http/src/h1/codec.rs index 9bb417091..ceb1027e5 100644 --- a/actix-http/src/h1/codec.rs +++ b/actix-http/src/h1/codec.rs @@ -154,7 +154,7 @@ impl Encoder for Codec { res.head_mut().version = self.version; // connection status - self.ctype = if let Some(ct) = res.head().ctype { + self.ctype = if let Some(ct) = res.head().ctype() { if ct == ConnectionType::KeepAlive { self.ctype } else { diff --git a/actix-http/src/h1/decoder.rs b/actix-http/src/h1/decoder.rs index a1b221c06..9b97713fb 100644 --- a/actix-http/src/h1/decoder.rs +++ b/actix-http/src/h1/decoder.rs @@ -158,7 +158,9 @@ pub(crate) trait MessageType: Sized { impl MessageType for Request { fn set_connection_type(&mut self, ctype: Option) { - self.head_mut().ctype = ctype; + if let Some(ctype) = ctype { + self.head_mut().set_connection_type(ctype); + } } fn headers_mut(&mut self) -> &mut HeaderMap { @@ -228,7 +230,9 @@ impl MessageType for Request { impl MessageType for ResponseHead { fn set_connection_type(&mut self, ctype: Option) { - self.ctype = ctype; + if let Some(ctype) = ctype { + ResponseHead::set_connection_type(self, ctype); + } } fn headers_mut(&mut self) -> &mut HeaderMap { @@ -814,7 +818,7 @@ mod tests { ); let req = parse_ready!(&mut buf); - assert_eq!(req.head().ctype, Some(ConnectionType::Close)); + assert_eq!(req.head().connection_type(), ConnectionType::Close); let mut buf = BytesMut::from( "GET /test HTTP/1.1\r\n\ @@ -822,7 +826,7 @@ mod tests { ); let req = parse_ready!(&mut buf); - assert_eq!(req.head().ctype, Some(ConnectionType::Close)); + assert_eq!(req.head().connection_type(), ConnectionType::Close); } #[test] @@ -834,7 +838,7 @@ mod tests { let req = parse_ready!(&mut buf); - assert_eq!(req.head().ctype, Some(ConnectionType::Close)); + assert_eq!(req.head().connection_type(), ConnectionType::Close); } #[test] @@ -845,7 +849,7 @@ mod tests { ); let req = parse_ready!(&mut buf); - assert_eq!(req.head().ctype, Some(ConnectionType::KeepAlive)); + assert_eq!(req.head().connection_type(), ConnectionType::KeepAlive); let mut buf = BytesMut::from( "GET /test HTTP/1.0\r\n\ @@ -853,7 +857,7 @@ mod tests { ); let req = parse_ready!(&mut buf); - assert_eq!(req.head().ctype, Some(ConnectionType::KeepAlive)); + assert_eq!(req.head().connection_type(), ConnectionType::KeepAlive); } #[test] @@ -864,7 +868,7 @@ mod tests { ); let req = parse_ready!(&mut buf); - assert_eq!(req.head().ctype, Some(ConnectionType::KeepAlive)); + assert_eq!(req.head().connection_type(), ConnectionType::KeepAlive); } #[test] @@ -886,7 +890,6 @@ mod tests { ); let req = parse_ready!(&mut buf); - assert_eq!(req.head().ctype, None); assert_eq!(req.head().connection_type(), ConnectionType::KeepAlive); } @@ -900,7 +903,7 @@ mod tests { let req = parse_ready!(&mut buf); assert!(req.upgrade()); - assert_eq!(req.head().ctype, Some(ConnectionType::Upgrade)); + assert_eq!(req.head().connection_type(), ConnectionType::Upgrade); let mut buf = BytesMut::from( "GET /test HTTP/1.1\r\n\ @@ -910,7 +913,7 @@ mod tests { let req = parse_ready!(&mut buf); assert!(req.upgrade()); - assert_eq!(req.head().ctype, Some(ConnectionType::Upgrade)); + assert_eq!(req.head().connection_type(), ConnectionType::Upgrade); } #[test] @@ -1008,7 +1011,7 @@ mod tests { ); let mut reader = MessageDecoder::::default(); let (req, pl) = reader.decode(&mut buf).unwrap().unwrap(); - assert_eq!(req.head().ctype, Some(ConnectionType::Upgrade)); + assert_eq!(req.head().connection_type(), ConnectionType::Upgrade); assert!(req.upgrade()); assert!(pl.is_unhandled()); } diff --git a/actix-http/src/h1/encoder.rs b/actix-http/src/h1/encoder.rs index dbf6d440f..382ebe5f1 100644 --- a/actix-http/src/h1/encoder.rs +++ b/actix-http/src/h1/encoder.rs @@ -15,7 +15,7 @@ use crate::body::BodySize; use crate::config::ServiceConfig; use crate::header::ContentEncoding; use crate::helpers; -use crate::message::{ConnectionType, RequestHead, ResponseHead}; +use crate::message::{ConnectionType, Head, RequestHead, ResponseHead}; use crate::request::Request; use crate::response::Response; @@ -41,7 +41,7 @@ impl Default for MessageEncoder { pub(crate) trait MessageType: Sized { fn status(&self) -> Option; - fn connection_type(&self) -> Option; + // fn connection_type(&self) -> Option; fn headers(&self) -> &HeaderMap; @@ -168,12 +168,12 @@ impl MessageType for Response<()> { } fn chunked(&self) -> bool { - !self.head().no_chunking + self.head().chunked() } - fn connection_type(&self) -> Option { - self.head().ctype - } + //fn connection_type(&self) -> Option { + // self.head().ctype + //} fn headers(&self) -> &HeaderMap { &self.head().headers @@ -196,12 +196,8 @@ impl MessageType for RequestHead { None } - fn connection_type(&self) -> Option { - self.ctype - } - fn chunked(&self) -> bool { - !self.no_chunking + self.chunked() } fn headers(&self) -> &HeaderMap { diff --git a/actix-http/src/lib.rs b/actix-http/src/lib.rs index edc06c2a6..565fe4455 100644 --- a/actix-http/src/lib.rs +++ b/actix-http/src/lib.rs @@ -35,7 +35,7 @@ pub use self::config::{KeepAlive, ServiceConfig}; pub use self::error::{Error, ResponseError, Result}; pub use self::extensions::Extensions; pub use self::httpmessage::HttpMessage; -pub use self::message::{Head, Message, RequestHead, ResponseHead}; +pub use self::message::{Message, RequestHead, ResponseHead}; pub use self::payload::{Payload, PayloadStream}; pub use self::request::Request; pub use self::response::{Response, ResponseBuilder}; diff --git a/actix-http/src/message.rs b/actix-http/src/message.rs index 4e46093f6..a1e9e3c60 100644 --- a/actix-http/src/message.rs +++ b/actix-http/src/message.rs @@ -2,6 +2,8 @@ use std::cell::{Ref, RefCell, RefMut}; use std::collections::VecDeque; use std::rc::Rc; +use bitflags::bitflags; + use crate::extensions::Extensions; use crate::http::{header, HeaderMap, Method, StatusCode, Uri, Version}; @@ -16,39 +18,22 @@ pub enum ConnectionType { Upgrade, } +bitflags! { + pub(crate) struct Flags: u8 { + const CLOSE = 0b0000_0001; + const KEEP_ALIVE = 0b0000_0010; + const UPGRADE = 0b0000_0100; + const NO_CHUNKING = 0b0000_1000; + const ENC_BR = 0b0001_0000; + const ENC_DEFLATE = 0b0010_0000; + const ENC_GZIP = 0b0100_0000; + } +} + #[doc(hidden)] pub trait Head: Default + 'static { fn clear(&mut self); - /// Read the message headers. - fn headers(&self) -> &HeaderMap; - - /// Mutable reference to the message headers. - fn headers_mut(&mut self) -> &mut HeaderMap; - - /// Connection type - fn connection_type(&self) -> ConnectionType; - - /// Set connection type of the message - fn set_connection_type(&mut self, ctype: ConnectionType); - - fn upgrade(&self) -> bool { - if let Some(hdr) = self.headers().get(header::CONNECTION) { - if let Ok(s) = hdr.to_str() { - s.to_ascii_lowercase().contains("upgrade") - } else { - false - } - } else { - false - } - } - - /// Check if keep-alive is enabled - fn keep_alive(&self) -> bool { - self.connection_type() == ConnectionType::KeepAlive - } - fn pool() -> &'static MessagePool; } @@ -58,9 +43,8 @@ pub struct RequestHead { pub method: Method, pub version: Version, pub headers: HeaderMap, - pub ctype: Option, - pub no_chunking: bool, pub extensions: RefCell, + flags: Flags, } impl Default for RequestHead { @@ -70,8 +54,7 @@ impl Default for RequestHead { method: Method::default(), version: Version::HTTP_11, headers: HeaderMap::with_capacity(16), - ctype: None, - no_chunking: false, + flags: Flags::empty(), extensions: RefCell::new(Extensions::new()), } } @@ -79,45 +62,11 @@ impl Default for RequestHead { impl Head for RequestHead { fn clear(&mut self) { - self.ctype = None; + self.flags = Flags::empty(); self.headers.clear(); self.extensions.borrow_mut().clear(); } - fn headers(&self) -> &HeaderMap { - &self.headers - } - - fn headers_mut(&mut self) -> &mut HeaderMap { - &mut self.headers - } - - fn set_connection_type(&mut self, ctype: ConnectionType) { - self.ctype = Some(ctype) - } - - fn connection_type(&self) -> ConnectionType { - if let Some(ct) = self.ctype { - ct - } else if self.version < Version::HTTP_11 { - ConnectionType::Close - } else { - ConnectionType::KeepAlive - } - } - - fn upgrade(&self) -> bool { - if let Some(hdr) = self.headers().get(header::CONNECTION) { - if let Ok(s) = hdr.to_str() { - s.to_ascii_lowercase().contains("upgrade") - } else { - false - } - } else { - false - } - } - fn pool() -> &'static MessagePool { REQUEST_POOL.with(|p| *p) } @@ -135,6 +84,70 @@ impl RequestHead { pub fn extensions_mut(&self) -> RefMut { self.extensions.borrow_mut() } + + /// Read the message headers. + pub fn headers(&self) -> &HeaderMap { + &self.headers + } + + /// Mutable reference to the message headers. + pub fn headers_mut(&mut self) -> &mut HeaderMap { + &mut self.headers + } + + #[inline] + /// Set connection type of the message + pub fn set_connection_type(&mut self, ctype: ConnectionType) { + match ctype { + ConnectionType::Close => self.flags.insert(Flags::CLOSE), + ConnectionType::KeepAlive => self.flags.insert(Flags::KEEP_ALIVE), + ConnectionType::Upgrade => self.flags.insert(Flags::UPGRADE), + } + } + + #[inline] + /// Connection type + pub fn connection_type(&self) -> ConnectionType { + if self.flags.contains(Flags::CLOSE) { + ConnectionType::Close + } else if self.flags.contains(Flags::KEEP_ALIVE) { + ConnectionType::KeepAlive + } else if self.flags.contains(Flags::UPGRADE) { + ConnectionType::Upgrade + } else if self.version < Version::HTTP_11 { + ConnectionType::Close + } else { + ConnectionType::KeepAlive + } + } + + /// Connection upgrade status + pub fn upgrade(&self) -> bool { + if let Some(hdr) = self.headers().get(header::CONNECTION) { + if let Ok(s) = hdr.to_str() { + s.to_ascii_lowercase().contains("upgrade") + } else { + false + } + } else { + false + } + } + + #[inline] + /// Get response body chunking state + pub fn chunked(&self) -> bool { + !self.flags.contains(Flags::NO_CHUNKING) + } + + #[inline] + pub fn no_chunking(&mut self, val: bool) { + if val { + self.flags.insert(Flags::NO_CHUNKING); + } else { + self.flags.remove(Flags::NO_CHUNKING); + } + } } #[derive(Debug)] @@ -143,9 +156,8 @@ pub struct ResponseHead { pub status: StatusCode, pub headers: HeaderMap, pub reason: Option<&'static str>, - pub no_chunking: bool, - pub(crate) ctype: Option, pub(crate) extensions: RefCell, + flags: Flags, } impl Default for ResponseHead { @@ -155,13 +167,24 @@ impl Default for ResponseHead { status: StatusCode::OK, headers: HeaderMap::with_capacity(16), reason: None, - no_chunking: false, - ctype: None, + flags: Flags::empty(), extensions: RefCell::new(Extensions::new()), } } } +impl Head for ResponseHead { + fn clear(&mut self) { + self.reason = None; + self.flags = Flags::empty(); + self.headers.clear(); + } + + fn pool() -> &'static MessagePool { + RESPONSE_POOL.with(|p| *p) + } +} + impl ResponseHead { /// Message extensions #[inline] @@ -174,31 +197,37 @@ impl ResponseHead { pub fn extensions_mut(&self) -> RefMut { self.extensions.borrow_mut() } -} -impl Head for ResponseHead { - fn clear(&mut self) { - self.ctype = None; - self.reason = None; - self.no_chunking = false; - self.headers.clear(); - } - - fn headers(&self) -> &HeaderMap { + #[inline] + /// Read the message headers. + pub fn headers(&self) -> &HeaderMap { &self.headers } - fn headers_mut(&mut self) -> &mut HeaderMap { + #[inline] + /// Mutable reference to the message headers. + pub fn headers_mut(&mut self) -> &mut HeaderMap { &mut self.headers } - fn set_connection_type(&mut self, ctype: ConnectionType) { - self.ctype = Some(ctype) + #[inline] + /// Set connection type of the message + pub fn set_connection_type(&mut self, ctype: ConnectionType) { + match ctype { + ConnectionType::Close => self.flags.insert(Flags::CLOSE), + ConnectionType::KeepAlive => self.flags.insert(Flags::KEEP_ALIVE), + ConnectionType::Upgrade => self.flags.insert(Flags::UPGRADE), + } } - fn connection_type(&self) -> ConnectionType { - if let Some(ct) = self.ctype { - ct + #[inline] + pub fn connection_type(&self) -> ConnectionType { + if self.flags.contains(Flags::CLOSE) { + ConnectionType::Close + } else if self.flags.contains(Flags::KEEP_ALIVE) { + ConnectionType::KeepAlive + } else if self.flags.contains(Flags::UPGRADE) { + ConnectionType::Upgrade } else if self.version < Version::HTTP_11 { ConnectionType::Close } else { @@ -206,16 +235,18 @@ impl Head for ResponseHead { } } - fn upgrade(&self) -> bool { + #[inline] + /// Check if keep-alive is enabled + pub fn keep_alive(&self) -> bool { + self.connection_type() == ConnectionType::KeepAlive + } + + #[inline] + /// Check upgrade status of this message + pub fn upgrade(&self) -> bool { self.connection_type() == ConnectionType::Upgrade } - fn pool() -> &'static MessagePool { - RESPONSE_POOL.with(|p| *p) - } -} - -impl ResponseHead { /// Get custom reason for the response #[inline] pub fn reason(&self) -> &str { @@ -227,6 +258,35 @@ impl ResponseHead { .unwrap_or("") } } + + #[inline] + pub(crate) fn ctype(&self) -> Option { + if self.flags.contains(Flags::CLOSE) { + Some(ConnectionType::Close) + } else if self.flags.contains(Flags::KEEP_ALIVE) { + Some(ConnectionType::KeepAlive) + } else if self.flags.contains(Flags::UPGRADE) { + Some(ConnectionType::Upgrade) + } else { + None + } + } + + #[inline] + /// Get response body chunking state + pub fn chunked(&self) -> bool { + !self.flags.contains(Flags::NO_CHUNKING) + } + + #[inline] + /// Set no chunking for payload + pub fn no_chunking(&mut self, val: bool) { + if val { + self.flags.insert(Flags::NO_CHUNKING); + } else { + self.flags.remove(Flags::NO_CHUNKING); + } + } } pub struct Message { diff --git a/actix-http/src/response.rs b/actix-http/src/response.rs index 31c0010ab..3b33e1f91 100644 --- a/actix-http/src/response.rs +++ b/actix-http/src/response.rs @@ -15,7 +15,7 @@ use serde_json; use crate::body::{Body, BodyStream, MessageBody, ResponseBody}; use crate::error::Error; use crate::header::{Header, IntoHeaderValue}; -use crate::message::{ConnectionType, Head, Message, ResponseHead}; +use crate::message::{ConnectionType, Message, ResponseHead}; /// An HTTP Response pub struct Response { @@ -462,7 +462,7 @@ impl ResponseBuilder { #[inline] pub fn no_chunking(&mut self) -> &mut Self { if let Some(parts) = parts(&mut self.head, &self.err) { - parts.no_chunking = true; + parts.no_chunking(true); } self } @@ -740,7 +740,7 @@ impl<'a> From<&'a ResponseHead> for ResponseBuilder { msg.status = head.status; msg.reason = head.reason; msg.headers = head.headers.clone(); - msg.no_chunking = head.no_chunking; + msg.no_chunking(!head.chunked()); ResponseBuilder { head: Some(msg), diff --git a/actix-http/src/ws/client/service.rs b/actix-http/src/ws/client/service.rs index cb3fb6f39..bc86e516a 100644 --- a/actix-http/src/ws/client/service.rs +++ b/actix-http/src/ws/client/service.rs @@ -15,7 +15,7 @@ use sha1::Sha1; use crate::body::BodySize; use crate::h1; -use crate::message::{ConnectionType, Head, ResponseHead}; +use crate::message::{ConnectionType, ResponseHead}; use crate::ws::Codec; use super::{ClientError, Connect, Protocol}; diff --git a/actix-web-actors/src/ws.rs b/actix-web-actors/src/ws.rs index cef5080c6..436011888 100644 --- a/actix-web-actors/src/ws.rs +++ b/actix-web-actors/src/ws.rs @@ -17,7 +17,7 @@ pub use actix_http::ws::{ CloseCode, CloseReason, Frame, HandshakeError, Message, ProtocolError, }; -use actix_web::dev::{Head, HttpResponseBuilder}; +use actix_web::dev::HttpResponseBuilder; use actix_web::error::{Error, ErrorInternalServerError, PayloadError}; use actix_web::http::{header, Method, StatusCode}; use actix_web::{HttpMessage, HttpRequest, HttpResponse}; diff --git a/awc/src/request.rs b/awc/src/request.rs index d25ecc421..7beb737e1 100644 --- a/awc/src/request.rs +++ b/awc/src/request.rs @@ -19,7 +19,7 @@ use actix_http::http::{ uri, ConnectionType, Error as HttpError, HeaderName, HeaderValue, HttpTryFrom, Method, Uri, Version, }; -use actix_http::{Error, Head, Payload, RequestHead}; +use actix_http::{Error, Payload, RequestHead}; use crate::response::ClientResponse; use crate::{Connect, PayloadError}; diff --git a/src/lib.rs b/src/lib.rs index 54709b47b..5b0ce7841 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -145,7 +145,7 @@ pub mod dev { pub use actix_http::body::{Body, BodySize, MessageBody, ResponseBody}; pub use actix_http::ResponseBuilder as HttpResponseBuilder; pub use actix_http::{ - Extensions, Head, Payload, PayloadStream, RequestHead, ResponseHead, + Extensions, Payload, PayloadStream, RequestHead, ResponseHead, }; pub use actix_router::{Path, ResourceDef, ResourcePath, Url}; pub use actix_server::Server; diff --git a/src/middleware/cors.rs b/src/middleware/cors.rs index b6acf4299..2ece543d2 100644 --- a/src/middleware/cors.rs +++ b/src/middleware/cors.rs @@ -46,7 +46,7 @@ use derive_more::Display; use futures::future::{ok, Either, Future, FutureResult}; use futures::Poll; -use crate::dev::{Head, RequestHead}; +use crate::dev::RequestHead; use crate::error::{ResponseError, Result}; use crate::http::header::{self, HeaderName, HeaderValue}; use crate::http::{self, HttpTryFrom, Method, StatusCode, Uri};