mirror of https://github.com/fafhrd91/actix-web
Various fixes in actix-http crate
This commit is contained in:
parent
282a66f327
commit
4cc8eafd3e
|
@ -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() };
|
||||||
|
|
||||||
|
|
|
@ -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))
|
||||||
}
|
}
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -168,7 +168,7 @@ 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() {
|
if !b.is_empty() {
|
||||||
send.reserve_capacity(b.len());
|
send.reserve_capacity(b.len());
|
||||||
} else {
|
} else {
|
||||||
|
@ -176,7 +176,6 @@ where
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Some(Err(e)) => return Err(e.into()),
|
Some(Err(e)) => return Err(e.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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>())
|
||||||
|
|
|
@ -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 }
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
if req.head().expect() {
|
|
||||||
// set dispatcher state so the future is pinned.
|
// set dispatcher state so the future is pinned.
|
||||||
let mut this = self.as_mut().project();
|
let mut this = self.as_mut().project();
|
||||||
|
if req.head().expect() {
|
||||||
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));
|
||||||
};
|
};
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
|
@ -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())
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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()
|
||||||
|
.get(header::CONNECTION)
|
||||||
|
.map(|hdr| {
|
||||||
if let Ok(s) = hdr.to_str() {
|
if let Ok(s) = hdr.to_str() {
|
||||||
s.to_ascii_lowercase().contains("upgrade")
|
s.to_ascii_lowercase().contains("upgrade")
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
} else {
|
})
|
||||||
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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(),
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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 _;
|
||||||
|
|
Loading…
Reference in New Issue