mirror of
https://github.com/fafhrd91/actix-web
synced 2024-11-24 00:21:08 +01:00
Merge remote-tracking branch 'origin/master' into remove-extensions-from-head
This commit is contained in:
commit
fb5b4734a4
@ -262,9 +262,9 @@ impl Files {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// See [`Files::method_guard`].
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[deprecated(since = "0.6.0", note = "Renamed to `method_guard`.")]
|
#[deprecated(since = "0.6.0", note = "Renamed to `method_guard`.")]
|
||||||
/// See [`Files::method_guard`].
|
|
||||||
pub fn use_guards<G: Guard + 'static>(self, guard: G) -> Self {
|
pub fn use_guards<G: Guard + 'static>(self, guard: G) -> Self {
|
||||||
self.method_guard(guard)
|
self.method_guard(guard)
|
||||||
}
|
}
|
||||||
|
@ -11,8 +11,8 @@
|
|||||||
//! .service(Files::new("/static", ".").prefer_utf8(true));
|
//! .service(Files::new("/static", ".").prefer_utf8(true));
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
#![deny(rust_2018_idioms)]
|
#![deny(rust_2018_idioms, nonstandard_style)]
|
||||||
#![warn(missing_docs, missing_debug_implementations)]
|
#![warn(future_incompatible, missing_docs, missing_debug_implementations)]
|
||||||
|
|
||||||
use actix_service::boxed::{BoxService, BoxServiceFactory};
|
use actix_service::boxed::{BoxService, BoxServiceFactory};
|
||||||
use actix_web::{
|
use actix_web::{
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
//! Various helpers for Actix applications to use during testing.
|
//! Various helpers for Actix applications to use during testing.
|
||||||
|
|
||||||
#![deny(rust_2018_idioms)]
|
#![deny(rust_2018_idioms, nonstandard_style)]
|
||||||
|
#![warn(future_incompatible)]
|
||||||
#![doc(html_logo_url = "https://actix.rs/img/logo.png")]
|
#![doc(html_logo_url = "https://actix.rs/img/logo.png")]
|
||||||
#![doc(html_favicon_url = "https://actix.rs/favicon.ico")]
|
#![doc(html_favicon_url = "https://actix.rs/favicon.ico")]
|
||||||
|
|
||||||
|
@ -189,11 +189,7 @@ mod _original {
|
|||||||
n /= 100;
|
n /= 100;
|
||||||
curr -= 2;
|
curr -= 2;
|
||||||
unsafe {
|
unsafe {
|
||||||
ptr::copy_nonoverlapping(
|
ptr::copy_nonoverlapping(lut_ptr.offset(d1 as isize), buf_ptr.offset(curr), 2);
|
||||||
lut_ptr.offset(d1 as isize),
|
|
||||||
buf_ptr.offset(curr),
|
|
||||||
2,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// decode last 1 or 2 chars
|
// decode last 1 or 2 chars
|
||||||
@ -206,11 +202,7 @@ mod _original {
|
|||||||
let d1 = n << 1;
|
let d1 = n << 1;
|
||||||
curr -= 2;
|
curr -= 2;
|
||||||
unsafe {
|
unsafe {
|
||||||
ptr::copy_nonoverlapping(
|
ptr::copy_nonoverlapping(lut_ptr.offset(d1 as isize), buf_ptr.offset(curr), 2);
|
||||||
lut_ptr.offset(d1 as isize),
|
|
||||||
buf_ptr.offset(curr),
|
|
||||||
2,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,15 +54,10 @@ const EMPTY_HEADER_INDEX: HeaderIndex = HeaderIndex {
|
|||||||
value: (0, 0),
|
value: (0, 0),
|
||||||
};
|
};
|
||||||
|
|
||||||
const EMPTY_HEADER_INDEX_ARRAY: [HeaderIndex; MAX_HEADERS] =
|
const EMPTY_HEADER_INDEX_ARRAY: [HeaderIndex; MAX_HEADERS] = [EMPTY_HEADER_INDEX; MAX_HEADERS];
|
||||||
[EMPTY_HEADER_INDEX; MAX_HEADERS];
|
|
||||||
|
|
||||||
impl HeaderIndex {
|
impl HeaderIndex {
|
||||||
fn record(
|
fn record(bytes: &[u8], headers: &[httparse::Header<'_>], indices: &mut [HeaderIndex]) {
|
||||||
bytes: &[u8],
|
|
||||||
headers: &[httparse::Header<'_>],
|
|
||||||
indices: &mut [HeaderIndex],
|
|
||||||
) {
|
|
||||||
let bytes_ptr = bytes.as_ptr() as usize;
|
let bytes_ptr = bytes.as_ptr() as usize;
|
||||||
for (header, indices) in headers.iter().zip(indices.iter_mut()) {
|
for (header, indices) in headers.iter().zip(indices.iter_mut()) {
|
||||||
let name_start = header.name.as_ptr() as usize - bytes_ptr;
|
let name_start = header.name.as_ptr() as usize - bytes_ptr;
|
||||||
|
@ -25,10 +25,7 @@ async fn main() -> io::Result<()> {
|
|||||||
|
|
||||||
Ok::<_, Error>(
|
Ok::<_, Error>(
|
||||||
Response::build(StatusCode::OK)
|
Response::build(StatusCode::OK)
|
||||||
.insert_header((
|
.insert_header(("x-head", HeaderValue::from_static("dummy value!")))
|
||||||
"x-head",
|
|
||||||
HeaderValue::from_static("dummy value!"),
|
|
||||||
))
|
|
||||||
.body(body),
|
.body(body),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
use actix_http::{
|
use actix_http::{
|
||||||
body::MessageBody, header::HeaderValue, Error, HttpService, Request, Response,
|
body::MessageBody, header::HeaderValue, Error, HttpService, Request, Response, StatusCode,
|
||||||
StatusCode,
|
|
||||||
};
|
};
|
||||||
use actix_server::Server;
|
use actix_server::Server;
|
||||||
use bytes::BytesMut;
|
use bytes::BytesMut;
|
||||||
|
@ -21,10 +21,7 @@ async fn main() -> io::Result<()> {
|
|||||||
log::info!("{:?}", req);
|
log::info!("{:?}", req);
|
||||||
|
|
||||||
let mut res = Response::build(StatusCode::OK);
|
let mut res = Response::build(StatusCode::OK);
|
||||||
res.insert_header((
|
res.insert_header(("x-head", HeaderValue::from_static("dummy value!")));
|
||||||
"x-head",
|
|
||||||
HeaderValue::from_static("dummy value!"),
|
|
||||||
));
|
|
||||||
|
|
||||||
let forty_two = req.extensions().get::<u32>().unwrap().to_string();
|
let forty_two = req.extensions().get::<u32>().unwrap().to_string();
|
||||||
res.insert_header((
|
res.insert_header((
|
||||||
|
@ -60,10 +60,7 @@ impl Heartbeat {
|
|||||||
impl Stream for Heartbeat {
|
impl Stream for Heartbeat {
|
||||||
type Item = Result<Bytes, Error>;
|
type Item = Result<Bytes, Error>;
|
||||||
|
|
||||||
fn poll_next(
|
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
mut self: Pin<&mut Self>,
|
|
||||||
cx: &mut Context<'_>,
|
|
||||||
) -> Poll<Option<Self::Item>> {
|
|
||||||
log::trace!("poll");
|
log::trace!("poll");
|
||||||
|
|
||||||
ready!(self.as_mut().interval.poll_tick(cx));
|
ready!(self.as_mut().interval.poll_tick(cx));
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
max_width = 89
|
|
||||||
reorder_imports = true
|
|
||||||
#wrap_comments = true
|
|
||||||
#fn_args_density = "Compressed"
|
|
||||||
#use_small_heuristics = false
|
|
@ -165,8 +165,7 @@ mod tests {
|
|||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn stream_delayed_error() {
|
async fn stream_delayed_error() {
|
||||||
let body =
|
let body = BodyStream::new(stream::iter(vec![Ok(Bytes::from("1")), Err(StreamErr)]));
|
||||||
BodyStream::new(stream::iter(vec![Ok(Bytes::from("1")), Err(StreamErr)]));
|
|
||||||
assert!(matches!(to_bytes(body).await, Err(StreamErr)));
|
assert!(matches!(to_bytes(body).await, Err(StreamErr)));
|
||||||
|
|
||||||
pin_project! {
|
pin_project! {
|
||||||
|
@ -24,9 +24,7 @@ impl BoxBody {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a mutable pinned reference to the inner message body type.
|
/// Returns a mutable pinned reference to the inner message body type.
|
||||||
pub fn as_pin_mut(
|
pub fn as_pin_mut(&mut self) -> Pin<&mut (dyn MessageBody<Error = Box<dyn StdError>>)> {
|
||||||
&mut self,
|
|
||||||
) -> Pin<&mut (dyn MessageBody<Error = Box<dyn StdError>>)> {
|
|
||||||
self.0.as_mut()
|
self.0.as_mut()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,9 +68,8 @@ mod test {
|
|||||||
let bytes = to_bytes(body).await.unwrap();
|
let bytes = to_bytes(body).await.unwrap();
|
||||||
assert_eq!(bytes, b"123"[..]);
|
assert_eq!(bytes, b"123"[..]);
|
||||||
|
|
||||||
let stream =
|
let stream = stream::iter(vec![Bytes::from_static(b"123"), Bytes::from_static(b"abc")])
|
||||||
stream::iter(vec![Bytes::from_static(b"123"), Bytes::from_static(b"abc")])
|
.map(Ok::<_, Error>);
|
||||||
.map(Ok::<_, Error>);
|
|
||||||
let body = BodyStream::new(stream);
|
let body = BodyStream::new(stream);
|
||||||
let bytes = to_bytes(body).await.unwrap();
|
let bytes = to_bytes(body).await.unwrap();
|
||||||
assert_eq!(bytes, b"123abc"[..]);
|
assert_eq!(bytes, b"123abc"[..]);
|
||||||
|
@ -214,8 +214,7 @@ where
|
|||||||
self.local_addr,
|
self.local_addr,
|
||||||
);
|
);
|
||||||
|
|
||||||
H2Service::with_config(cfg, service.into_factory())
|
H2Service::with_config(cfg, service.into_factory()).on_connect_ext(self.on_connect_ext)
|
||||||
.on_connect_ext(self.on_connect_ext)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finish service configuration and create `HttpService` instance.
|
/// Finish service configuration and create `HttpService` instance.
|
||||||
|
@ -44,17 +44,17 @@ where
|
|||||||
pub fn new(stream: S, encoding: ContentEncoding) -> Decoder<S> {
|
pub fn new(stream: S, encoding: ContentEncoding) -> Decoder<S> {
|
||||||
let decoder = match encoding {
|
let decoder = match encoding {
|
||||||
#[cfg(feature = "compress-brotli")]
|
#[cfg(feature = "compress-brotli")]
|
||||||
ContentEncoding::Br => Some(ContentDecoder::Br(Box::new(
|
ContentEncoding::Br => Some(ContentDecoder::Br(Box::new(BrotliDecoder::new(
|
||||||
BrotliDecoder::new(Writer::new()),
|
Writer::new(),
|
||||||
))),
|
)))),
|
||||||
#[cfg(feature = "compress-gzip")]
|
#[cfg(feature = "compress-gzip")]
|
||||||
ContentEncoding::Deflate => Some(ContentDecoder::Deflate(Box::new(
|
ContentEncoding::Deflate => Some(ContentDecoder::Deflate(Box::new(
|
||||||
ZlibDecoder::new(Writer::new()),
|
ZlibDecoder::new(Writer::new()),
|
||||||
))),
|
))),
|
||||||
#[cfg(feature = "compress-gzip")]
|
#[cfg(feature = "compress-gzip")]
|
||||||
ContentEncoding::Gzip => Some(ContentDecoder::Gzip(Box::new(
|
ContentEncoding::Gzip => Some(ContentDecoder::Gzip(Box::new(GzDecoder::new(
|
||||||
GzDecoder::new(Writer::new()),
|
Writer::new(),
|
||||||
))),
|
)))),
|
||||||
#[cfg(feature = "compress-zstd")]
|
#[cfg(feature = "compress-zstd")]
|
||||||
ContentEncoding::Zstd => Some(ContentDecoder::Zstd(Box::new(
|
ContentEncoding::Zstd => Some(ContentDecoder::Zstd(Box::new(
|
||||||
ZstdDecoder::new(Writer::new()).expect(
|
ZstdDecoder::new(Writer::new()).expect(
|
||||||
@ -93,10 +93,7 @@ where
|
|||||||
{
|
{
|
||||||
type Item = Result<Bytes, PayloadError>;
|
type Item = Result<Bytes, PayloadError>;
|
||||||
|
|
||||||
fn poll_next(
|
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
mut self: Pin<&mut Self>,
|
|
||||||
cx: &mut Context<'_>,
|
|
||||||
) -> Poll<Option<Self::Item>> {
|
|
||||||
loop {
|
loop {
|
||||||
if let Some(ref mut fut) = self.fut {
|
if let Some(ref mut fut) = self.fut {
|
||||||
let (chunk, decoder) =
|
let (chunk, decoder) =
|
||||||
|
@ -53,11 +53,7 @@ impl<B: MessageBody> Encoder<B> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn response(
|
pub fn response(encoding: ContentEncoding, head: &mut ResponseHead, body: B) -> Self {
|
||||||
encoding: ContentEncoding,
|
|
||||||
head: &mut ResponseHead,
|
|
||||||
body: B,
|
|
||||||
) -> Self {
|
|
||||||
let can_encode = !(head.headers().contains_key(&CONTENT_ENCODING)
|
let can_encode = !(head.headers().contains_key(&CONTENT_ENCODING)
|
||||||
|| head.status == StatusCode::SWITCHING_PROTOCOLS
|
|| head.status == StatusCode::SWITCHING_PROTOCOLS
|
||||||
|| head.status == StatusCode::NO_CONTENT
|
|| head.status == StatusCode::NO_CONTENT
|
||||||
|
@ -457,8 +457,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_payload_error() {
|
fn test_payload_error() {
|
||||||
let err: PayloadError =
|
let err: PayloadError = io::Error::new(io::ErrorKind::Other, "ParseError").into();
|
||||||
io::Error::new(io::ErrorKind::Other, "ParseError").into();
|
|
||||||
assert!(err.to_string().contains("ParseError"));
|
assert!(err.to_string().contains("ParseError"));
|
||||||
|
|
||||||
let err = PayloadError::Incomplete(None);
|
let err = PayloadError::Incomplete(None);
|
||||||
|
@ -50,10 +50,7 @@ impl ChunkedState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_size(
|
fn read_size(rdr: &mut BytesMut, size: &mut u64) -> Poll<Result<ChunkedState, io::Error>> {
|
||||||
rdr: &mut BytesMut,
|
|
||||||
size: &mut u64,
|
|
||||||
) -> Poll<Result<ChunkedState, io::Error>> {
|
|
||||||
let radix = 16;
|
let radix = 16;
|
||||||
|
|
||||||
let rem = match byte!(rdr) {
|
let rem = match byte!(rdr) {
|
||||||
@ -111,10 +108,7 @@ impl ChunkedState {
|
|||||||
_ => Poll::Ready(Ok(ChunkedState::Extension)), // no supported extensions
|
_ => Poll::Ready(Ok(ChunkedState::Extension)), // no supported extensions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn read_size_lf(
|
fn read_size_lf(rdr: &mut BytesMut, size: u64) -> Poll<Result<ChunkedState, io::Error>> {
|
||||||
rdr: &mut BytesMut,
|
|
||||||
size: u64,
|
|
||||||
) -> Poll<Result<ChunkedState, io::Error>> {
|
|
||||||
match byte!(rdr) {
|
match byte!(rdr) {
|
||||||
b'\n' if size > 0 => Poll::Ready(Ok(ChunkedState::Body)),
|
b'\n' if size > 0 => Poll::Ready(Ok(ChunkedState::Body)),
|
||||||
b'\n' if size == 0 => Poll::Ready(Ok(ChunkedState::EndCr)),
|
b'\n' if size == 0 => Poll::Ready(Ok(ChunkedState::EndCr)),
|
||||||
|
@ -74,8 +74,7 @@ pub(crate) trait MessageType: Sized {
|
|||||||
let headers = self.headers_mut();
|
let headers = self.headers_mut();
|
||||||
|
|
||||||
for idx in raw_headers.iter() {
|
for idx in raw_headers.iter() {
|
||||||
let name =
|
let name = HeaderName::from_bytes(&slice[idx.name.0..idx.name.1]).unwrap();
|
||||||
HeaderName::from_bytes(&slice[idx.name.0..idx.name.1]).unwrap();
|
|
||||||
|
|
||||||
// SAFETY: httparse already checks header value is only visible ASCII bytes
|
// SAFETY: httparse already checks header value is only visible ASCII bytes
|
||||||
// from_maybe_shared_unchecked contains debug assertions so they are omitted here
|
// from_maybe_shared_unchecked contains debug assertions so they are omitted here
|
||||||
@ -605,8 +604,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_body() {
|
fn test_parse_body() {
|
||||||
let mut buf =
|
let mut buf = BytesMut::from("GET /test HTTP/1.1\r\nContent-Length: 4\r\n\r\nbody");
|
||||||
BytesMut::from("GET /test HTTP/1.1\r\nContent-Length: 4\r\n\r\nbody");
|
|
||||||
|
|
||||||
let mut reader = MessageDecoder::<Request>::default();
|
let mut reader = MessageDecoder::<Request>::default();
|
||||||
let (req, pl) = reader.decode(&mut buf).unwrap().unwrap();
|
let (req, pl) = reader.decode(&mut buf).unwrap().unwrap();
|
||||||
@ -622,8 +620,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_body_crlf() {
|
fn test_parse_body_crlf() {
|
||||||
let mut buf =
|
let mut buf = BytesMut::from("\r\nGET /test HTTP/1.1\r\nContent-Length: 4\r\n\r\nbody");
|
||||||
BytesMut::from("\r\nGET /test HTTP/1.1\r\nContent-Length: 4\r\n\r\nbody");
|
|
||||||
|
|
||||||
let mut reader = MessageDecoder::<Request>::default();
|
let mut reader = MessageDecoder::<Request>::default();
|
||||||
let (req, pl) = reader.decode(&mut buf).unwrap().unwrap();
|
let (req, pl) = reader.decode(&mut buf).unwrap().unwrap();
|
||||||
|
@ -27,6 +27,7 @@ use crate::{
|
|||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
codec::Codec,
|
codec::Codec,
|
||||||
|
decoder::MAX_BUFFER_SIZE,
|
||||||
payload::{Payload, PayloadSender, PayloadStatus},
|
payload::{Payload, PayloadSender, PayloadStatus},
|
||||||
Message, MessageType,
|
Message, MessageType,
|
||||||
};
|
};
|
||||||
@ -259,10 +260,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll_flush(
|
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
|
||||||
self: Pin<&mut Self>,
|
|
||||||
cx: &mut Context<'_>,
|
|
||||||
) -> Poll<Result<(), io::Error>> {
|
|
||||||
let InnerDispatcherProj { io, write_buf, .. } = self.project();
|
let InnerDispatcherProj { io, write_buf, .. } = self.project();
|
||||||
let mut io = Pin::new(io.as_mut().unwrap());
|
let mut io = Pin::new(io.as_mut().unwrap());
|
||||||
|
|
||||||
@ -272,10 +270,7 @@ where
|
|||||||
while written < len {
|
while written < len {
|
||||||
match io.as_mut().poll_write(cx, &write_buf[written..])? {
|
match io.as_mut().poll_write(cx, &write_buf[written..])? {
|
||||||
Poll::Ready(0) => {
|
Poll::Ready(0) => {
|
||||||
return Poll::Ready(Err(io::Error::new(
|
return Poll::Ready(Err(io::Error::new(io::ErrorKind::WriteZero, "")))
|
||||||
io::ErrorKind::WriteZero,
|
|
||||||
"",
|
|
||||||
)))
|
|
||||||
}
|
}
|
||||||
Poll::Ready(n) => written += n,
|
Poll::Ready(n) => written += n,
|
||||||
Poll::Pending => {
|
Poll::Pending => {
|
||||||
@ -418,15 +413,12 @@ where
|
|||||||
while this.write_buf.len() < super::payload::MAX_BUFFER_SIZE {
|
while this.write_buf.len() < super::payload::MAX_BUFFER_SIZE {
|
||||||
match stream.as_mut().poll_next(cx) {
|
match stream.as_mut().poll_next(cx) {
|
||||||
Poll::Ready(Some(Ok(item))) => {
|
Poll::Ready(Some(Ok(item))) => {
|
||||||
this.codec.encode(
|
this.codec
|
||||||
Message::Chunk(Some(item)),
|
.encode(Message::Chunk(Some(item)), this.write_buf)?;
|
||||||
this.write_buf,
|
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Poll::Ready(None) => {
|
Poll::Ready(None) => {
|
||||||
this.codec
|
this.codec.encode(Message::Chunk(None), this.write_buf)?;
|
||||||
.encode(Message::Chunk(None), this.write_buf)?;
|
|
||||||
// payload stream finished.
|
// payload stream finished.
|
||||||
// set state to None and handle next message
|
// set state to None and handle next message
|
||||||
this.state.set(State::None);
|
this.state.set(State::None);
|
||||||
@ -453,15 +445,12 @@ where
|
|||||||
while this.write_buf.len() < super::payload::MAX_BUFFER_SIZE {
|
while this.write_buf.len() < super::payload::MAX_BUFFER_SIZE {
|
||||||
match stream.as_mut().poll_next(cx) {
|
match stream.as_mut().poll_next(cx) {
|
||||||
Poll::Ready(Some(Ok(item))) => {
|
Poll::Ready(Some(Ok(item))) => {
|
||||||
this.codec.encode(
|
this.codec
|
||||||
Message::Chunk(Some(item)),
|
.encode(Message::Chunk(Some(item)), this.write_buf)?;
|
||||||
this.write_buf,
|
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Poll::Ready(None) => {
|
Poll::Ready(None) => {
|
||||||
this.codec
|
this.codec.encode(Message::Chunk(None), this.write_buf)?;
|
||||||
.encode(Message::Chunk(None), this.write_buf)?;
|
|
||||||
// payload stream finished.
|
// payload stream finished.
|
||||||
// set state to None and handle next message
|
// set state to None and handle next message
|
||||||
this.state.set(State::None);
|
this.state.set(State::None);
|
||||||
@ -567,9 +556,11 @@ where
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
_ => unreachable!(
|
_ => {
|
||||||
"State must be set to ServiceCall or ExceptCall in handle_request"
|
unreachable!(
|
||||||
),
|
"State must be set to ServiceCall or ExceptCall in handle_request"
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -603,8 +594,7 @@ where
|
|||||||
// everything remain in read buffer would be handed to
|
// everything remain in read buffer would be handed to
|
||||||
// upgraded Request.
|
// upgraded Request.
|
||||||
MessageType::Stream if this.flow.upgrade.is_some() => {
|
MessageType::Stream if this.flow.upgrade.is_some() => {
|
||||||
this.messages
|
this.messages.push_back(DispatcherMessage::Upgrade(req));
|
||||||
.push_back(DispatcherMessage::Upgrade(req));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -619,8 +609,7 @@ where
|
|||||||
where the state can be collected and consumed.
|
where the state can be collected and consumed.
|
||||||
*/
|
*/
|
||||||
let (ps, pl) = Payload::create(false);
|
let (ps, pl) = Payload::create(false);
|
||||||
let (req1, _) =
|
let (req1, _) = req.replace_payload(crate::Payload::H1(pl));
|
||||||
req.replace_payload(crate::Payload::H1(pl));
|
|
||||||
req = req1;
|
req = req1;
|
||||||
*this.payload = Some(ps);
|
*this.payload = Some(ps);
|
||||||
}
|
}
|
||||||
@ -641,9 +630,7 @@ where
|
|||||||
if let Some(ref mut payload) = this.payload {
|
if let Some(ref mut payload) = this.payload {
|
||||||
payload.feed_data(chunk);
|
payload.feed_data(chunk);
|
||||||
} else {
|
} else {
|
||||||
error!(
|
error!("Internal server error: unexpected payload chunk");
|
||||||
"Internal server error: unexpected payload chunk"
|
|
||||||
);
|
|
||||||
this.flags.insert(Flags::READ_DISCONNECT);
|
this.flags.insert(Flags::READ_DISCONNECT);
|
||||||
this.messages.push_back(DispatcherMessage::Error(
|
this.messages.push_back(DispatcherMessage::Error(
|
||||||
Response::internal_server_error().drop_body(),
|
Response::internal_server_error().drop_body(),
|
||||||
@ -681,12 +668,11 @@ where
|
|||||||
payload.set_error(PayloadError::Overflow);
|
payload.set_error(PayloadError::Overflow);
|
||||||
}
|
}
|
||||||
// Requests overflow buffer size should be responded with 431
|
// Requests overflow buffer size should be responded with 431
|
||||||
this.messages.push_back(DispatcherMessage::Error(
|
this.messages
|
||||||
Response::with_body(
|
.push_back(DispatcherMessage::Error(Response::with_body(
|
||||||
StatusCode::REQUEST_HEADER_FIELDS_TOO_LARGE,
|
StatusCode::REQUEST_HEADER_FIELDS_TOO_LARGE,
|
||||||
(),
|
(),
|
||||||
),
|
)));
|
||||||
));
|
|
||||||
this.flags.insert(Flags::READ_DISCONNECT);
|
this.flags.insert(Flags::READ_DISCONNECT);
|
||||||
*this.error = Some(ParseError::TooLarge.into());
|
*this.error = Some(ParseError::TooLarge.into());
|
||||||
break;
|
break;
|
||||||
@ -728,8 +714,7 @@ where
|
|||||||
None => {
|
None => {
|
||||||
// conditionally go into shutdown timeout
|
// conditionally go into shutdown timeout
|
||||||
if this.flags.contains(Flags::SHUTDOWN) {
|
if this.flags.contains(Flags::SHUTDOWN) {
|
||||||
if let Some(deadline) = this.codec.config().client_disconnect_timer()
|
if let Some(deadline) = this.codec.config().client_disconnect_timer() {
|
||||||
{
|
|
||||||
// write client disconnect time out and poll again to
|
// write client disconnect time out and poll again to
|
||||||
// go into Some<Pin<&mut Sleep>> branch
|
// go into Some<Pin<&mut Sleep>> branch
|
||||||
this.ka_timer.set(Some(sleep_until(deadline)));
|
this.ka_timer.set(Some(sleep_until(deadline)));
|
||||||
@ -772,9 +757,7 @@ where
|
|||||||
this.flags.insert(Flags::STARTED | Flags::SHUTDOWN);
|
this.flags.insert(Flags::STARTED | Flags::SHUTDOWN);
|
||||||
}
|
}
|
||||||
// still have unfinished task. try to reset and register keep-alive.
|
// still have unfinished task. try to reset and register keep-alive.
|
||||||
} else if let Some(deadline) =
|
} else if let Some(deadline) = this.codec.config().keep_alive_expire() {
|
||||||
this.codec.config().keep_alive_expire()
|
|
||||||
{
|
|
||||||
timer.as_mut().reset(deadline);
|
timer.as_mut().reset(deadline);
|
||||||
let _ = timer.poll(cx);
|
let _ = timer.poll(cx);
|
||||||
}
|
}
|
||||||
@ -793,7 +776,6 @@ where
|
|||||||
/// Returns true when io stream can be disconnected after write to it.
|
/// Returns true when io stream can be disconnected after write to it.
|
||||||
///
|
///
|
||||||
/// It covers these conditions:
|
/// It covers these conditions:
|
||||||
///
|
|
||||||
/// - `std::io::ErrorKind::ConnectionReset` after partial read.
|
/// - `std::io::ErrorKind::ConnectionReset` after partial read.
|
||||||
/// - all data read done.
|
/// - all data read done.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
@ -813,46 +795,39 @@ where
|
|||||||
|
|
||||||
loop {
|
loop {
|
||||||
// Return early when read buf exceed decoder's max buffer size.
|
// Return early when read buf exceed decoder's max buffer size.
|
||||||
if this.read_buf.len() >= super::decoder::MAX_BUFFER_SIZE {
|
if this.read_buf.len() >= MAX_BUFFER_SIZE {
|
||||||
/*
|
// At this point it's not known IO stream is still scheduled to be waked up so
|
||||||
At this point it's not known IO stream is still scheduled
|
// force wake up dispatcher just in case.
|
||||||
to be waked up. so force wake up dispatcher just in case.
|
//
|
||||||
|
// Reason:
|
||||||
|
// AsyncRead mostly would only have guarantee wake up when the poll_read
|
||||||
|
// return Poll::Pending.
|
||||||
|
//
|
||||||
|
// Case:
|
||||||
|
// When read_buf is beyond max buffer size the early return could be successfully
|
||||||
|
// be parsed as a new Request. This case would not generate ParseError::TooLarge and
|
||||||
|
// at this point IO stream is not fully read to Pending and would result in
|
||||||
|
// dispatcher stuck until timeout (KA)
|
||||||
|
//
|
||||||
|
// Note:
|
||||||
|
// This is a perf choice to reduce branch on <Request as MessageType>::decode.
|
||||||
|
//
|
||||||
|
// A Request head too large to parse is only checked on
|
||||||
|
// `httparse::Status::Partial` condition.
|
||||||
|
|
||||||
Reason:
|
|
||||||
AsyncRead mostly would only have guarantee wake up
|
|
||||||
when the poll_read return Poll::Pending.
|
|
||||||
|
|
||||||
Case:
|
|
||||||
When read_buf is beyond max buffer size the early return
|
|
||||||
could be successfully be parsed as a new Request.
|
|
||||||
This case would not generate ParseError::TooLarge
|
|
||||||
and at this point IO stream is not fully read to Pending
|
|
||||||
and would result in dispatcher stuck until timeout (KA)
|
|
||||||
|
|
||||||
Note:
|
|
||||||
This is a perf choice to reduce branch on
|
|
||||||
<Request as MessageType>::decode.
|
|
||||||
|
|
||||||
A Request head too large to parse is only checked on
|
|
||||||
httparse::Status::Partial condition.
|
|
||||||
*/
|
|
||||||
if this.payload.is_none() {
|
if this.payload.is_none() {
|
||||||
/*
|
// When dispatcher has a payload the responsibility of wake up it would be shift
|
||||||
When dispatcher has a payload the responsibility of
|
// to h1::payload::Payload.
|
||||||
wake up it would be shift to h1::payload::Payload.
|
//
|
||||||
|
// Reason:
|
||||||
Reason:
|
// Self wake up when there is payload would waste poll and/or result in
|
||||||
Self wake up when there is payload would waste poll
|
// over read.
|
||||||
and/or result in over read.
|
//
|
||||||
|
// Case:
|
||||||
Case:
|
// When payload is (partial) dropped by user there is no need to do
|
||||||
When payload is (partial) dropped by user there is
|
// read anymore. At this case read_buf could always remain beyond
|
||||||
no need to do read anymore.
|
// MAX_BUFFER_SIZE and self wake up would be busy poll dispatcher and
|
||||||
At this case read_buf could always remain beyond
|
// waste resources.
|
||||||
MAX_BUFFER_SIZE and self wake up would be busy poll
|
|
||||||
dispatcher and waste resource.
|
|
||||||
|
|
||||||
*/
|
|
||||||
cx.waker().wake_by_ref();
|
cx.waker().wake_by_ref();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1060,14 +1035,12 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn ok_service(
|
fn ok_service(
|
||||||
) -> impl Service<Request, Response = Response<impl MessageBody>, Error = Error>
|
) -> impl Service<Request, Response = Response<impl MessageBody>, Error = Error> {
|
||||||
{
|
|
||||||
fn_service(|_req: Request| ready(Ok::<_, Error>(Response::ok())))
|
fn_service(|_req: Request| ready(Ok::<_, Error>(Response::ok())))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn echo_path_service(
|
fn echo_path_service(
|
||||||
) -> impl Service<Request, Response = Response<impl MessageBody>, Error = Error>
|
) -> impl Service<Request, Response = Response<impl MessageBody>, Error = Error> {
|
||||||
{
|
|
||||||
fn_service(|req: Request| {
|
fn_service(|req: Request| {
|
||||||
let path = req.path().as_bytes();
|
let path = req.path().as_bytes();
|
||||||
ready(Ok::<_, Error>(
|
ready(Ok::<_, Error>(
|
||||||
@ -1076,8 +1049,8 @@ mod tests {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn echo_payload_service(
|
fn echo_payload_service() -> impl Service<Request, Response = Response<Bytes>, Error = Error>
|
||||||
) -> impl Service<Request, Response = Response<Bytes>, Error = Error> {
|
{
|
||||||
fn_service(|mut req: Request| {
|
fn_service(|mut req: Request| {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
use futures_util::stream::StreamExt as _;
|
use futures_util::stream::StreamExt as _;
|
||||||
|
@ -103,9 +103,7 @@ pub(crate) trait MessageType: Sized {
|
|||||||
dst.put_slice(b"\r\n");
|
dst.put_slice(b"\r\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BodySize::Sized(0) if camel_case => {
|
BodySize::Sized(0) if camel_case => dst.put_slice(b"\r\nContent-Length: 0\r\n"),
|
||||||
dst.put_slice(b"\r\nContent-Length: 0\r\n")
|
|
||||||
}
|
|
||||||
BodySize::Sized(0) => dst.put_slice(b"\r\ncontent-length: 0\r\n"),
|
BodySize::Sized(0) => dst.put_slice(b"\r\ncontent-length: 0\r\n"),
|
||||||
BodySize::Sized(len) => helpers::write_content_length(len, dst),
|
BodySize::Sized(len) => helpers::write_content_length(len, dst),
|
||||||
BodySize::None => dst.put_slice(b"\r\n"),
|
BodySize::None => dst.put_slice(b"\r\n"),
|
||||||
@ -307,11 +305,7 @@ impl MessageType for RequestHeadType {
|
|||||||
Version::HTTP_11 => "HTTP/1.1",
|
Version::HTTP_11 => "HTTP/1.1",
|
||||||
Version::HTTP_2 => "HTTP/2.0",
|
Version::HTTP_2 => "HTTP/2.0",
|
||||||
Version::HTTP_3 => "HTTP/3.0",
|
Version::HTTP_3 => "HTTP/3.0",
|
||||||
_ =>
|
_ => return Err(io::Error::new(io::ErrorKind::Other, "unsupported version")),
|
||||||
return Err(io::Error::new(
|
|
||||||
io::ErrorKind::Other,
|
|
||||||
"unsupported version"
|
|
||||||
)),
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))
|
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))
|
||||||
@ -568,8 +562,7 @@ mod tests {
|
|||||||
ConnectionType::Close,
|
ConnectionType::Close,
|
||||||
&ServiceConfig::default(),
|
&ServiceConfig::default(),
|
||||||
);
|
);
|
||||||
let data =
|
let data = String::from_utf8(Vec::from(bytes.split().freeze().as_ref())).unwrap();
|
||||||
String::from_utf8(Vec::from(bytes.split().freeze().as_ref())).unwrap();
|
|
||||||
|
|
||||||
assert!(data.contains("Content-Length: 0\r\n"));
|
assert!(data.contains("Content-Length: 0\r\n"));
|
||||||
assert!(data.contains("Connection: close\r\n"));
|
assert!(data.contains("Connection: close\r\n"));
|
||||||
@ -583,8 +576,7 @@ mod tests {
|
|||||||
ConnectionType::KeepAlive,
|
ConnectionType::KeepAlive,
|
||||||
&ServiceConfig::default(),
|
&ServiceConfig::default(),
|
||||||
);
|
);
|
||||||
let data =
|
let data = String::from_utf8(Vec::from(bytes.split().freeze().as_ref())).unwrap();
|
||||||
String::from_utf8(Vec::from(bytes.split().freeze().as_ref())).unwrap();
|
|
||||||
assert!(data.contains("Transfer-Encoding: chunked\r\n"));
|
assert!(data.contains("Transfer-Encoding: chunked\r\n"));
|
||||||
assert!(data.contains("Content-Type: plain/text\r\n"));
|
assert!(data.contains("Content-Type: plain/text\r\n"));
|
||||||
assert!(data.contains("Date: date\r\n"));
|
assert!(data.contains("Date: date\r\n"));
|
||||||
@ -605,8 +597,7 @@ mod tests {
|
|||||||
ConnectionType::KeepAlive,
|
ConnectionType::KeepAlive,
|
||||||
&ServiceConfig::default(),
|
&ServiceConfig::default(),
|
||||||
);
|
);
|
||||||
let data =
|
let data = String::from_utf8(Vec::from(bytes.split().freeze().as_ref())).unwrap();
|
||||||
String::from_utf8(Vec::from(bytes.split().freeze().as_ref())).unwrap();
|
|
||||||
assert!(data.contains("transfer-encoding: chunked\r\n"));
|
assert!(data.contains("transfer-encoding: chunked\r\n"));
|
||||||
assert!(data.contains("content-type: xml\r\n"));
|
assert!(data.contains("content-type: xml\r\n"));
|
||||||
assert!(data.contains("content-type: plain/text\r\n"));
|
assert!(data.contains("content-type: plain/text\r\n"));
|
||||||
@ -639,8 +630,7 @@ mod tests {
|
|||||||
ConnectionType::Close,
|
ConnectionType::Close,
|
||||||
&ServiceConfig::default(),
|
&ServiceConfig::default(),
|
||||||
);
|
);
|
||||||
let data =
|
let data = String::from_utf8(Vec::from(bytes.split().freeze().as_ref())).unwrap();
|
||||||
String::from_utf8(Vec::from(bytes.split().freeze().as_ref())).unwrap();
|
|
||||||
assert!(data.contains("content-length: 0\r\n"));
|
assert!(data.contains("content-length: 0\r\n"));
|
||||||
assert!(data.contains("connection: close\r\n"));
|
assert!(data.contains("connection: close\r\n"));
|
||||||
assert!(data.contains("authorization: another authorization\r\n"));
|
assert!(data.contains("authorization: another authorization\r\n"));
|
||||||
@ -663,8 +653,7 @@ mod tests {
|
|||||||
ConnectionType::Upgrade,
|
ConnectionType::Upgrade,
|
||||||
&ServiceConfig::default(),
|
&ServiceConfig::default(),
|
||||||
);
|
);
|
||||||
let data =
|
let data = String::from_utf8(Vec::from(bytes.split().freeze().as_ref())).unwrap();
|
||||||
String::from_utf8(Vec::from(bytes.split().freeze().as_ref())).unwrap();
|
|
||||||
assert!(!data.contains("content-length: 0\r\n"));
|
assert!(!data.contains("content-length: 0\r\n"));
|
||||||
assert!(!data.contains("transfer-encoding: chunked\r\n"));
|
assert!(!data.contains("transfer-encoding: chunked\r\n"));
|
||||||
}
|
}
|
||||||
|
@ -227,10 +227,7 @@ impl Inner {
|
|||||||
self.len
|
self.len
|
||||||
}
|
}
|
||||||
|
|
||||||
fn readany(
|
fn readany(&mut self, cx: &mut Context<'_>) -> Poll<Option<Result<Bytes, PayloadError>>> {
|
||||||
&mut self,
|
|
||||||
cx: &mut Context<'_>,
|
|
||||||
) -> Poll<Option<Result<Bytes, PayloadError>>> {
|
|
||||||
if let Some(data) = self.items.pop_front() {
|
if let Some(data) = self.items.pop_front() {
|
||||||
self.len -= data.len();
|
self.len -= data.len();
|
||||||
self.need_read = self.len < MAX_BUFFER_SIZE;
|
self.need_read = self.len < MAX_BUFFER_SIZE;
|
||||||
|
@ -266,8 +266,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, S, B, X, U> ServiceFactory<(T, Option<net::SocketAddr>)>
|
impl<T, S, B, X, U> ServiceFactory<(T, Option<net::SocketAddr>)> for H1Service<T, S, B, X, U>
|
||||||
for H1Service<T, S, B, X, U>
|
|
||||||
where
|
where
|
||||||
T: AsyncRead + AsyncWrite + Unpin + 'static,
|
T: AsyncRead + AsyncWrite + Unpin + 'static,
|
||||||
|
|
||||||
@ -310,9 +309,9 @@ where
|
|||||||
|
|
||||||
let upgrade = match upgrade {
|
let upgrade = match upgrade {
|
||||||
Some(upgrade) => {
|
Some(upgrade) => {
|
||||||
let upgrade = upgrade.await.map_err(|e| {
|
let upgrade = upgrade
|
||||||
log::error!("Init http upgrade service error: {:?}", e)
|
.await
|
||||||
})?;
|
.map_err(|e| log::error!("Init http upgrade service error: {:?}", e))?;
|
||||||
Some(upgrade)
|
Some(upgrade)
|
||||||
}
|
}
|
||||||
None => None,
|
None => None,
|
||||||
@ -336,8 +335,7 @@ where
|
|||||||
/// `Service` implementation for HTTP/1 transport
|
/// `Service` implementation for HTTP/1 transport
|
||||||
pub type H1ServiceHandler<T, S, B, X, U> = HttpServiceHandler<T, S, B, X, U>;
|
pub type H1ServiceHandler<T, S, B, X, U> = HttpServiceHandler<T, S, B, X, U>;
|
||||||
|
|
||||||
impl<T, S, B, X, U> Service<(T, Option<net::SocketAddr>)>
|
impl<T, S, B, X, U> Service<(T, Option<net::SocketAddr>)> for HttpServiceHandler<T, S, B, X, U>
|
||||||
for HttpServiceHandler<T, S, B, X, U>
|
|
||||||
where
|
where
|
||||||
T: AsyncRead + AsyncWrite + Unpin,
|
T: AsyncRead + AsyncWrite + Unpin,
|
||||||
|
|
||||||
|
@ -70,15 +70,12 @@ where
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.is_write_buf_full()
|
.is_write_buf_full()
|
||||||
{
|
{
|
||||||
let next =
|
let next = match this.body.as_mut().as_pin_mut().unwrap().poll_next(cx) {
|
||||||
match this.body.as_mut().as_pin_mut().unwrap().poll_next(cx) {
|
Poll::Ready(Some(Ok(item))) => Poll::Ready(Some(item)),
|
||||||
Poll::Ready(Some(Ok(item))) => Poll::Ready(Some(item)),
|
Poll::Ready(Some(Err(err))) => return Poll::Ready(Err(err.into())),
|
||||||
Poll::Ready(Some(Err(err))) => {
|
Poll::Ready(None) => Poll::Ready(None),
|
||||||
return Poll::Ready(Err(err.into()))
|
Poll::Pending => Poll::Pending,
|
||||||
}
|
};
|
||||||
Poll::Ready(None) => Poll::Ready(None),
|
|
||||||
Poll::Pending => Poll::Pending,
|
|
||||||
};
|
|
||||||
|
|
||||||
match next {
|
match next {
|
||||||
Poll::Ready(item) => {
|
Poll::Ready(item) => {
|
||||||
@ -88,9 +85,9 @@ where
|
|||||||
let _ = this.body.take();
|
let _ = this.body.take();
|
||||||
}
|
}
|
||||||
let framed = this.framed.as_mut().as_pin_mut().unwrap();
|
let framed = this.framed.as_mut().as_pin_mut().unwrap();
|
||||||
framed.write(Message::Chunk(item)).map_err(|err| {
|
framed
|
||||||
Error::new_send_response().with_cause(err)
|
.write(Message::Chunk(item))
|
||||||
})?;
|
.map_err(|err| Error::new_send_response().with_cause(err))?;
|
||||||
}
|
}
|
||||||
Poll::Pending => body_ready = false,
|
Poll::Pending => body_ready = false,
|
||||||
}
|
}
|
||||||
|
@ -109,7 +109,7 @@ where
|
|||||||
Poll::Ready(Some((req, tx))) => {
|
Poll::Ready(Some((req, tx))) => {
|
||||||
let (parts, body) = req.into_parts();
|
let (parts, body) = req.into_parts();
|
||||||
let pl = crate::h2::Payload::new(body);
|
let pl = crate::h2::Payload::new(body);
|
||||||
let pl = Payload::<crate::payload::PayloadStream>::H2(pl);
|
let pl = Payload::H2(pl);
|
||||||
let mut req = Request::with_payload(pl);
|
let mut req = Request::with_payload(pl);
|
||||||
|
|
||||||
let head = req.head_mut();
|
let head = req.head_mut();
|
||||||
@ -160,16 +160,11 @@ where
|
|||||||
Poll::Ready(_) => {
|
Poll::Ready(_) => {
|
||||||
ping_pong.on_flight = false;
|
ping_pong.on_flight = false;
|
||||||
|
|
||||||
let dead_line =
|
let dead_line = this.config.keep_alive_expire().unwrap();
|
||||||
this.config.keep_alive_expire().unwrap();
|
|
||||||
ping_pong.timer.as_mut().reset(dead_line);
|
ping_pong.timer.as_mut().reset(dead_line);
|
||||||
}
|
}
|
||||||
Poll::Pending => {
|
Poll::Pending => {
|
||||||
return ping_pong
|
return ping_pong.timer.as_mut().poll(cx).map(|_| Ok(()))
|
||||||
.timer
|
|
||||||
.as_mut()
|
|
||||||
.poll(cx)
|
|
||||||
.map(|_| Ok(()))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -40,10 +40,7 @@ impl Payload {
|
|||||||
impl Stream for Payload {
|
impl Stream for Payload {
|
||||||
type Item = Result<Bytes, PayloadError>;
|
type Item = Result<Bytes, PayloadError>;
|
||||||
|
|
||||||
fn poll_next(
|
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
self: Pin<&mut Self>,
|
|
||||||
cx: &mut Context<'_>,
|
|
||||||
) -> Poll<Option<Self::Item>> {
|
|
||||||
let this = self.get_mut();
|
let this = self.get_mut();
|
||||||
|
|
||||||
match ready!(Pin::new(&mut this.stream).poll_data(cx)) {
|
match ready!(Pin::new(&mut this.stream).poll_data(cx)) {
|
||||||
|
@ -10,8 +10,7 @@ use std::{
|
|||||||
use actix_codec::{AsyncRead, AsyncWrite};
|
use actix_codec::{AsyncRead, AsyncWrite};
|
||||||
use actix_rt::net::TcpStream;
|
use actix_rt::net::TcpStream;
|
||||||
use actix_service::{
|
use actix_service::{
|
||||||
fn_factory, fn_service, IntoServiceFactory, Service, ServiceFactory,
|
fn_factory, fn_service, IntoServiceFactory, Service, ServiceFactory, ServiceFactoryExt as _,
|
||||||
ServiceFactoryExt as _,
|
|
||||||
};
|
};
|
||||||
use actix_utils::future::ready;
|
use actix_utils::future::ready;
|
||||||
use futures_core::{future::LocalBoxFuture, ready};
|
use futures_core::{future::LocalBoxFuture, ready};
|
||||||
@ -279,8 +278,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn call(&self, (io, addr): (T, Option<net::SocketAddr>)) -> Self::Future {
|
fn call(&self, (io, addr): (T, Option<net::SocketAddr>)) -> Self::Future {
|
||||||
let on_connect_data =
|
let on_connect_data = OnConnectData::from_io(&io, self.on_connect_ext.as_deref());
|
||||||
OnConnectData::from_io(&io, self.on_connect_ext.as_deref());
|
|
||||||
|
|
||||||
H2ServiceHandlerResponse {
|
H2ServiceHandlerResponse {
|
||||||
state: State::Handshake(
|
state: State::Handshake(
|
||||||
|
@ -6,7 +6,7 @@ use http::header::{HeaderName, InvalidHeaderName};
|
|||||||
|
|
||||||
/// Sealed trait implemented for types that can be effectively borrowed as a [`HeaderValue`].
|
/// Sealed trait implemented for types that can be effectively borrowed as a [`HeaderValue`].
|
||||||
///
|
///
|
||||||
/// [`HeaderValue`]: crate::http::HeaderValue
|
/// [`HeaderValue`]: super::HeaderValue
|
||||||
pub trait AsHeaderName: Sealed {}
|
pub trait AsHeaderName: Sealed {}
|
||||||
|
|
||||||
pub struct Seal;
|
pub struct Seal;
|
||||||
|
@ -12,7 +12,7 @@ use super::{Header, IntoHeaderValue};
|
|||||||
/// An interface for types that can be converted into a [`HeaderName`]/[`HeaderValue`] pair for
|
/// An interface for types that can be converted into a [`HeaderName`]/[`HeaderValue`] pair for
|
||||||
/// insertion into a [`HeaderMap`].
|
/// insertion into a [`HeaderMap`].
|
||||||
///
|
///
|
||||||
/// [`HeaderMap`]: crate::http::HeaderMap
|
/// [`HeaderMap`]: super::HeaderMap
|
||||||
pub trait IntoHeaderPair: Sized {
|
pub trait IntoHeaderPair: Sized {
|
||||||
type Error: Into<HttpError>;
|
type Error: Into<HttpError>;
|
||||||
|
|
||||||
|
@ -123,12 +123,11 @@ impl HeaderMap {
|
|||||||
let mut map = HeaderMap::with_capacity(capacity);
|
let mut map = HeaderMap::with_capacity(capacity);
|
||||||
map.append(first_name.clone(), first_value);
|
map.append(first_name.clone(), first_value);
|
||||||
|
|
||||||
let (map, _) =
|
let (map, _) = drain.fold((map, first_name), |(mut map, prev_name), (name, value)| {
|
||||||
drain.fold((map, first_name), |(mut map, prev_name), (name, value)| {
|
let name = name.unwrap_or(prev_name);
|
||||||
let name = name.unwrap_or(prev_name);
|
map.append(name.clone(), value);
|
||||||
map.append(name.clone(), value);
|
(map, name)
|
||||||
(map, name)
|
});
|
||||||
});
|
|
||||||
|
|
||||||
map
|
map
|
||||||
}
|
}
|
||||||
|
@ -11,22 +11,20 @@ pub use http::header::{
|
|||||||
pub use http::header::{
|
pub use http::header::{
|
||||||
ACCEPT, ACCEPT_CHARSET, ACCEPT_ENCODING, ACCEPT_LANGUAGE, ACCEPT_RANGES,
|
ACCEPT, ACCEPT_CHARSET, ACCEPT_ENCODING, ACCEPT_LANGUAGE, ACCEPT_RANGES,
|
||||||
ACCESS_CONTROL_ALLOW_CREDENTIALS, ACCESS_CONTROL_ALLOW_HEADERS,
|
ACCESS_CONTROL_ALLOW_CREDENTIALS, ACCESS_CONTROL_ALLOW_HEADERS,
|
||||||
ACCESS_CONTROL_ALLOW_METHODS, ACCESS_CONTROL_ALLOW_ORIGIN,
|
ACCESS_CONTROL_ALLOW_METHODS, ACCESS_CONTROL_ALLOW_ORIGIN, ACCESS_CONTROL_EXPOSE_HEADERS,
|
||||||
ACCESS_CONTROL_EXPOSE_HEADERS, ACCESS_CONTROL_MAX_AGE,
|
ACCESS_CONTROL_MAX_AGE, ACCESS_CONTROL_REQUEST_HEADERS, ACCESS_CONTROL_REQUEST_METHOD, AGE,
|
||||||
ACCESS_CONTROL_REQUEST_HEADERS, ACCESS_CONTROL_REQUEST_METHOD, AGE, ALLOW, ALT_SVC,
|
ALLOW, ALT_SVC, AUTHORIZATION, CACHE_CONTROL, CONNECTION, CONTENT_DISPOSITION,
|
||||||
AUTHORIZATION, CACHE_CONTROL, CONNECTION, CONTENT_DISPOSITION, CONTENT_ENCODING,
|
CONTENT_ENCODING, CONTENT_LANGUAGE, CONTENT_LENGTH, CONTENT_LOCATION, CONTENT_RANGE,
|
||||||
CONTENT_LANGUAGE, CONTENT_LENGTH, CONTENT_LOCATION, CONTENT_RANGE,
|
CONTENT_SECURITY_POLICY, CONTENT_SECURITY_POLICY_REPORT_ONLY, CONTENT_TYPE, COOKIE, DATE,
|
||||||
CONTENT_SECURITY_POLICY, CONTENT_SECURITY_POLICY_REPORT_ONLY, CONTENT_TYPE, COOKIE,
|
DNT, ETAG, EXPECT, EXPIRES, FORWARDED, FROM, HOST, IF_MATCH, IF_MODIFIED_SINCE,
|
||||||
DATE, DNT, ETAG, EXPECT, EXPIRES, FORWARDED, FROM, HOST, IF_MATCH,
|
IF_NONE_MATCH, IF_RANGE, IF_UNMODIFIED_SINCE, LAST_MODIFIED, LINK, LOCATION, MAX_FORWARDS,
|
||||||
IF_MODIFIED_SINCE, IF_NONE_MATCH, IF_RANGE, IF_UNMODIFIED_SINCE, LAST_MODIFIED,
|
ORIGIN, PRAGMA, PROXY_AUTHENTICATE, PROXY_AUTHORIZATION, PUBLIC_KEY_PINS,
|
||||||
LINK, LOCATION, MAX_FORWARDS, ORIGIN, PRAGMA, PROXY_AUTHENTICATE,
|
PUBLIC_KEY_PINS_REPORT_ONLY, RANGE, REFERER, REFERRER_POLICY, REFRESH, RETRY_AFTER,
|
||||||
PROXY_AUTHORIZATION, PUBLIC_KEY_PINS, PUBLIC_KEY_PINS_REPORT_ONLY, RANGE, REFERER,
|
SEC_WEBSOCKET_ACCEPT, SEC_WEBSOCKET_EXTENSIONS, SEC_WEBSOCKET_KEY, SEC_WEBSOCKET_PROTOCOL,
|
||||||
REFERRER_POLICY, REFRESH, RETRY_AFTER, SEC_WEBSOCKET_ACCEPT,
|
|
||||||
SEC_WEBSOCKET_EXTENSIONS, SEC_WEBSOCKET_KEY, SEC_WEBSOCKET_PROTOCOL,
|
|
||||||
SEC_WEBSOCKET_VERSION, SERVER, SET_COOKIE, STRICT_TRANSPORT_SECURITY, TE, TRAILER,
|
SEC_WEBSOCKET_VERSION, SERVER, SET_COOKIE, STRICT_TRANSPORT_SECURITY, TE, TRAILER,
|
||||||
TRANSFER_ENCODING, UPGRADE, UPGRADE_INSECURE_REQUESTS, USER_AGENT, VARY, VIA,
|
TRANSFER_ENCODING, UPGRADE, UPGRADE_INSECURE_REQUESTS, USER_AGENT, VARY, VIA, WARNING,
|
||||||
WARNING, WWW_AUTHENTICATE, X_CONTENT_TYPE_OPTIONS, X_DNS_PREFETCH_CONTROL,
|
WWW_AUTHENTICATE, X_CONTENT_TYPE_OPTIONS, X_DNS_PREFETCH_CONTROL, X_FRAME_OPTIONS,
|
||||||
X_FRAME_OPTIONS, X_XSS_PROTECTION,
|
X_XSS_PROTECTION,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{error::ParseError, HttpMessage};
|
use crate::{error::ParseError, HttpMessage};
|
||||||
@ -43,8 +41,8 @@ pub use self::into_pair::IntoHeaderPair;
|
|||||||
pub use self::into_value::IntoHeaderValue;
|
pub use self::into_value::IntoHeaderValue;
|
||||||
pub use self::map::HeaderMap;
|
pub use self::map::HeaderMap;
|
||||||
pub use self::shared::{
|
pub use self::shared::{
|
||||||
parse_extended_value, q, Charset, ContentEncoding, ExtendedValue, HttpDate,
|
parse_extended_value, q, Charset, ContentEncoding, ExtendedValue, HttpDate, LanguageTag,
|
||||||
LanguageTag, Quality, QualityItem,
|
Quality, QualityItem,
|
||||||
};
|
};
|
||||||
pub use self::utils::{
|
pub use self::utils::{
|
||||||
fmt_comma_delimited, from_comma_delimited, from_one_raw_str, http_percent_encode,
|
fmt_comma_delimited, from_comma_delimited, from_one_raw_str, http_percent_encode,
|
||||||
|
@ -63,9 +63,7 @@ pub struct ExtendedValue {
|
|||||||
/// [RFC 2231 §7]: https://datatracker.ietf.org/doc/html/rfc2231#section-7
|
/// [RFC 2231 §7]: https://datatracker.ietf.org/doc/html/rfc2231#section-7
|
||||||
/// [RFC 2978 §2.3]: https://datatracker.ietf.org/doc/html/rfc2978#section-2.3
|
/// [RFC 2978 §2.3]: https://datatracker.ietf.org/doc/html/rfc2978#section-2.3
|
||||||
/// [RFC 3986 §2.1]: https://datatracker.ietf.org/doc/html/rfc5646#section-2.1
|
/// [RFC 3986 §2.1]: https://datatracker.ietf.org/doc/html/rfc5646#section-2.1
|
||||||
pub fn parse_extended_value(
|
pub fn parse_extended_value(val: &str) -> Result<ExtendedValue, crate::error::ParseError> {
|
||||||
val: &str,
|
|
||||||
) -> Result<ExtendedValue, crate::error::ParseError> {
|
|
||||||
// Break into three pieces separated by the single-quote character
|
// Break into three pieces separated by the single-quote character
|
||||||
let mut parts = val.splitn(3, '\'');
|
let mut parts = val.splitn(3, '\'');
|
||||||
|
|
||||||
@ -100,8 +98,7 @@ pub fn parse_extended_value(
|
|||||||
|
|
||||||
impl fmt::Display for ExtendedValue {
|
impl fmt::Display for ExtendedValue {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
let encoded_value =
|
let encoded_value = percent_encoding::percent_encode(&self.value[..], HTTP_VALUE);
|
||||||
percent_encoding::percent_encode(&self.value[..], HTTP_VALUE);
|
|
||||||
if let Some(ref lang) = self.language_tag {
|
if let Some(ref lang) = self.language_tag {
|
||||||
write!(f, "{}'{}'{}", self.charset, lang, encoded_value)
|
write!(f, "{}'{}'{}", self.charset, lang, encoded_value)
|
||||||
} else {
|
} else {
|
||||||
@ -143,8 +140,8 @@ mod tests {
|
|||||||
assert!(extended_value.language_tag.is_none());
|
assert!(extended_value.language_tag.is_none());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
vec![
|
vec![
|
||||||
194, 163, b' ', b'a', b'n', b'd', b' ', 226, 130, 172, b' ', b'r', b'a',
|
194, 163, b' ', b'a', b'n', b'd', b' ', 226, 130, 172, b' ', b'r', b'a', b't',
|
||||||
b't', b'e', b's',
|
b'e', b's',
|
||||||
],
|
],
|
||||||
extended_value.value
|
extended_value.value
|
||||||
);
|
);
|
||||||
@ -185,8 +182,8 @@ mod tests {
|
|||||||
charset: Charset::Ext("UTF-8".to_string()),
|
charset: Charset::Ext("UTF-8".to_string()),
|
||||||
language_tag: None,
|
language_tag: None,
|
||||||
value: vec![
|
value: vec![
|
||||||
194, 163, b' ', b'a', b'n', b'd', b' ', 226, 130, 172, b' ', b'r', b'a',
|
194, 163, b' ', b'a', b'n', b'd', b' ', 226, 130, 172, b' ', b'r', b'a', b't',
|
||||||
b't', b'e', b's',
|
b'e', b's',
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -4,8 +4,7 @@ use bytes::BytesMut;
|
|||||||
use http::header::{HeaderValue, InvalidHeaderValue};
|
use http::header::{HeaderValue, InvalidHeaderValue};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::DATE_VALUE_LENGTH, error::ParseError, header::IntoHeaderValue,
|
config::DATE_VALUE_LENGTH, error::ParseError, header::IntoHeaderValue, helpers::MutWriter,
|
||||||
helpers::MutWriter,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A timestamp with HTTP-style formatting and parsing.
|
/// A timestamp with HTTP-style formatting and parsing.
|
||||||
|
@ -120,8 +120,7 @@ impl<T: str::FromStr> str::FromStr for QualityItem<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let q_value = q_val.parse::<f32>().map_err(|_| ParseError::Header)?;
|
let q_value = q_val.parse::<f32>().map_err(|_| ParseError::Header)?;
|
||||||
let q_value =
|
let q_value = Quality::try_from(q_value).map_err(|_| ParseError::Header)?;
|
||||||
Quality::try_from(q_value).map_err(|_| ParseError::Header)?;
|
|
||||||
|
|
||||||
quality = q_value;
|
quality = q_value;
|
||||||
raw_item = val;
|
raw_item = val;
|
||||||
|
@ -14,7 +14,8 @@
|
|||||||
//! [rustls]: https://crates.io/crates/rustls
|
//! [rustls]: https://crates.io/crates/rustls
|
||||||
//! [trust-dns]: https://crates.io/crates/trust-dns
|
//! [trust-dns]: https://crates.io/crates/trust-dns
|
||||||
|
|
||||||
#![deny(rust_2018_idioms, nonstandard_style, clippy::uninit_assumed_init)]
|
#![deny(rust_2018_idioms, nonstandard_style)]
|
||||||
|
#![warn(future_incompatible)]
|
||||||
#![allow(
|
#![allow(
|
||||||
clippy::type_complexity,
|
clippy::type_complexity,
|
||||||
clippy::too_many_arguments,
|
clippy::too_many_arguments,
|
||||||
@ -87,10 +88,7 @@ pub(crate) struct OnConnectData(Option<Extensions>);
|
|||||||
|
|
||||||
impl OnConnectData {
|
impl OnConnectData {
|
||||||
/// Construct by calling the on-connect callback with the underlying transport I/O.
|
/// Construct by calling the on-connect callback with the underlying transport I/O.
|
||||||
pub(crate) fn from_io<T>(
|
pub(crate) fn from_io<T>(io: &T, on_connect_ext: Option<&ConnectCallback<T>>) -> Self {
|
||||||
io: &T,
|
|
||||||
on_connect_ext: Option<&ConnectCallback<T>>,
|
|
||||||
) -> Self {
|
|
||||||
let ext = on_connect_ext.map(|handler| {
|
let ext = on_connect_ext.map(|handler| {
|
||||||
let mut extensions = Extensions::default();
|
let mut extensions = Extensions::default();
|
||||||
handler(io, &mut extensions);
|
handler(io, &mut extensions);
|
||||||
|
@ -56,10 +56,7 @@ where
|
|||||||
type Item = Result<Bytes, PayloadError>;
|
type Item = Result<Bytes, PayloadError>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn poll_next(
|
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
self: Pin<&mut Self>,
|
|
||||||
cx: &mut Context<'_>,
|
|
||||||
) -> Poll<Option<Self::Item>> {
|
|
||||||
match self.get_mut() {
|
match self.get_mut() {
|
||||||
Payload::None => Poll::Ready(None),
|
Payload::None => Poll::Ready(None),
|
||||||
Payload::H1(ref mut pl) => pl.readany(cx),
|
Payload::H1(ref mut pl) => pl.readany(cx),
|
||||||
|
@ -231,9 +231,7 @@ impl<B: Default> Default for Response<B> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I: Into<Response<BoxBody>>, E: Into<Error>> From<Result<I, E>>
|
impl<I: Into<Response<BoxBody>>, E: Into<Error>> From<Result<I, E>> for Response<BoxBody> {
|
||||||
for Response<BoxBody>
|
|
||||||
{
|
|
||||||
fn from(res: Result<I, E>) -> Self {
|
fn from(res: Result<I, E>) -> Self {
|
||||||
match res {
|
match res {
|
||||||
Ok(val) => val.into(),
|
Ok(val) => val.into(),
|
||||||
|
@ -47,7 +47,8 @@ impl ResponseBuilder {
|
|||||||
/// Create response builder
|
/// Create response builder
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
// /// use actix_http::{Response, ResponseBuilder, StatusCode};, / ``
|
/// ```
|
||||||
|
/// use actix_http::{Response, ResponseBuilder, StatusCode};
|
||||||
/// let res: Response<_> = ResponseBuilder::default().finish();
|
/// let res: Response<_> = ResponseBuilder::default().finish();
|
||||||
/// assert_eq!(res.status(), StatusCode::OK);
|
/// assert_eq!(res.status(), StatusCode::OK);
|
||||||
/// ```
|
/// ```
|
||||||
@ -62,7 +63,8 @@ impl ResponseBuilder {
|
|||||||
/// Set HTTP status code of this response.
|
/// Set HTTP status code of this response.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
// /// use actix_http::{ResponseBuilder, StatusCode};, / ``
|
/// ```
|
||||||
|
/// use actix_http::{ResponseBuilder, StatusCode};
|
||||||
/// let res = ResponseBuilder::default().status(StatusCode::NOT_FOUND).finish();
|
/// let res = ResponseBuilder::default().status(StatusCode::NOT_FOUND).finish();
|
||||||
/// assert_eq!(res.status(), StatusCode::NOT_FOUND);
|
/// assert_eq!(res.status(), StatusCode::NOT_FOUND);
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -161,11 +161,7 @@ where
|
|||||||
X::Error: Into<Response<BoxBody>>,
|
X::Error: Into<Response<BoxBody>>,
|
||||||
X::InitError: fmt::Debug,
|
X::InitError: fmt::Debug,
|
||||||
|
|
||||||
U: ServiceFactory<
|
U: ServiceFactory<(Request, Framed<TcpStream, h1::Codec>), Config = (), Response = ()>,
|
||||||
(Request, Framed<TcpStream, h1::Codec>),
|
|
||||||
Config = (),
|
|
||||||
Response = (),
|
|
||||||
>,
|
|
||||||
U::Future: 'static,
|
U::Future: 'static,
|
||||||
U::Error: fmt::Display + Into<Response<BoxBody>>,
|
U::Error: fmt::Display + Into<Response<BoxBody>>,
|
||||||
U::InitError: fmt::Debug,
|
U::InitError: fmt::Debug,
|
||||||
@ -381,9 +377,9 @@ where
|
|||||||
|
|
||||||
let upgrade = match upgrade {
|
let upgrade = match upgrade {
|
||||||
Some(upgrade) => {
|
Some(upgrade) => {
|
||||||
let upgrade = upgrade.await.map_err(|e| {
|
let upgrade = upgrade
|
||||||
log::error!("Init http upgrade service error: {:?}", e)
|
.await
|
||||||
})?;
|
.map_err(|e| log::error!("Init http upgrade service error: {:?}", e))?;
|
||||||
Some(upgrade)
|
Some(upgrade)
|
||||||
}
|
}
|
||||||
None => None,
|
None => None,
|
||||||
@ -626,8 +622,7 @@ where
|
|||||||
StateProj::H2Handshake { handshake: data } => {
|
StateProj::H2Handshake { handshake: data } => {
|
||||||
match ready!(Pin::new(&mut data.as_mut().unwrap().0).poll(cx)) {
|
match ready!(Pin::new(&mut data.as_mut().unwrap().0).poll(cx)) {
|
||||||
Ok((conn, timer)) => {
|
Ok((conn, timer)) => {
|
||||||
let (_, config, flow, conn_data, peer_addr) =
|
let (_, config, flow, conn_data, peer_addr) = data.take().unwrap();
|
||||||
data.take().unwrap();
|
|
||||||
|
|
||||||
self.as_mut().project().state.set(State::H2 {
|
self.as_mut().project().state.set(State::H2 {
|
||||||
dispatcher: h2::Dispatcher::new(
|
dispatcher: h2::Dispatcher::new(
|
||||||
|
@ -224,9 +224,7 @@ impl Decoder for Codec {
|
|||||||
OpCode::Continue => {
|
OpCode::Continue => {
|
||||||
if self.flags.contains(Flags::CONTINUATION) {
|
if self.flags.contains(Flags::CONTINUATION) {
|
||||||
Ok(Some(Frame::Continuation(Item::Continue(
|
Ok(Some(Frame::Continuation(Item::Continue(
|
||||||
payload
|
payload.map(|pl| pl.freeze()).unwrap_or_else(Bytes::new),
|
||||||
.map(|pl| pl.freeze())
|
|
||||||
.unwrap_or_else(Bytes::new),
|
|
||||||
))))
|
))))
|
||||||
} else {
|
} else {
|
||||||
Err(ProtocolError::ContinuationNotStarted)
|
Err(ProtocolError::ContinuationNotStarted)
|
||||||
@ -236,9 +234,7 @@ impl Decoder for Codec {
|
|||||||
if !self.flags.contains(Flags::CONTINUATION) {
|
if !self.flags.contains(Flags::CONTINUATION) {
|
||||||
self.flags.insert(Flags::CONTINUATION);
|
self.flags.insert(Flags::CONTINUATION);
|
||||||
Ok(Some(Frame::Continuation(Item::FirstBinary(
|
Ok(Some(Frame::Continuation(Item::FirstBinary(
|
||||||
payload
|
payload.map(|pl| pl.freeze()).unwrap_or_else(Bytes::new),
|
||||||
.map(|pl| pl.freeze())
|
|
||||||
.unwrap_or_else(Bytes::new),
|
|
||||||
))))
|
))))
|
||||||
} else {
|
} else {
|
||||||
Err(ProtocolError::ContinuationStarted)
|
Err(ProtocolError::ContinuationStarted)
|
||||||
@ -248,9 +244,7 @@ impl Decoder for Codec {
|
|||||||
if !self.flags.contains(Flags::CONTINUATION) {
|
if !self.flags.contains(Flags::CONTINUATION) {
|
||||||
self.flags.insert(Flags::CONTINUATION);
|
self.flags.insert(Flags::CONTINUATION);
|
||||||
Ok(Some(Frame::Continuation(Item::FirstText(
|
Ok(Some(Frame::Continuation(Item::FirstText(
|
||||||
payload
|
payload.map(|pl| pl.freeze()).unwrap_or_else(Bytes::new),
|
||||||
.map(|pl| pl.freeze())
|
|
||||||
.unwrap_or_else(Bytes::new),
|
|
||||||
))))
|
))))
|
||||||
} else {
|
} else {
|
||||||
Err(ProtocolError::ContinuationStarted)
|
Err(ProtocolError::ContinuationStarted)
|
||||||
|
@ -304,8 +304,7 @@ mod inner {
|
|||||||
let item = match this.framed.next_item(cx) {
|
let item = match this.framed.next_item(cx) {
|
||||||
Poll::Ready(Some(Ok(el))) => el,
|
Poll::Ready(Some(Ok(el))) => el,
|
||||||
Poll::Ready(Some(Err(err))) => {
|
Poll::Ready(Some(Err(err))) => {
|
||||||
*this.state =
|
*this.state = State::FramedError(DispatcherError::Decoder(err));
|
||||||
State::FramedError(DispatcherError::Decoder(err));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
Poll::Pending => return false,
|
Poll::Pending => return false,
|
||||||
@ -348,8 +347,7 @@ mod inner {
|
|||||||
match Pin::new(&mut this.rx).poll_next(cx) {
|
match Pin::new(&mut this.rx).poll_next(cx) {
|
||||||
Poll::Ready(Some(Ok(Message::Item(msg)))) => {
|
Poll::Ready(Some(Ok(Message::Item(msg)))) => {
|
||||||
if let Err(err) = this.framed.as_mut().write(msg) {
|
if let Err(err) = this.framed.as_mut().write(msg) {
|
||||||
*this.state =
|
*this.state = State::FramedError(DispatcherError::Encoder(err));
|
||||||
State::FramedError(DispatcherError::Encoder(err));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -371,8 +369,7 @@ mod inner {
|
|||||||
Poll::Ready(Ok(_)) => {}
|
Poll::Ready(Ok(_)) => {}
|
||||||
Poll::Ready(Err(err)) => {
|
Poll::Ready(Err(err)) => {
|
||||||
debug!("Error sending data: {:?}", err);
|
debug!("Error sending data: {:?}", err);
|
||||||
*this.state =
|
*this.state = State::FramedError(DispatcherError::Encoder(err));
|
||||||
State::FramedError(DispatcherError::Encoder(err));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -432,9 +429,7 @@ mod inner {
|
|||||||
Poll::Ready(Ok(()))
|
Poll::Ready(Ok(()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
State::FramedError(_) => {
|
State::FramedError(_) => Poll::Ready(Err(this.state.take_framed_error())),
|
||||||
Poll::Ready(Err(this.state.take_framed_error()))
|
|
||||||
}
|
|
||||||
State::Stopping => Poll::Ready(Ok(())),
|
State::Stopping => Poll::Ready(Ok(())),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -16,8 +16,7 @@ impl Parser {
|
|||||||
src: &[u8],
|
src: &[u8],
|
||||||
server: bool,
|
server: bool,
|
||||||
max_size: usize,
|
max_size: usize,
|
||||||
) -> Result<Option<(usize, bool, OpCode, usize, Option<[u8; 4]>)>, ProtocolError>
|
) -> Result<Option<(usize, bool, OpCode, usize, Option<[u8; 4]>)>, ProtocolError> {
|
||||||
{
|
|
||||||
let chunk_len = src.len();
|
let chunk_len = src.len();
|
||||||
|
|
||||||
let mut idx = 2;
|
let mut idx = 2;
|
||||||
@ -228,15 +227,11 @@ mod tests {
|
|||||||
payload: Bytes,
|
payload: Bytes,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_none(
|
fn is_none(frm: &Result<Option<(bool, OpCode, Option<BytesMut>)>, ProtocolError>) -> bool {
|
||||||
frm: &Result<Option<(bool, OpCode, Option<BytesMut>)>, ProtocolError>,
|
|
||||||
) -> bool {
|
|
||||||
matches!(*frm, Ok(None))
|
matches!(*frm, Ok(None))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract(
|
fn extract(frm: Result<Option<(bool, OpCode, Option<BytesMut>)>, ProtocolError>) -> F {
|
||||||
frm: Result<Option<(bool, OpCode, Option<BytesMut>)>, ProtocolError>,
|
|
||||||
) -> F {
|
|
||||||
match frm {
|
match frm {
|
||||||
Ok(Some((finished, opcode, payload))) => F {
|
Ok(Some((finished, opcode, payload))) => F {
|
||||||
finished,
|
finished,
|
||||||
|
@ -54,8 +54,8 @@ mod tests {
|
|||||||
let mask = [0x6d, 0xb6, 0xb2, 0x80];
|
let mask = [0x6d, 0xb6, 0xb2, 0x80];
|
||||||
|
|
||||||
let unmasked = vec![
|
let unmasked = vec![
|
||||||
0xf3, 0x00, 0x01, 0x02, 0x03, 0x80, 0x81, 0x82, 0xff, 0xfe, 0x00, 0x17,
|
0xf3, 0x00, 0x01, 0x02, 0x03, 0x80, 0x81, 0x82, 0xff, 0xfe, 0x00, 0x17, 0x74, 0xf9,
|
||||||
0x74, 0xf9, 0x12, 0x03,
|
0x12, 0x03,
|
||||||
];
|
];
|
||||||
|
|
||||||
// Check masking with proper alignment.
|
// Check masking with proper alignment.
|
||||||
@ -85,8 +85,8 @@ mod tests {
|
|||||||
fn test_apply_mask() {
|
fn test_apply_mask() {
|
||||||
let mask = [0x6d, 0xb6, 0xb2, 0x80];
|
let mask = [0x6d, 0xb6, 0xb2, 0x80];
|
||||||
let unmasked = vec![
|
let unmasked = vec![
|
||||||
0xf3, 0x00, 0x01, 0x02, 0x03, 0x80, 0x81, 0x82, 0xff, 0xfe, 0x00, 0x17,
|
0xf3, 0x00, 0x01, 0x02, 0x03, 0x80, 0x81, 0x82, 0xff, 0xfe, 0x00, 0x17, 0x74, 0xf9,
|
||||||
0x74, 0xf9, 0x12, 0x03,
|
0x12, 0x03,
|
||||||
];
|
];
|
||||||
|
|
||||||
for data_len in 0..=unmasked.len() {
|
for data_len in 0..=unmasked.len() {
|
||||||
|
@ -9,9 +9,7 @@ use derive_more::{Display, Error, From};
|
|||||||
use http::{header, Method, StatusCode};
|
use http::{header, Method, StatusCode};
|
||||||
|
|
||||||
use crate::body::BoxBody;
|
use crate::body::BoxBody;
|
||||||
use crate::{
|
use crate::{header::HeaderValue, message::RequestHead, response::Response, ResponseBuilder};
|
||||||
header::HeaderValue, message::RequestHead, response::Response, ResponseBuilder,
|
|
||||||
};
|
|
||||||
|
|
||||||
mod codec;
|
mod codec;
|
||||||
mod dispatcher;
|
mod dispatcher;
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
use std::convert::Infallible;
|
use std::convert::Infallible;
|
||||||
|
|
||||||
use actix_http::{
|
use actix_http::{body::BoxBody, HttpMessage, HttpService, Request, Response, StatusCode};
|
||||||
body::BoxBody, HttpMessage, HttpService, Request, Response, StatusCode,
|
|
||||||
};
|
|
||||||
use actix_http_test::test_server;
|
use actix_http_test::test_server;
|
||||||
use actix_service::ServiceFactoryExt;
|
use actix_service::ServiceFactoryExt;
|
||||||
use actix_utils::future;
|
use actix_utils::future;
|
||||||
|
@ -170,10 +170,11 @@ async fn test_h2_headers() {
|
|||||||
|
|
||||||
let mut srv = test_server(move || {
|
let mut srv = test_server(move || {
|
||||||
let data = data.clone();
|
let data = data.clone();
|
||||||
HttpService::build().h2(move |_| {
|
HttpService::build()
|
||||||
let mut builder = Response::build(StatusCode::OK);
|
.h2(move |_| {
|
||||||
for idx in 0..90 {
|
let mut builder = Response::build(StatusCode::OK);
|
||||||
builder.insert_header(
|
for idx in 0..90 {
|
||||||
|
builder.insert_header(
|
||||||
(format!("X-TEST-{}", idx).as_str(),
|
(format!("X-TEST-{}", idx).as_str(),
|
||||||
"TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
"TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
||||||
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
||||||
@ -189,12 +190,13 @@ async fn test_h2_headers() {
|
|||||||
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
||||||
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST ",
|
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST ",
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
ok::<_, Infallible>(builder.body(data.clone()))
|
ok::<_, Infallible>(builder.body(data.clone()))
|
||||||
})
|
})
|
||||||
.openssl(tls_config())
|
.openssl(tls_config())
|
||||||
.map_err(|_| ())
|
.map_err(|_| ())
|
||||||
}).await;
|
})
|
||||||
|
.await;
|
||||||
|
|
||||||
let response = srv.sget("/").send().await.unwrap();
|
let response = srv.sget("/").send().await.unwrap();
|
||||||
assert!(response.status().is_success());
|
assert!(response.status().is_success());
|
||||||
@ -315,9 +317,8 @@ async fn test_h2_body_length() {
|
|||||||
let mut srv = test_server(move || {
|
let mut srv = test_server(move || {
|
||||||
HttpService::build()
|
HttpService::build()
|
||||||
.h2(|_| async {
|
.h2(|_| async {
|
||||||
let body = once(async {
|
let body =
|
||||||
Ok::<_, Infallible>(Bytes::from_static(STR.as_ref()))
|
once(async { Ok::<_, Infallible>(Bytes::from_static(STR.as_ref())) });
|
||||||
});
|
|
||||||
|
|
||||||
Ok::<_, Infallible>(
|
Ok::<_, Infallible>(
|
||||||
Response::ok().set_body(SizedStream::new(STR.len() as u64, body)),
|
Response::ok().set_body(SizedStream::new(STR.len() as u64, body)),
|
||||||
|
@ -238,10 +238,11 @@ async fn test_h2_headers() {
|
|||||||
|
|
||||||
let mut srv = test_server(move || {
|
let mut srv = test_server(move || {
|
||||||
let data = data.clone();
|
let data = data.clone();
|
||||||
HttpService::build().h2(move |_| {
|
HttpService::build()
|
||||||
let mut config = Response::build(StatusCode::OK);
|
.h2(move |_| {
|
||||||
for idx in 0..90 {
|
let mut config = Response::build(StatusCode::OK);
|
||||||
config.insert_header((
|
for idx in 0..90 {
|
||||||
|
config.insert_header((
|
||||||
format!("X-TEST-{}", idx).as_str(),
|
format!("X-TEST-{}", idx).as_str(),
|
||||||
"TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
"TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
||||||
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
||||||
@ -257,11 +258,12 @@ async fn test_h2_headers() {
|
|||||||
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
||||||
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST ",
|
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST ",
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
ok::<_, Infallible>(config.body(data.clone()))
|
ok::<_, Infallible>(config.body(data.clone()))
|
||||||
})
|
})
|
||||||
.rustls(tls_config())
|
.rustls(tls_config())
|
||||||
}).await;
|
})
|
||||||
|
.await;
|
||||||
|
|
||||||
let response = srv.sget("/").send().await.unwrap();
|
let response = srv.sget("/").send().await.unwrap();
|
||||||
assert!(response.status().is_success());
|
assert!(response.status().is_success());
|
||||||
|
@ -154,9 +154,7 @@ async fn test_chunked_payload() {
|
|||||||
})
|
})
|
||||||
.fold(0usize, |acc, chunk| ready(acc + chunk.len()))
|
.fold(0usize, |acc, chunk| ready(acc + chunk.len()))
|
||||||
.map(|req_size| {
|
.map(|req_size| {
|
||||||
Ok::<_, Error>(
|
Ok::<_, Error>(Response::ok().set_body(format!("size={}", req_size)))
|
||||||
Response::ok().set_body(format!("size={}", req_size)),
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
}))
|
}))
|
||||||
.tcp()
|
.tcp()
|
||||||
@ -165,8 +163,7 @@ async fn test_chunked_payload() {
|
|||||||
|
|
||||||
let returned_size = {
|
let returned_size = {
|
||||||
let mut stream = net::TcpStream::connect(srv.addr()).unwrap();
|
let mut stream = net::TcpStream::connect(srv.addr()).unwrap();
|
||||||
let _ = stream
|
let _ = stream.write_all(b"POST /test HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n");
|
||||||
.write_all(b"POST /test HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n");
|
|
||||||
|
|
||||||
for chunk_size in chunk_sizes.iter() {
|
for chunk_size in chunk_sizes.iter() {
|
||||||
let mut bytes = Vec::new();
|
let mut bytes = Vec::new();
|
||||||
@ -293,8 +290,7 @@ async fn test_http1_keepalive_close() {
|
|||||||
.await;
|
.await;
|
||||||
|
|
||||||
let mut stream = net::TcpStream::connect(srv.addr()).unwrap();
|
let mut stream = net::TcpStream::connect(srv.addr()).unwrap();
|
||||||
let _ =
|
let _ = stream.write_all(b"GET /test/tests/test HTTP/1.1\r\nconnection: close\r\n\r\n");
|
||||||
stream.write_all(b"GET /test/tests/test HTTP/1.1\r\nconnection: close\r\n\r\n");
|
|
||||||
let mut data = vec![0; 1024];
|
let mut data = vec![0; 1024];
|
||||||
let _ = stream.read(&mut data);
|
let _ = stream.read(&mut data);
|
||||||
assert_eq!(&data[..17], b"HTTP/1.1 200 OK\r\n");
|
assert_eq!(&data[..17], b"HTTP/1.1 200 OK\r\n");
|
||||||
@ -338,8 +334,8 @@ async fn test_http10_keepalive() {
|
|||||||
.await;
|
.await;
|
||||||
|
|
||||||
let mut stream = net::TcpStream::connect(srv.addr()).unwrap();
|
let mut stream = net::TcpStream::connect(srv.addr()).unwrap();
|
||||||
let _ = stream
|
let _ =
|
||||||
.write_all(b"GET /test/tests/test HTTP/1.0\r\nconnection: keep-alive\r\n\r\n");
|
stream.write_all(b"GET /test/tests/test HTTP/1.0\r\nconnection: keep-alive\r\n\r\n");
|
||||||
let mut data = vec![0; 1024];
|
let mut data = vec![0; 1024];
|
||||||
let _ = stream.read(&mut data);
|
let _ = stream.read(&mut data);
|
||||||
assert_eq!(&data[..17], b"HTTP/1.0 200 OK\r\n");
|
assert_eq!(&data[..17], b"HTTP/1.0 200 OK\r\n");
|
||||||
@ -436,10 +432,11 @@ async fn test_h1_headers() {
|
|||||||
|
|
||||||
let mut srv = test_server(move || {
|
let mut srv = test_server(move || {
|
||||||
let data = data.clone();
|
let data = data.clone();
|
||||||
HttpService::build().h1(move |_| {
|
HttpService::build()
|
||||||
let mut builder = Response::build(StatusCode::OK);
|
.h1(move |_| {
|
||||||
for idx in 0..90 {
|
let mut builder = Response::build(StatusCode::OK);
|
||||||
builder.insert_header((
|
for idx in 0..90 {
|
||||||
|
builder.insert_header((
|
||||||
format!("X-TEST-{}", idx).as_str(),
|
format!("X-TEST-{}", idx).as_str(),
|
||||||
"TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
"TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
||||||
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
||||||
@ -455,10 +452,12 @@ async fn test_h1_headers() {
|
|||||||
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
||||||
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST ",
|
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST ",
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
ok::<_, Infallible>(builder.body(data.clone()))
|
ok::<_, Infallible>(builder.body(data.clone()))
|
||||||
}).tcp()
|
})
|
||||||
}).await;
|
.tcp()
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
|
||||||
let response = srv.get("/").send().await.unwrap();
|
let response = srv.get("/").send().await.unwrap();
|
||||||
assert!(response.status().is_success());
|
assert!(response.status().is_success());
|
||||||
@ -655,9 +654,7 @@ async fn test_h1_body_chunked_implicit() {
|
|||||||
HttpService::build()
|
HttpService::build()
|
||||||
.h1(|_| {
|
.h1(|_| {
|
||||||
let body = once(ok::<_, Error>(Bytes::from_static(STR.as_ref())));
|
let body = once(ok::<_, Error>(Bytes::from_static(STR.as_ref())));
|
||||||
ok::<_, Infallible>(
|
ok::<_, Infallible>(Response::build(StatusCode::OK).body(BodyStream::new(body)))
|
||||||
Response::build(StatusCode::OK).body(BodyStream::new(body)),
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
.tcp()
|
.tcp()
|
||||||
})
|
})
|
||||||
@ -776,10 +773,8 @@ async fn test_not_modified_spec_h1() {
|
|||||||
.h1(|req: Request| {
|
.h1(|req: Request| {
|
||||||
let res: Response<BoxBody> = match req.path() {
|
let res: Response<BoxBody> = match req.path() {
|
||||||
// with no content-length
|
// with no content-length
|
||||||
"/none" => {
|
"/none" => Response::with_body(StatusCode::NOT_MODIFIED, body::None::new())
|
||||||
Response::with_body(StatusCode::NOT_MODIFIED, body::None::new())
|
.map_into_boxed_body(),
|
||||||
.map_into_boxed_body()
|
|
||||||
}
|
|
||||||
|
|
||||||
// with no content-length
|
// with no content-length
|
||||||
"/body" => Response::with_body(StatusCode::NOT_MODIFIED, "1234")
|
"/body" => Response::with_body(StatusCode::NOT_MODIFIED, "1234")
|
||||||
@ -787,10 +782,8 @@ async fn test_not_modified_spec_h1() {
|
|||||||
|
|
||||||
// with manual content-length header and specific None body
|
// with manual content-length header and specific None body
|
||||||
"/cl-none" => {
|
"/cl-none" => {
|
||||||
let mut res = Response::with_body(
|
let mut res =
|
||||||
StatusCode::NOT_MODIFIED,
|
Response::with_body(StatusCode::NOT_MODIFIED, body::None::new());
|
||||||
body::None::new(),
|
|
||||||
);
|
|
||||||
res.headers_mut()
|
res.headers_mut()
|
||||||
.insert(CL.clone(), header::HeaderValue::from_static("24"));
|
.insert(CL.clone(), header::HeaderValue::from_static("24"));
|
||||||
res.map_into_boxed_body()
|
res.map_into_boxed_body()
|
||||||
@ -798,8 +791,7 @@ async fn test_not_modified_spec_h1() {
|
|||||||
|
|
||||||
// with manual content-length header and ignore-able body
|
// with manual content-length header and ignore-able body
|
||||||
"/cl-body" => {
|
"/cl-body" => {
|
||||||
let mut res =
|
let mut res = Response::with_body(StatusCode::NOT_MODIFIED, "1234");
|
||||||
Response::with_body(StatusCode::NOT_MODIFIED, "1234");
|
|
||||||
res.headers_mut()
|
res.headers_mut()
|
||||||
.insert(CL.clone(), header::HeaderValue::from_static("4"));
|
.insert(CL.clone(), header::HeaderValue::from_static("4"));
|
||||||
res.map_into_boxed_body()
|
res.map_into_boxed_body()
|
||||||
|
@ -56,8 +56,9 @@ impl From<WsServiceError> for Response<BoxBody> {
|
|||||||
WsServiceError::Http(err) => err.into(),
|
WsServiceError::Http(err) => err.into(),
|
||||||
WsServiceError::Ws(err) => err.into(),
|
WsServiceError::Ws(err) => err.into(),
|
||||||
WsServiceError::Io(_err) => unreachable!(),
|
WsServiceError::Io(_err) => unreachable!(),
|
||||||
WsServiceError::Dispatcher => Response::internal_server_error()
|
WsServiceError::Dispatcher => {
|
||||||
.set_body(BoxBody::new(format!("{}", err))),
|
Response::internal_server_error().set_body(BoxBody::new(format!("{}", err)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -97,9 +98,7 @@ where
|
|||||||
async fn service(msg: Frame) -> Result<Message, Error> {
|
async fn service(msg: Frame) -> Result<Message, Error> {
|
||||||
let msg = match msg {
|
let msg = match msg {
|
||||||
Frame::Ping(msg) => Message::Pong(msg),
|
Frame::Ping(msg) => Message::Pong(msg),
|
||||||
Frame::Text(text) => {
|
Frame::Text(text) => Message::Text(String::from_utf8_lossy(&text).into_owned().into()),
|
||||||
Message::Text(String::from_utf8_lossy(&text).into_owned().into())
|
|
||||||
}
|
|
||||||
Frame::Binary(bin) => Message::Binary(bin),
|
Frame::Binary(bin) => Message::Binary(bin),
|
||||||
Frame::Continuation(item) => Message::Continuation(item),
|
Frame::Continuation(item) => Message::Continuation(item),
|
||||||
Frame::Close(reason) => Message::Close(reason),
|
Frame::Close(reason) => Message::Close(reason),
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
//! Multipart form support for Actix Web.
|
//! Multipart form support for Actix Web.
|
||||||
|
|
||||||
#![deny(rust_2018_idioms)]
|
#![deny(rust_2018_idioms, nonstandard_style)]
|
||||||
|
#![warn(future_incompatible)]
|
||||||
#![allow(clippy::borrow_interior_mutable_const)]
|
#![allow(clippy::borrow_interior_mutable_const)]
|
||||||
|
|
||||||
mod error;
|
mod error;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
//! Resource path matching and router.
|
//! Resource path matching and router.
|
||||||
|
|
||||||
#![deny(rust_2018_idioms, nonstandard_style)]
|
#![deny(rust_2018_idioms, nonstandard_style)]
|
||||||
|
#![warn(future_incompatible)]
|
||||||
#![doc(html_logo_url = "https://actix.rs/img/logo.png")]
|
#![doc(html_logo_url = "https://actix.rs/img/logo.png")]
|
||||||
#![doc(html_favicon_url = "https://actix.rs/favicon.ico")]
|
#![doc(html_favicon_url = "https://actix.rs/favicon.ico")]
|
||||||
|
|
||||||
|
@ -168,7 +168,7 @@ const REGEX_FLAGS: &str = "(?s-m)";
|
|||||||
/// extracted in the same way as non-tail dynamic segments.
|
/// extracted in the same way as non-tail dynamic segments.
|
||||||
///
|
///
|
||||||
/// ## Examples
|
/// ## Examples
|
||||||
/// ```rust
|
/// ```
|
||||||
/// # use actix_router::{Path, ResourceDef};
|
/// # use actix_router::{Path, ResourceDef};
|
||||||
/// let resource = ResourceDef::new("/blob/{tail}*");
|
/// let resource = ResourceDef::new("/blob/{tail}*");
|
||||||
/// assert!(resource.is_match("/blob/HEAD/Cargo.toml"));
|
/// assert!(resource.is_match("/blob/HEAD/Cargo.toml"));
|
||||||
@ -191,7 +191,7 @@ const REGEX_FLAGS: &str = "(?s-m)";
|
|||||||
/// expectations in the router using these definitions and cause runtime panics.
|
/// expectations in the router using these definitions and cause runtime panics.
|
||||||
///
|
///
|
||||||
/// ## Examples
|
/// ## Examples
|
||||||
/// ```rust
|
/// ```
|
||||||
/// # use actix_router::ResourceDef;
|
/// # use actix_router::ResourceDef;
|
||||||
/// let resource = ResourceDef::new(["/home", "/index"]);
|
/// let resource = ResourceDef::new(["/home", "/index"]);
|
||||||
/// assert!(resource.is_match("/home"));
|
/// assert!(resource.is_match("/home"));
|
||||||
@ -206,7 +206,7 @@ const REGEX_FLAGS: &str = "(?s-m)";
|
|||||||
/// resource-path pairs that would not be compatible.
|
/// resource-path pairs that would not be compatible.
|
||||||
///
|
///
|
||||||
/// ## Examples
|
/// ## Examples
|
||||||
/// ```rust
|
/// ```
|
||||||
/// # use actix_router::ResourceDef;
|
/// # use actix_router::ResourceDef;
|
||||||
/// assert!(!ResourceDef::new("/root").is_match("/root/"));
|
/// assert!(!ResourceDef::new("/root").is_match("/root/"));
|
||||||
/// assert!(!ResourceDef::new("/root/").is_match("/root"));
|
/// assert!(!ResourceDef::new("/root/").is_match("/root"));
|
||||||
|
@ -26,6 +26,9 @@
|
|||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
|
#![deny(rust_2018_idioms, nonstandard_style)]
|
||||||
|
#![warn(future_incompatible)]
|
||||||
|
|
||||||
#[cfg(feature = "openssl")]
|
#[cfg(feature = "openssl")]
|
||||||
extern crate tls_openssl as openssl;
|
extern crate tls_openssl as openssl;
|
||||||
#[cfg(feature = "rustls")]
|
#[cfg(feature = "rustls")]
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
//! Actix actors support for Actix Web.
|
//! Actix actors support for Actix Web.
|
||||||
|
|
||||||
#![deny(rust_2018_idioms)]
|
#![deny(rust_2018_idioms, nonstandard_style)]
|
||||||
#![allow(clippy::borrow_interior_mutable_const)]
|
#![warn(future_incompatible)]
|
||||||
|
|
||||||
mod context;
|
mod context;
|
||||||
pub mod ws;
|
pub mod ws;
|
||||||
|
@ -57,6 +57,8 @@
|
|||||||
//! [DELETE]: macro@delete
|
//! [DELETE]: macro@delete
|
||||||
|
|
||||||
#![recursion_limit = "512"]
|
#![recursion_limit = "512"]
|
||||||
|
#![deny(rust_2018_idioms, nonstandard_style)]
|
||||||
|
#![warn(future_incompatible)]
|
||||||
|
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
|
@ -1,7 +1,4 @@
|
|||||||
extern crate proc_macro;
|
use std::{collections::HashSet, convert::TryFrom};
|
||||||
|
|
||||||
use std::collections::HashSet;
|
|
||||||
use std::convert::TryFrom;
|
|
||||||
|
|
||||||
use actix_router::ResourceDef;
|
use actix_router::ResourceDef;
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
|
@ -95,7 +95,8 @@
|
|||||||
//! # }
|
//! # }
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
#![deny(rust_2018_idioms)]
|
#![deny(rust_2018_idioms, nonstandard_style)]
|
||||||
|
#![warn(future_incompatible)]
|
||||||
#![allow(
|
#![allow(
|
||||||
clippy::type_complexity,
|
clippy::type_complexity,
|
||||||
clippy::borrow_interior_mutable_const,
|
clippy::borrow_interior_mutable_const,
|
||||||
|
@ -128,7 +128,7 @@ macro_rules! error_helper {
|
|||||||
InternalError::new(err, StatusCode::$status).into()
|
InternalError::new(err, StatusCode::$status).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
error_helper!(ErrorBadRequest, BAD_REQUEST);
|
error_helper!(ErrorBadRequest, BAD_REQUEST);
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
//! Error and Result module
|
//! Error and Result module
|
||||||
|
// This is meant to be a glob import of the whole error module except for `Error`. Rustdoc can't yet
|
||||||
/// This is meant to be a glob import of the whole error module, but rustdoc can't handle
|
// correctly resolve the conflicting `Error` type defined in this module, so these re-exports are
|
||||||
/// shadowing `Error` type, so it is expanded manually.
|
// expanded manually.
|
||||||
/// See https://github.com/rust-lang/rust/issues/83375
|
//
|
||||||
|
// See <https://github.com/rust-lang/rust/issues/83375>
|
||||||
pub use actix_http::error::{
|
pub use actix_http::error::{
|
||||||
BlockingError, ContentTypeError, DispatchError, HttpError, ParseError, PayloadError,
|
BlockingError, ContentTypeError, DispatchError, HttpError, ParseError, PayloadError,
|
||||||
};
|
};
|
||||||
|
@ -65,6 +65,7 @@
|
|||||||
//! * `secure-cookies` - secure cookies support
|
//! * `secure-cookies` - secure cookies support
|
||||||
|
|
||||||
#![deny(rust_2018_idioms, nonstandard_style)]
|
#![deny(rust_2018_idioms, nonstandard_style)]
|
||||||
|
#![warn(future_incompatible)]
|
||||||
#![allow(clippy::needless_doctest_main, clippy::type_complexity)]
|
#![allow(clippy::needless_doctest_main, clippy::type_complexity)]
|
||||||
#![doc(html_logo_url = "https://actix.rs/img/logo.png")]
|
#![doc(html_logo_url = "https://actix.rs/img/logo.png")]
|
||||||
#![doc(html_favicon_url = "https://actix.rs/favicon.ico")]
|
#![doc(html_favicon_url = "https://actix.rs/favicon.ico")]
|
||||||
|
@ -173,7 +173,7 @@ impl HttpRequest {
|
|||||||
/// let opt_t = req.conn_data::<PeerCertificate>();
|
/// let opt_t = req.conn_data::<PeerCertificate>();
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// [on-connect]: crate::HttpServiceBuilder::on_connect_ext
|
/// [on-connect]: crate::HttpServer::on_connect
|
||||||
pub fn conn_data<T: 'static>(&self) -> Option<&T> {
|
pub fn conn_data<T: 'static>(&self) -> Option<&T> {
|
||||||
self.inner
|
self.inner
|
||||||
.conn_data
|
.conn_data
|
||||||
|
@ -109,6 +109,7 @@ impl HttpResponseBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Replaced with [`Self::insert_header()`].
|
/// Replaced with [`Self::insert_header()`].
|
||||||
|
#[doc(hidden)]
|
||||||
#[deprecated(
|
#[deprecated(
|
||||||
since = "4.0.0",
|
since = "4.0.0",
|
||||||
note = "Replaced with `insert_header((key, value))`. Will be removed in v5."
|
note = "Replaced with `insert_header((key, value))`. Will be removed in v5."
|
||||||
@ -133,6 +134,7 @@ impl HttpResponseBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Replaced with [`Self::append_header()`].
|
/// Replaced with [`Self::append_header()`].
|
||||||
|
#[doc(hidden)]
|
||||||
#[deprecated(
|
#[deprecated(
|
||||||
since = "4.0.0",
|
since = "4.0.0",
|
||||||
note = "Replaced with `append_header((key, value))`. Will be removed in v5."
|
note = "Replaced with `append_header((key, value))`. Will be removed in v5."
|
||||||
|
Loading…
Reference in New Issue
Block a user