Various fixes in actix-http crate

This commit is contained in:
Igor Aleksanov 2021-06-22 19:49:39 +03:00
parent 282a66f327
commit 4cc8eafd3e
23 changed files with 100 additions and 46 deletions

View File

@ -78,12 +78,12 @@ impl HeaderIndex {
// test cases taken from: // test cases taken from:
// https://github.com/seanmonstar/httparse/blob/master/benches/parse.rs // https://github.com/seanmonstar/httparse/blob/master/benches/parse.rs
const REQ_SHORT: &'static [u8] = b"\ const REQ_SHORT: &[u8] = b"\
GET / HTTP/1.0\r\n\ GET / HTTP/1.0\r\n\
Host: example.com\r\n\ Host: example.com\r\n\
Cookie: session=60; user_id=1\r\n\r\n"; Cookie: session=60; user_id=1\r\n\r\n";
const REQ: &'static [u8] = b"\ const REQ: &[u8] = b"\
GET /wp-content/uploads/2010/03/hello-kitty-darth-vader-pink.jpg HTTP/1.1\r\n\ GET /wp-content/uploads/2010/03/hello-kitty-darth-vader-pink.jpg HTTP/1.1\r\n\
Host: www.kittyhell.com\r\n\ Host: www.kittyhell.com\r\n\
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; ja-JP-mac; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 Pathtraq/0.9\r\n\ User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; ja-JP-mac; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 Pathtraq/0.9\r\n\
@ -119,6 +119,8 @@ mod _original {
use std::mem::MaybeUninit; use std::mem::MaybeUninit;
pub fn parse_headers(src: &mut BytesMut) -> usize { pub fn parse_headers(src: &mut BytesMut) -> usize {
#![allow(clippy::uninit_assumed_init)]
let mut headers: [HeaderIndex; MAX_HEADERS] = let mut headers: [HeaderIndex; MAX_HEADERS] =
unsafe { MaybeUninit::uninit().assume_init() }; unsafe { MaybeUninit::uninit().assume_init() };

View File

@ -32,6 +32,7 @@ pub enum AnyBody {
impl AnyBody { impl AnyBody {
/// Create body from slice (copy) /// Create body from slice (copy)
#[must_use]
pub fn from_slice(s: &[u8]) -> Self { pub fn from_slice(s: &[u8]) -> Self {
Self::Bytes(Bytes::copy_from_slice(s)) Self::Bytes(Bytes::copy_from_slice(s))
} }

View File

@ -36,6 +36,7 @@ where
<S::Service as Service<Request>>::Future: 'static, <S::Service as Service<Request>>::Future: 'static,
{ {
/// Create instance of `ServiceConfigBuilder` /// Create instance of `ServiceConfigBuilder`
#[must_use]
pub fn new() -> Self { pub fn new() -> Self {
HttpServiceBuilder { HttpServiceBuilder {
keep_alive: KeepAlive::Timeout(5), keep_alive: KeepAlive::Timeout(5),

View File

@ -64,6 +64,7 @@ pub struct Connector<T> {
impl Connector<()> { impl Connector<()> {
#[allow(clippy::new_ret_no_self, clippy::let_unit_value)] #[allow(clippy::new_ret_no_self, clippy::let_unit_value)]
#[must_use]
pub fn new() -> Connector< pub fn new() -> Connector<
impl Service< impl Service<
TcpConnect<Uri>, TcpConnect<Uri>,
@ -85,7 +86,7 @@ impl Connector<()> {
use bytes::{BufMut, BytesMut}; use bytes::{BufMut, BytesMut};
let mut alpn = BytesMut::with_capacity(20); let mut alpn = BytesMut::with_capacity(20);
for proto in protocols.iter() { for proto in &protocols {
alpn.put_u8(proto.len() as u8); alpn.put_u8(proto.len() as u8);
alpn.put(proto.as_slice()); alpn.put(proto.as_slice());
} }
@ -290,8 +291,7 @@ where
let h2 = sock let h2 = sock
.ssl() .ssl()
.selected_alpn_protocol() .selected_alpn_protocol()
.map(|protos| protos.windows(2).any(|w| w == H2)) .map_or(false, |protos| protos.windows(2).any(|w| w == H2));
.unwrap_or(false);
if h2 { if h2 {
(Box::new(sock), Protocol::Http2) (Box::new(sock), Protocol::Http2)
} else { } else {
@ -325,8 +325,7 @@ where
.get_ref() .get_ref()
.1 .1
.get_alpn_protocol() .get_alpn_protocol()
.map(|protos| protos.windows(2).any(|w| w == H2)) .map_or(false, |protos| protos.windows(2).any(|w| w == H2));
.unwrap_or(false);
if h2 { if h2 {
(Box::new(sock), Protocol::Http2) (Box::new(sock), Protocol::Http2)
} else { } else {

View File

@ -168,14 +168,13 @@ where
if let Err(e) = send.send_data(bytes, false) { if let Err(e) = send.send_data(bytes, false) {
return Err(e.into()); return Err(e.into());
} else {
if !b.is_empty() {
send.reserve_capacity(b.len());
} else {
buf = None;
}
continue;
} }
if !b.is_empty() {
send.reserve_capacity(b.len());
} else {
buf = None;
}
continue;
} }
Some(Err(e)) => return Err(e.into()), Some(Err(e)) => return Err(e.into()),
} }

View File

@ -68,6 +68,7 @@ impl Default for ServiceConfig {
impl ServiceConfig { impl ServiceConfig {
/// Create instance of `ServiceConfig` /// Create instance of `ServiceConfig`
#[must_use]
pub fn new( pub fn new(
keep_alive: KeepAlive, keep_alive: KeepAlive,
client_timeout: u64, client_timeout: u64,
@ -99,30 +100,35 @@ impl ServiceConfig {
/// Returns true if connection is secure (HTTPS) /// Returns true if connection is secure (HTTPS)
#[inline] #[inline]
#[must_use]
pub fn secure(&self) -> bool { pub fn secure(&self) -> bool {
self.0.secure self.0.secure
} }
/// Returns the local address that this server is bound to. /// Returns the local address that this server is bound to.
#[inline] #[inline]
#[must_use]
pub fn local_addr(&self) -> Option<net::SocketAddr> { pub fn local_addr(&self) -> Option<net::SocketAddr> {
self.0.local_addr self.0.local_addr
} }
/// Keep alive duration if configured. /// Keep alive duration if configured.
#[inline] #[inline]
#[must_use]
pub fn keep_alive(&self) -> Option<Duration> { pub fn keep_alive(&self) -> Option<Duration> {
self.0.keep_alive self.0.keep_alive
} }
/// Return state of connection keep-alive functionality /// Return state of connection keep-alive functionality
#[inline] #[inline]
#[must_use]
pub fn keep_alive_enabled(&self) -> bool { pub fn keep_alive_enabled(&self) -> bool {
self.0.ka_enabled self.0.ka_enabled
} }
/// Client timeout for first request. /// Client timeout for first request.
#[inline] #[inline]
#[must_use]
pub fn client_timer(&self) -> Option<Sleep> { pub fn client_timer(&self) -> Option<Sleep> {
let delay_time = self.0.client_timeout; let delay_time = self.0.client_timeout;
if delay_time != 0 { if delay_time != 0 {
@ -133,6 +139,7 @@ impl ServiceConfig {
} }
/// Client timeout for first request. /// Client timeout for first request.
#[must_use]
pub fn client_timer_expire(&self) -> Option<Instant> { pub fn client_timer_expire(&self) -> Option<Instant> {
let delay = self.0.client_timeout; let delay = self.0.client_timeout;
if delay != 0 { if delay != 0 {
@ -143,6 +150,7 @@ impl ServiceConfig {
} }
/// Client disconnect timer /// Client disconnect timer
#[must_use]
pub fn client_disconnect_timer(&self) -> Option<Instant> { pub fn client_disconnect_timer(&self) -> Option<Instant> {
let delay = self.0.client_disconnect; let delay = self.0.client_disconnect;
if delay != 0 { if delay != 0 {
@ -152,13 +160,15 @@ impl ServiceConfig {
} }
} }
#[inline]
/// Return keep-alive timer delay is configured. /// Return keep-alive timer delay is configured.
#[inline]
#[must_use]
pub fn keep_alive_timer(&self) -> Option<Sleep> { pub fn keep_alive_timer(&self) -> Option<Sleep> {
self.keep_alive().map(|ka| sleep_until(self.now() + ka)) self.keep_alive().map(|ka| sleep_until(self.now() + ka))
} }
/// Keep-alive expire time /// Keep-alive expire time
#[must_use]
pub fn keep_alive_expire(&self) -> Option<Instant> { pub fn keep_alive_expire(&self) -> Option<Instant> {
self.keep_alive().map(|ka| self.now() + ka) self.keep_alive().map(|ka| self.now() + ka)
} }
@ -365,11 +375,11 @@ mod tests {
let clone3 = service.clone(); let clone3 = service.clone();
drop(clone1); drop(clone1);
assert_eq!(false, notify_on_drop::is_dropped()); assert!(!notify_on_drop::is_dropped());
drop(clone2); drop(clone2);
assert_eq!(false, notify_on_drop::is_dropped()); assert!(!notify_on_drop::is_dropped());
drop(clone3); drop(clone3);
assert_eq!(false, notify_on_drop::is_dropped()); assert!(!notify_on_drop::is_dropped());
drop(service); drop(service);
assert!(notify_on_drop::is_dropped()); assert!(notify_on_drop::is_dropped());

View File

@ -125,7 +125,7 @@ impl fmt::Display for Error {
impl StdError for Error { impl StdError for Error {
fn source(&self) -> Option<&(dyn StdError + 'static)> { fn source(&self) -> Option<&(dyn StdError + 'static)> {
self.inner.cause.as_ref().map(|err| err.as_ref()) self.inner.cause.as_ref().map(Box::as_ref)
} }
} }

View File

@ -18,6 +18,7 @@ pub struct Extensions {
impl Extensions { impl Extensions {
/// Creates an empty `Extensions`. /// Creates an empty `Extensions`.
#[inline] #[inline]
#[must_use]
pub fn new() -> Extensions { pub fn new() -> Extensions {
Extensions { Extensions {
map: AHashMap::default(), map: AHashMap::default(),
@ -52,6 +53,7 @@ impl Extensions {
/// assert_eq!(map.insert(1u32), None); /// assert_eq!(map.insert(1u32), None);
/// assert!(map.contains::<u32>()); /// assert!(map.contains::<u32>());
/// ``` /// ```
#[must_use]
pub fn contains<T: 'static>(&self) -> bool { pub fn contains<T: 'static>(&self) -> bool {
self.map.contains_key(&TypeId::of::<T>()) self.map.contains_key(&TypeId::of::<T>())
} }
@ -64,6 +66,7 @@ impl Extensions {
/// map.insert(1u32); /// map.insert(1u32);
/// assert_eq!(map.get::<u32>(), Some(&1u32)); /// assert_eq!(map.get::<u32>(), Some(&1u32));
/// ``` /// ```
#[must_use]
pub fn get<T: 'static>(&self) -> Option<&T> { pub fn get<T: 'static>(&self) -> Option<&T> {
self.map self.map
.get(&TypeId::of::<T>()) .get(&TypeId::of::<T>())

View File

@ -53,6 +53,7 @@ impl ClientCodec {
/// Create HTTP/1 codec. /// Create HTTP/1 codec.
/// ///
/// `keepalive_enabled` how response `connection` header get generated. /// `keepalive_enabled` how response `connection` header get generated.
#[must_use]
pub fn new(config: ServiceConfig) -> Self { pub fn new(config: ServiceConfig) -> Self {
let flags = if config.keep_alive_enabled() { let flags = if config.keep_alive_enabled() {
Flags::KEEPALIVE_ENABLED Flags::KEEPALIVE_ENABLED
@ -74,16 +75,19 @@ impl ClientCodec {
} }
/// Check if request is upgrade /// Check if request is upgrade
#[must_use]
pub fn upgrade(&self) -> bool { pub fn upgrade(&self) -> bool {
self.inner.ctype == ConnectionType::Upgrade self.inner.ctype == ConnectionType::Upgrade
} }
/// Check if last response is keep-alive /// Check if last response is keep-alive
#[must_use]
pub fn keepalive(&self) -> bool { pub fn keepalive(&self) -> bool {
self.inner.ctype == ConnectionType::KeepAlive self.inner.ctype == ConnectionType::KeepAlive
} }
/// Check last request's message type /// Check last request's message type
#[must_use]
pub fn message_type(&self) -> MessageType { pub fn message_type(&self) -> MessageType {
if self.inner.flags.contains(Flags::STREAM) { if self.inner.flags.contains(Flags::STREAM) {
MessageType::Stream MessageType::Stream
@ -95,6 +99,7 @@ impl ClientCodec {
} }
/// Convert message codec to a payload codec /// Convert message codec to a payload codec
#[must_use]
pub fn into_payload_codec(self) -> ClientPayloadCodec { pub fn into_payload_codec(self) -> ClientPayloadCodec {
ClientPayloadCodec { inner: self.inner } ClientPayloadCodec { inner: self.inner }
} }
@ -102,11 +107,13 @@ impl ClientCodec {
impl ClientPayloadCodec { impl ClientPayloadCodec {
/// Check if last response is keep-alive /// Check if last response is keep-alive
#[must_use]
pub fn keepalive(&self) -> bool { pub fn keepalive(&self) -> bool {
self.inner.ctype == ConnectionType::KeepAlive self.inner.ctype == ConnectionType::KeepAlive
} }
/// Transform payload codec to a message codec /// Transform payload codec to a message codec
#[must_use]
pub fn into_message_codec(self) -> ClientCodec { pub fn into_message_codec(self) -> ClientCodec {
ClientCodec { inner: self.inner } ClientCodec { inner: self.inner }
} }

View File

@ -52,6 +52,7 @@ impl Codec {
/// Create HTTP/1 codec. /// Create HTTP/1 codec.
/// ///
/// `keepalive_enabled` how response `connection` header get generated. /// `keepalive_enabled` how response `connection` header get generated.
#[must_use]
pub fn new(config: ServiceConfig) -> Self { pub fn new(config: ServiceConfig) -> Self {
let flags = if config.keep_alive_enabled() { let flags = if config.keep_alive_enabled() {
Flags::KEEPALIVE_ENABLED Flags::KEEPALIVE_ENABLED
@ -72,24 +73,28 @@ impl Codec {
/// Check if request is upgrade. /// Check if request is upgrade.
#[inline] #[inline]
#[must_use]
pub fn upgrade(&self) -> bool { pub fn upgrade(&self) -> bool {
self.ctype == ConnectionType::Upgrade self.ctype == ConnectionType::Upgrade
} }
/// Check if last response is keep-alive. /// Check if last response is keep-alive.
#[inline] #[inline]
#[must_use]
pub fn keepalive(&self) -> bool { pub fn keepalive(&self) -> bool {
self.ctype == ConnectionType::KeepAlive self.ctype == ConnectionType::KeepAlive
} }
/// Check if keep-alive enabled on server level. /// Check if keep-alive enabled on server level.
#[inline] #[inline]
#[must_use]
pub fn keepalive_enabled(&self) -> bool { pub fn keepalive_enabled(&self) -> bool {
self.flags.contains(Flags::KEEPALIVE_ENABLED) self.flags.contains(Flags::KEEPALIVE_ENABLED)
} }
/// Check last request's message type. /// Check last request's message type.
#[inline] #[inline]
#[must_use]
pub fn message_type(&self) -> MessageType { pub fn message_type(&self) -> MessageType {
if self.flags.contains(Flags::STREAM) { if self.flags.contains(Flags::STREAM) {
MessageType::Stream MessageType::Stream
@ -101,6 +106,7 @@ impl Codec {
} }
#[inline] #[inline]
#[must_use]
pub fn config(&self) -> &ServiceConfig { pub fn config(&self) -> &ServiceConfig {
&self.config &self.config
} }

View File

@ -102,7 +102,7 @@ pub(crate) trait MessageType: Sized {
} }
// transfer-encoding // transfer-encoding
header::TRANSFER_ENCODING => { header::TRANSFER_ENCODING => {
if let Ok(s) = value.to_str().map(|s| s.trim()) { if let Ok(s) = value.to_str().map(str::trim) {
chunked = s.eq_ignore_ascii_case("chunked"); chunked = s.eq_ignore_ascii_case("chunked");
} else { } else {
return Err(ParseError::Header); return Err(ParseError::Header);
@ -110,7 +110,7 @@ pub(crate) trait MessageType: Sized {
} }
// connection keep-alive state // connection keep-alive state
header::CONNECTION => { header::CONNECTION => {
ka = if let Ok(conn) = value.to_str().map(|conn| conn.trim()) { ka = if let Ok(conn) = value.to_str().map(str::trim) {
if conn.eq_ignore_ascii_case("keep-alive") { if conn.eq_ignore_ascii_case("keep-alive") {
Some(ConnectionType::KeepAlive) Some(ConnectionType::KeepAlive)
} else if conn.eq_ignore_ascii_case("close") { } else if conn.eq_ignore_ascii_case("close") {
@ -125,7 +125,7 @@ pub(crate) trait MessageType: Sized {
}; };
} }
header::UPGRADE => { header::UPGRADE => {
if let Ok(val) = value.to_str().map(|val| val.trim()) { if let Ok(val) = value.to_str().map(str::trim) {
if val.eq_ignore_ascii_case("websocket") { if val.eq_ignore_ascii_case("websocket") {
has_upgrade_websocket = true; has_upgrade_websocket = true;
} }

View File

@ -515,14 +515,13 @@ where
cx: &mut Context<'_>, cx: &mut Context<'_>,
) -> Result<(), DispatchError> { ) -> Result<(), DispatchError> {
// Handle `EXPECT: 100-Continue` header // Handle `EXPECT: 100-Continue` header
// set dispatcher state so the future is pinned.
let mut this = self.as_mut().project();
if req.head().expect() { if req.head().expect() {
// set dispatcher state so the future is pinned.
let mut this = self.as_mut().project();
let task = this.flow.expect.call(req); let task = this.flow.expect.call(req);
this.state.set(State::ExpectCall(task)); this.state.set(State::ExpectCall(task));
} else { } else {
// the same as above. // the same as above.
let mut this = self.as_mut().project();
let task = this.flow.service.call(req); let task = this.flow.service.call(req);
this.state.set(State::ServiceCall(task)); this.state.set(State::ServiceCall(task));
}; };

View File

@ -41,6 +41,7 @@ impl Payload {
/// * `PayloadSender` - *Sender* side of the stream /// * `PayloadSender` - *Sender* side of the stream
/// ///
/// * `Payload` - *Receiver* side of the stream /// * `Payload` - *Receiver* side of the stream
#[must_use]
pub fn create(eof: bool) -> (PayloadSender, Payload) { pub fn create(eof: bool) -> (PayloadSender, Payload) {
let shared = Rc::new(RefCell::new(Inner::new(eof))); let shared = Rc::new(RefCell::new(Inner::new(eof)));
@ -54,6 +55,7 @@ impl Payload {
/// Create empty payload /// Create empty payload
#[doc(hidden)] #[doc(hidden)]
#[must_use]
pub fn empty() -> Payload { pub fn empty() -> Payload {
Payload { Payload {
inner: Rc::new(RefCell::new(Inner::new(true))), inner: Rc::new(RefCell::new(Inner::new(true))),
@ -186,8 +188,7 @@ impl Inner {
if self if self
.task .task
.as_ref() .as_ref()
.map(|w| !cx.waker().will_wake(w)) .map_or(true, |w| !cx.waker().will_wake(w))
.unwrap_or(true)
{ {
self.task = Some(cx.waker().clone()); self.task = Some(cx.waker().clone());
} }
@ -199,8 +200,7 @@ impl Inner {
if self if self
.io_task .io_task
.as_ref() .as_ref()
.map(|w| !cx.waker().will_wake(w)) .map_or(true, |w| !cx.waker().will_wake(w))
.unwrap_or(true)
{ {
self.io_task = Some(cx.waker().clone()); self.io_task = Some(cx.waker().clone());
} }

View File

@ -81,6 +81,7 @@ impl HeaderMap {
/// assert!(map.is_empty()); /// assert!(map.is_empty());
/// assert_eq!(0, map.capacity()); /// assert_eq!(0, map.capacity());
/// ``` /// ```
#[must_use]
pub fn new() -> Self { pub fn new() -> Self {
HeaderMap::default() HeaderMap::default()
} }
@ -98,6 +99,7 @@ impl HeaderMap {
/// assert!(map.is_empty()); /// assert!(map.is_empty());
/// assert!(map.capacity() >= 16); /// assert!(map.capacity() >= 16);
/// ``` /// ```
#[must_use]
pub fn with_capacity(capacity: usize) -> Self { pub fn with_capacity(capacity: usize) -> Self {
HeaderMap { HeaderMap {
inner: AHashMap::with_capacity(capacity), inner: AHashMap::with_capacity(capacity),
@ -150,6 +152,7 @@ impl HeaderMap {
/// map.append(header::SET_COOKIE, HeaderValue::from_static("two=2")); /// map.append(header::SET_COOKIE, HeaderValue::from_static("two=2"));
/// assert_eq!(map.len(), 3); /// assert_eq!(map.len(), 3);
/// ``` /// ```
#[must_use]
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
self.inner self.inner
.iter() .iter()
@ -173,6 +176,7 @@ impl HeaderMap {
/// map.append(header::SET_COOKIE, HeaderValue::from_static("two=2")); /// map.append(header::SET_COOKIE, HeaderValue::from_static("two=2"));
/// assert_eq!(map.len_keys(), 2); /// assert_eq!(map.len_keys(), 2);
/// ``` /// ```
#[must_use]
pub fn len_keys(&self) -> usize { pub fn len_keys(&self) -> usize {
self.inner.len() self.inner.len()
} }
@ -188,6 +192,7 @@ impl HeaderMap {
/// map.insert(header::ACCEPT, HeaderValue::from_static("text/plain")); /// map.insert(header::ACCEPT, HeaderValue::from_static("text/plain"));
/// assert!(!map.is_empty()); /// assert!(!map.is_empty());
/// ``` /// ```
#[must_use]
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
self.inner.len() == 0 self.inner.len() == 0
} }
@ -249,7 +254,7 @@ impl HeaderMap {
/// assert!(map.get("INVALID HEADER NAME").is_none()); /// assert!(map.get("INVALID HEADER NAME").is_none());
/// ``` /// ```
pub fn get(&self, key: impl AsHeaderName) -> Option<&HeaderValue> { pub fn get(&self, key: impl AsHeaderName) -> Option<&HeaderValue> {
self.get_value(key).map(|val| val.first()) self.get_value(key).map(Value::first)
} }
/// Returns a mutable reference to the _first_ value associated a header name. /// Returns a mutable reference to the _first_ value associated a header name.
@ -280,8 +285,8 @@ impl HeaderMap {
/// ``` /// ```
pub fn get_mut(&mut self, key: impl AsHeaderName) -> Option<&mut HeaderValue> { pub fn get_mut(&mut self, key: impl AsHeaderName) -> Option<&mut HeaderValue> {
match key.try_as_name(super::as_name::Seal).ok()? { match key.try_as_name(super::as_name::Seal).ok()? {
Cow::Borrowed(name) => self.inner.get_mut(name).map(|v| v.first_mut()), Cow::Borrowed(name) => self.inner.get_mut(name).map(Value::first_mut),
Cow::Owned(name) => self.inner.get_mut(&name).map(|v| v.first_mut()), Cow::Owned(name) => self.inner.get_mut(&name).map(Value::first_mut),
} }
} }
@ -434,6 +439,7 @@ impl HeaderMap {
/// assert!(map.is_empty()); /// assert!(map.is_empty());
/// assert!(map.capacity() >= 16); /// assert!(map.capacity() >= 16);
/// ``` /// ```
#[must_use]
pub fn capacity(&self) -> usize { pub fn capacity(&self) -> usize {
self.inner.capacity() self.inner.capacity()
} }
@ -489,6 +495,7 @@ impl HeaderMap {
/// assert!(pairs.contains(&(&header::SET_COOKIE, &HeaderValue::from_static("one=1")))); /// assert!(pairs.contains(&(&header::SET_COOKIE, &HeaderValue::from_static("one=1"))));
/// assert!(pairs.contains(&(&header::SET_COOKIE, &HeaderValue::from_static("two=2")))); /// assert!(pairs.contains(&(&header::SET_COOKIE, &HeaderValue::from_static("two=2"))));
/// ``` /// ```
#[must_use]
pub fn iter(&self) -> Iter<'_> { pub fn iter(&self) -> Iter<'_> {
Iter::new(self.inner.iter()) Iter::new(self.inner.iter())
} }
@ -515,6 +522,7 @@ impl HeaderMap {
/// assert!(keys.contains(&header::HOST)); /// assert!(keys.contains(&header::HOST));
/// assert!(keys.contains(&header::SET_COOKIE)); /// assert!(keys.contains(&header::SET_COOKIE));
/// ``` /// ```
#[must_use]
pub fn keys(&self) -> Keys<'_> { pub fn keys(&self) -> Keys<'_> {
Keys(self.inner.keys()) Keys(self.inner.keys())
} }

View File

@ -33,12 +33,14 @@ pub enum ContentEncoding {
impl ContentEncoding { impl ContentEncoding {
/// Is the content compressed? /// Is the content compressed?
#[inline] #[inline]
#[must_use]
pub fn is_compression(self) -> bool { pub fn is_compression(self) -> bool {
matches!(self, ContentEncoding::Identity | ContentEncoding::Auto) matches!(self, ContentEncoding::Identity | ContentEncoding::Auto)
} }
/// Convert content encoding to string /// Convert content encoding to string
#[inline] #[inline]
#[must_use]
pub fn as_str(self) -> &'static str { pub fn as_str(self) -> &'static str {
match self { match self {
ContentEncoding::Br => "br", ContentEncoding::Br => "br",
@ -51,6 +53,7 @@ impl ContentEncoding {
/// Default Q-factor (quality) value. /// Default Q-factor (quality) value.
#[inline] #[inline]
#[must_use]
pub fn quality(self) -> f64 { pub fn quality(self) -> f64 {
match self { match self {
ContentEncoding::Br => 1.1, ContentEncoding::Br => 1.1,

View File

@ -152,15 +152,16 @@ impl RequestHead {
/// Connection upgrade status /// Connection upgrade status
pub fn upgrade(&self) -> bool { pub fn upgrade(&self) -> bool {
if let Some(hdr) = self.headers().get(header::CONNECTION) { self.headers()
if let Ok(s) = hdr.to_str() { .get(header::CONNECTION)
s.to_ascii_lowercase().contains("upgrade") .map(|hdr| {
} else { if let Ok(s) = hdr.to_str() {
false s.to_ascii_lowercase().contains("upgrade")
} } else {
} else { false
false }
} })
.unwrap_or(false)
} }
#[inline] #[inline]
@ -233,6 +234,7 @@ pub struct ResponseHead {
impl ResponseHead { impl ResponseHead {
/// Create new instance of `ResponseHead` type /// Create new instance of `ResponseHead` type
#[inline] #[inline]
#[must_use]
pub fn new(status: StatusCode) -> ResponseHead { pub fn new(status: StatusCode) -> ResponseHead {
ResponseHead { ResponseHead {
status, status,
@ -308,13 +310,11 @@ impl ResponseHead {
/// Get custom reason for the response /// Get custom reason for the response
#[inline] #[inline]
pub fn reason(&self) -> &str { pub fn reason(&self) -> &str {
if let Some(reason) = self.reason { self.reason.unwrap_or_else(|| {
reason
} else {
self.status self.status
.canonical_reason() .canonical_reason()
.unwrap_or("<unknown status code>") .unwrap_or("<unknown status code>")
} })
} }
#[inline] #[inline]
@ -355,8 +355,9 @@ pub struct Message<T: Head> {
impl<T: Head> Message<T> { impl<T: Head> Message<T> {
/// Get new message from the pool of objects /// Get new message from the pool of objects
#[must_use]
pub fn new() -> Self { pub fn new() -> Self {
T::with_pool(|p| p.get_message()) T::with_pool(MessagePool::get_message)
} }
} }

View File

@ -57,6 +57,7 @@ impl From<Message<RequestHead>> for Request<PayloadStream> {
impl Request<PayloadStream> { impl Request<PayloadStream> {
/// Create new Request instance /// Create new Request instance
#[must_use]
pub fn new() -> Request<PayloadStream> { pub fn new() -> Request<PayloadStream> {
Request { Request {
head: Message::new(), head: Message::new(),

View File

@ -25,6 +25,7 @@ pub struct Response<B> {
impl Response<AnyBody> { impl Response<AnyBody> {
/// Constructs a new response with default body. /// Constructs a new response with default body.
#[inline] #[inline]
#[must_use]
pub fn new(status: StatusCode) -> Self { pub fn new(status: StatusCode) -> Self {
Response { Response {
head: BoxedResponseHead::new(status), head: BoxedResponseHead::new(status),
@ -34,6 +35,7 @@ impl Response<AnyBody> {
/// Constructs a new response builder. /// Constructs a new response builder.
#[inline] #[inline]
#[must_use]
pub fn build(status: StatusCode) -> ResponseBuilder { pub fn build(status: StatusCode) -> ResponseBuilder {
ResponseBuilder::new(status) ResponseBuilder::new(status)
} }
@ -43,24 +45,28 @@ impl Response<AnyBody> {
/// Constructs a new response with status 200 OK. /// Constructs a new response with status 200 OK.
#[inline] #[inline]
#[must_use]
pub fn ok() -> Self { pub fn ok() -> Self {
Response::new(StatusCode::OK) Response::new(StatusCode::OK)
} }
/// Constructs a new response with status 400 Bad Request. /// Constructs a new response with status 400 Bad Request.
#[inline] #[inline]
#[must_use]
pub fn bad_request() -> Self { pub fn bad_request() -> Self {
Response::new(StatusCode::BAD_REQUEST) Response::new(StatusCode::BAD_REQUEST)
} }
/// Constructs a new response with status 404 Not Found. /// Constructs a new response with status 404 Not Found.
#[inline] #[inline]
#[must_use]
pub fn not_found() -> Self { pub fn not_found() -> Self {
Response::new(StatusCode::NOT_FOUND) Response::new(StatusCode::NOT_FOUND)
} }
/// Constructs a new response with status 500 Internal Server Error. /// Constructs a new response with status 500 Internal Server Error.
#[inline] #[inline]
#[must_use]
pub fn internal_server_error() -> Self { pub fn internal_server_error() -> Self {
Response::new(StatusCode::INTERNAL_SERVER_ERROR) Response::new(StatusCode::INTERNAL_SERVER_ERROR)
} }

View File

@ -62,6 +62,7 @@ impl ResponseBuilder {
/// assert_eq!(res.status(), StatusCode::OK); /// assert_eq!(res.status(), StatusCode::OK);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn new(status: StatusCode) -> Self { pub fn new(status: StatusCode) -> Self {
ResponseBuilder { ResponseBuilder {
head: Some(BoxedResponseHead::new(status)), head: Some(BoxedResponseHead::new(status)),
@ -220,6 +221,7 @@ impl ResponseBuilder {
/// Responses extensions /// Responses extensions
#[inline] #[inline]
#[must_use]
pub fn extensions(&self) -> Ref<'_, Extensions> { pub fn extensions(&self) -> Ref<'_, Extensions> {
let head = self.head.as_ref().expect("cannot reuse response builder"); let head = self.head.as_ref().expect("cannot reuse response builder");
head.extensions.borrow() head.extensions.borrow()

View File

@ -47,6 +47,7 @@ where
B: MessageBody + 'static, B: MessageBody + 'static,
{ {
/// Create builder for `HttpService` instance. /// Create builder for `HttpService` instance.
#[must_use]
pub fn build() -> HttpServiceBuilder<T, S> { pub fn build() -> HttpServiceBuilder<T, S> {
HttpServiceBuilder::new() HttpServiceBuilder::new()
} }

View File

@ -80,6 +80,7 @@ bitflags! {
impl Codec { impl Codec {
/// Create new WebSocket frames decoder. /// Create new WebSocket frames decoder.
#[must_use]
pub const fn new() -> Codec { pub const fn new() -> Codec {
Codec { Codec {
max_size: 65_536, max_size: 65_536,
@ -90,6 +91,7 @@ impl Codec {
/// Set max frame size. /// Set max frame size.
/// ///
/// By default max size is set to 64kB. /// By default max size is set to 64kB.
#[must_use]
pub fn max_size(mut self, size: usize) -> Self { pub fn max_size(mut self, size: usize) -> Self {
self.max_size = size; self.max_size = size;
self self
@ -98,6 +100,7 @@ impl Codec {
/// Set decoder to client mode. /// Set decoder to client mode.
/// ///
/// By default decoder works in server mode. /// By default decoder works in server mode.
#[must_use]
pub fn client_mode(mut self) -> Self { pub fn client_mode(mut self) -> Self {
self.flags.remove(Flags::SERVER); self.flags.remove(Flags::SERVER);
self self

View File

@ -139,6 +139,7 @@ impl Parser {
} }
/// Parse the payload of a close frame. /// Parse the payload of a close frame.
#[must_use]
pub fn parse_close_payload(payload: &[u8]) -> Option<CloseReason> { pub fn parse_close_payload(payload: &[u8]) -> Option<CloseReason> {
if payload.len() >= 2 { if payload.len() >= 2 {
let raw_code = u16::from_be_bytes(TryFrom::try_from(&payload[..2]).unwrap()); let raw_code = u16::from_be_bytes(TryFrom::try_from(&payload[..2]).unwrap());

View File

@ -226,6 +226,7 @@ static WS_GUID: &[u8] = b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
/// Hashes the `Sec-WebSocket-Key` header according to the WebSocket spec. /// Hashes the `Sec-WebSocket-Key` header according to the WebSocket spec.
/// ///
/// Result is a Base64 encoded byte array. `base64(sha1(input))` is always 28 bytes. /// Result is a Base64 encoded byte array. `base64(sha1(input))` is always 28 bytes.
#[must_use]
pub fn hash_key(key: &[u8]) -> [u8; 28] { pub fn hash_key(key: &[u8]) -> [u8; 28] {
let hash = { let hash = {
use sha1::Digest as _; use sha1::Digest as _;