From 8497b5f4901f0a78f3769615f9e23a0c0de2382d Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Mon, 24 Aug 2020 10:13:35 +0100 Subject: [PATCH 01/20] integrate with updated actix-{codec, utils} (#1634) --- CHANGES.md | 11 +++-- Cargo.toml | 6 +-- actix-http/CHANGES.md | 3 +- actix-http/Cargo.toml | 4 +- actix-http/src/client/connection.rs | 12 ++++-- actix-http/src/client/h1proto.rs | 65 ++++++++++++++++------------- actix-http/src/error.rs | 7 ++-- actix-http/src/h1/client.rs | 5 +-- actix-http/src/h1/codec.rs | 5 +-- actix-http/src/h1/service.rs | 16 ++++--- actix-http/src/h1/utils.rs | 28 +++++++++---- actix-http/src/ws/codec.rs | 3 +- actix-http/src/ws/dispatcher.rs | 16 +++---- actix-http/tests/test_ws.rs | 4 +- actix-multipart/Cargo.toml | 2 +- actix-web-actors/Cargo.toml | 2 +- awc/CHANGES.md | 5 +++ awc/Cargo.toml | 4 +- awc/src/connect.rs | 4 +- awc/src/ws.rs | 2 +- awc/tests/test_ws.rs | 2 +- test-server/CHANGES.md | 3 ++ test-server/Cargo.toml | 4 +- 23 files changed, 127 insertions(+), 86 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 0a7b26d7d..0d7311748 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,14 +1,19 @@ # Changes -## Unreleased +## Unreleased - 2020-xx-xx ### Added -* `middleware::NormalizePath` now has configurable behaviour for either always having a trailing slash, - or as the new addition, always trimming trailing slashes. +* `middleware::NormalizePath` now has configurable behaviour for either always having a trailing + slash, or as the new addition, always trimming trailing slashes. + +### Changed +* Update actix-codec and actix-utils dependencies. + ## 3.0.0-beta.3 - 2020-08-17 ### Changed * Update `rustls` to 0.18 + ## 3.0.0-beta.2 - 2020-08-17 ### Changed * `PayloadConfig` is now also considered in `Bytes` and `String` extractors when set diff --git a/Cargo.toml b/Cargo.toml index 52d19c572..dbdab5937 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -65,9 +65,9 @@ name = "test_server" required-features = ["compress"] [dependencies] -actix-codec = "0.2.0" -actix-service = "1.0.2" -actix-utils = "1.0.6" +actix-codec = "0.3.0" +actix-service = "1.0.6" +actix-utils = "2.0.0" actix-router = "0.2.4" actix-rt = "1.1.1" actix-server = "1.0.0" diff --git a/actix-http/CHANGES.md b/actix-http/CHANGES.md index e223f10c3..d8d674fb1 100644 --- a/actix-http/CHANGES.md +++ b/actix-http/CHANGES.md @@ -1,7 +1,8 @@ # Changes ## Unreleased - +### Changed +* Update actix-codec and actix-utils dependencies. ## [2.0.0-beta.3] - 2020-08-14 diff --git a/actix-http/Cargo.toml b/actix-http/Cargo.toml index 5b65e83a9..750d1e0af 100644 --- a/actix-http/Cargo.toml +++ b/actix-http/Cargo.toml @@ -41,9 +41,9 @@ actors = ["actix"] [dependencies] actix-service = "1.0.5" -actix-codec = "0.2.0" +actix-codec = "0.3.0" actix-connect = "2.0.0-alpha.4" -actix-utils = "1.0.6" +actix-utils = "2.0.0" actix-rt = "1.0.0" actix-threadpool = "0.3.1" actix-tls = { version = "2.0.0-alpha.2", optional = true } diff --git a/actix-http/src/client/connection.rs b/actix-http/src/client/connection.rs index eecf2ee6f..ec86dabb0 100644 --- a/actix-http/src/client/connection.rs +++ b/actix-http/src/client/connection.rs @@ -46,10 +46,10 @@ pub trait Connection { pub(crate) trait ConnectionLifetime: AsyncRead + AsyncWrite + 'static { /// Close connection - fn close(&mut self); + fn close(self: Pin<&mut Self>); /// Release connection to the connection pool - fn release(&mut self); + fn release(self: Pin<&mut Self>); } #[doc(hidden)] @@ -195,11 +195,15 @@ where match self { EitherConnection::A(con) => con .open_tunnel(head) - .map(|res| res.map(|(head, framed)| (head, framed.map_io(EitherIo::A)))) + .map(|res| { + res.map(|(head, framed)| (head, framed.into_map_io(EitherIo::A))) + }) .boxed_local(), EitherConnection::B(con) => con .open_tunnel(head) - .map(|res| res.map(|(head, framed)| (head, framed.map_io(EitherIo::B)))) + .map(|res| { + res.map(|(head, framed)| (head, framed.into_map_io(EitherIo::B))) + }) .boxed_local(), } } diff --git a/actix-http/src/client/h1proto.rs b/actix-http/src/client/h1proto.rs index 51e853b3d..06cc05404 100644 --- a/actix-http/src/client/h1proto.rs +++ b/actix-http/src/client/h1proto.rs @@ -67,17 +67,17 @@ where }; // create Framed and send request - let mut framed = Framed::new(io, h1::ClientCodec::default()); - framed.send((head, body.size()).into()).await?; + let mut framed_inner = Framed::new(io, h1::ClientCodec::default()); + framed_inner.send((head, body.size()).into()).await?; // send request body match body.size() { BodySize::None | BodySize::Empty | BodySize::Sized(0) => (), - _ => send_body(body, &mut framed).await?, + _ => send_body(body, Pin::new(&mut framed_inner)).await?, }; // read response and init read body - let res = framed.into_future().await; + let res = Pin::new(&mut framed_inner).into_future().await; let (head, framed) = if let (Some(result), framed) = res { let item = result.map_err(SendRequestError::from)?; (item, framed) @@ -85,14 +85,14 @@ where return Err(SendRequestError::from(ConnectError::Disconnected)); }; - match framed.get_codec().message_type() { + match framed.codec_ref().message_type() { h1::MessageType::None => { - let force_close = !framed.get_codec().keepalive(); + let force_close = !framed.codec_ref().keepalive(); release_connection(framed, force_close); Ok((head, Payload::None)) } _ => { - let pl: PayloadStream = PlStream::new(framed).boxed_local(); + let pl: PayloadStream = PlStream::new(framed_inner).boxed_local(); Ok((head, pl.into())) } } @@ -119,35 +119,36 @@ where } /// send request body to the peer -pub(crate) async fn send_body( +pub(crate) async fn send_body( body: B, - framed: &mut Framed, + mut framed: Pin<&mut Framed>, ) -> Result<(), SendRequestError> where - I: ConnectionLifetime, + T: ConnectionLifetime + Unpin, B: MessageBody, { - let mut eof = false; pin_mut!(body); + + let mut eof = false; while !eof { - while !eof && !framed.is_write_buf_full() { + while !eof && !framed.as_ref().is_write_buf_full() { match poll_fn(|cx| body.as_mut().poll_next(cx)).await { Some(result) => { - framed.write(h1::Message::Chunk(Some(result?)))?; + framed.as_mut().write(h1::Message::Chunk(Some(result?)))?; } None => { eof = true; - framed.write(h1::Message::Chunk(None))?; + framed.as_mut().write(h1::Message::Chunk(None))?; } } } - if !framed.is_write_buf_empty() { - poll_fn(|cx| match framed.flush(cx) { + if !framed.as_ref().is_write_buf_empty() { + poll_fn(|cx| match framed.as_mut().flush(cx) { Poll::Ready(Ok(_)) => Poll::Ready(Ok(())), Poll::Ready(Err(err)) => Poll::Ready(Err(err)), Poll::Pending => { - if !framed.is_write_buf_full() { + if !framed.as_ref().is_write_buf_full() { Poll::Ready(Ok(())) } else { Poll::Pending @@ -158,13 +159,14 @@ where } } - SinkExt::flush(framed).await?; + SinkExt::flush(Pin::into_inner(framed)).await?; Ok(()) } #[doc(hidden)] /// HTTP client connection pub struct H1Connection { + /// T should be `Unpin` io: Option, created: time::Instant, pool: Option>, @@ -175,7 +177,7 @@ where T: AsyncRead + AsyncWrite + Unpin + 'static, { /// Close connection - fn close(&mut self) { + fn close(mut self: Pin<&mut Self>) { if let Some(mut pool) = self.pool.take() { if let Some(io) = self.io.take() { pool.close(IoConnection::new( @@ -188,7 +190,7 @@ where } /// Release this connection to the connection pool - fn release(&mut self) { + fn release(mut self: Pin<&mut Self>) { if let Some(mut pool) = self.pool.take() { if let Some(io) = self.io.take() { pool.release(IoConnection::new( @@ -242,14 +244,18 @@ impl AsyncWrite for H1Connection } } +#[pin_project::pin_project] pub(crate) struct PlStream { + #[pin] framed: Option>, } impl PlStream { fn new(framed: Framed) -> Self { + let framed = framed.into_map_codec(|codec| codec.into_payload_codec()); + PlStream { - framed: Some(framed.map_codec(|codec| codec.into_payload_codec())), + framed: Some(framed), } } } @@ -261,16 +267,16 @@ impl Stream for PlStream { self: Pin<&mut Self>, cx: &mut Context<'_>, ) -> Poll> { - let this = self.get_mut(); + let mut this = self.project(); - match this.framed.as_mut().unwrap().next_item(cx)? { + match this.framed.as_mut().as_pin_mut().unwrap().next_item(cx)? { Poll::Pending => Poll::Pending, Poll::Ready(Some(chunk)) => { if let Some(chunk) = chunk { Poll::Ready(Some(Ok(chunk))) } else { - let framed = this.framed.take().unwrap(); - let force_close = !framed.get_codec().keepalive(); + let framed = this.framed.as_mut().as_pin_mut().unwrap(); + let force_close = !framed.codec_ref().keepalive(); release_connection(framed, force_close); Poll::Ready(None) } @@ -280,14 +286,13 @@ impl Stream for PlStream { } } -fn release_connection(framed: Framed, force_close: bool) +fn release_connection(framed: Pin<&mut Framed>, force_close: bool) where T: ConnectionLifetime, { - let mut parts = framed.into_parts(); - if !force_close && parts.read_buf.is_empty() && parts.write_buf.is_empty() { - parts.io.release() + if !force_close && framed.is_read_buf_empty() && framed.is_write_buf_empty() { + framed.io_pin().release() } else { - parts.io.close() + framed.io_pin().close() } } diff --git a/actix-http/src/error.rs b/actix-http/src/error.rs index d0754ce88..e93c077af 100644 --- a/actix-http/src/error.rs +++ b/actix-http/src/error.rs @@ -1,4 +1,5 @@ //! Error and Result module + use std::cell::RefCell; use std::io::Write; use std::str::Utf8Error; @@ -7,7 +8,7 @@ use std::{fmt, io, result}; use actix_codec::{Decoder, Encoder}; pub use actix_threadpool::BlockingError; -use actix_utils::framed::DispatcherError as FramedDispatcherError; +use actix_utils::dispatcher::DispatcherError as FramedDispatcherError; use actix_utils::timeout::TimeoutError; use bytes::BytesMut; use derive_more::{Display, From}; @@ -452,10 +453,10 @@ impl ResponseError for ContentTypeError { } } -impl ResponseError for FramedDispatcherError +impl + Decoder, I> ResponseError for FramedDispatcherError where E: fmt::Debug + fmt::Display, - ::Error: fmt::Debug, + >::Error: fmt::Debug, ::Error: fmt::Debug, { } diff --git a/actix-http/src/h1/client.rs b/actix-http/src/h1/client.rs index bcfc18cde..2e0103409 100644 --- a/actix-http/src/h1/client.rs +++ b/actix-http/src/h1/client.rs @@ -173,13 +173,12 @@ impl Decoder for ClientPayloadCodec { } } -impl Encoder for ClientCodec { - type Item = Message<(RequestHeadType, BodySize)>; +impl Encoder> for ClientCodec { type Error = io::Error; fn encode( &mut self, - item: Self::Item, + item: Message<(RequestHeadType, BodySize)>, dst: &mut BytesMut, ) -> Result<(), Self::Error> { match item { diff --git a/actix-http/src/h1/codec.rs b/actix-http/src/h1/codec.rs index de2af9ee7..036f16670 100644 --- a/actix-http/src/h1/codec.rs +++ b/actix-http/src/h1/codec.rs @@ -144,13 +144,12 @@ impl Decoder for Codec { } } -impl Encoder for Codec { - type Item = Message<(Response<()>, BodySize)>; +impl Encoder, BodySize)>> for Codec { type Error = io::Error; fn encode( &mut self, - item: Self::Item, + item: Message<(Response<()>, BodySize)>, dst: &mut BytesMut, ) -> Result<(), Self::Error> { match item { diff --git a/actix-http/src/h1/service.rs b/actix-http/src/h1/service.rs index 4d1a1dc1b..339a0f538 100644 --- a/actix-http/src/h1/service.rs +++ b/actix-http/src/h1/service.rs @@ -548,10 +548,12 @@ where } #[doc(hidden)] +#[pin_project::pin_project] pub struct OneRequestServiceResponse where T: AsyncRead + AsyncWrite + Unpin, { + #[pin] framed: Option>, } @@ -562,16 +564,18 @@ where type Output = Result<(Request, Framed), ParseError>; fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - match self.framed.as_mut().unwrap().next_item(cx) { - Poll::Ready(Some(Ok(req))) => match req { + let this = self.as_mut().project(); + + match ready!(this.framed.as_pin_mut().unwrap().next_item(cx)) { + Some(Ok(req)) => match req { Message::Item(req) => { - Poll::Ready(Ok((req, self.framed.take().unwrap()))) + let mut this = self.as_mut().project(); + Poll::Ready(Ok((req, this.framed.take().unwrap()))) } Message::Chunk(_) => unreachable!("Something is wrong"), }, - Poll::Ready(Some(Err(err))) => Poll::Ready(Err(err)), - Poll::Ready(None) => Poll::Ready(Err(ParseError::Incomplete)), - Poll::Pending => Poll::Pending, + Some(Err(err)) => Poll::Ready(Err(err)), + None => Poll::Ready(Err(ParseError::Incomplete)), } } } diff --git a/actix-http/src/h1/utils.rs b/actix-http/src/h1/utils.rs index c44925c7a..9e9c57137 100644 --- a/actix-http/src/h1/utils.rs +++ b/actix-http/src/h1/utils.rs @@ -9,12 +9,13 @@ use crate::error::Error; use crate::h1::{Codec, Message}; use crate::response::Response; -/// Send http/1 response +/// Send HTTP/1 response #[pin_project::pin_project] pub struct SendResponse { res: Option, BodySize)>>, #[pin] body: Option>, + #[pin] framed: Option>, } @@ -35,23 +36,30 @@ where impl Future for SendResponse where - T: AsyncRead + AsyncWrite, + T: AsyncRead + AsyncWrite + Unpin, B: MessageBody + Unpin, { type Output = Result, Error>; // TODO: rethink if we need loops in polls - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let mut this = self.project(); + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let mut this = self.as_mut().project(); let mut body_done = this.body.is_none(); loop { let mut body_ready = !body_done; - let framed = this.framed.as_mut().unwrap(); // send body if this.res.is_none() && body_ready { - while body_ready && !body_done && !framed.is_write_buf_full() { + while body_ready + && !body_done + && !this + .framed + .as_ref() + .as_pin_ref() + .unwrap() + .is_write_buf_full() + { match this.body.as_mut().as_pin_mut().unwrap().poll_next(cx)? { Poll::Ready(item) => { // body is done when item is None @@ -59,6 +67,7 @@ where if body_done { let _ = this.body.take(); } + let framed = this.framed.as_mut().as_pin_mut().unwrap(); framed.write(Message::Chunk(item))?; } Poll::Pending => body_ready = false, @@ -66,6 +75,8 @@ where } } + let framed = this.framed.as_mut().as_pin_mut().unwrap(); + // flush write buffer if !framed.is_write_buf_empty() { match framed.flush(cx)? { @@ -96,6 +107,9 @@ where break; } } - Poll::Ready(Ok(this.framed.take().unwrap())) + + let framed = this.framed.take().unwrap(); + + Poll::Ready(Ok(framed)) } } diff --git a/actix-http/src/ws/codec.rs b/actix-http/src/ws/codec.rs index 733976a78..7c9628b1a 100644 --- a/actix-http/src/ws/codec.rs +++ b/actix-http/src/ws/codec.rs @@ -91,8 +91,7 @@ impl Codec { } } -impl Encoder for Codec { - type Item = Message; +impl Encoder for Codec { type Error = ProtocolError; fn encode(&mut self, item: Message, dst: &mut BytesMut) -> Result<(), Self::Error> { diff --git a/actix-http/src/ws/dispatcher.rs b/actix-http/src/ws/dispatcher.rs index 7a6b11b18..b114217a0 100644 --- a/actix-http/src/ws/dispatcher.rs +++ b/actix-http/src/ws/dispatcher.rs @@ -4,16 +4,18 @@ use std::task::{Context, Poll}; use actix_codec::{AsyncRead, AsyncWrite, Framed}; use actix_service::{IntoService, Service}; -use actix_utils::framed; +use actix_utils::dispatcher::{Dispatcher as InnerDispatcher, DispatcherError}; use super::{Codec, Frame, Message}; +#[pin_project::pin_project] pub struct Dispatcher where S: Service + 'static, T: AsyncRead + AsyncWrite, { - inner: framed::Dispatcher, + #[pin] + inner: InnerDispatcher, } impl Dispatcher @@ -25,13 +27,13 @@ where { pub fn new>(io: T, service: F) -> Self { Dispatcher { - inner: framed::Dispatcher::new(Framed::new(io, Codec::new()), service), + inner: InnerDispatcher::new(Framed::new(io, Codec::new()), service), } } pub fn with>(framed: Framed, service: F) -> Self { Dispatcher { - inner: framed::Dispatcher::new(framed, service), + inner: InnerDispatcher::new(framed, service), } } } @@ -43,9 +45,9 @@ where S::Future: 'static, S::Error: 'static, { - type Output = Result<(), framed::DispatcherError>; + type Output = Result<(), DispatcherError>; - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - Pin::new(&mut self.inner).poll(cx) + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + self.project().inner.poll(cx) } } diff --git a/actix-http/tests/test_ws.rs b/actix-http/tests/test_ws.rs index ff9def85b..5d86605f4 100644 --- a/actix-http/tests/test_ws.rs +++ b/actix-http/tests/test_ws.rs @@ -8,7 +8,7 @@ use actix_codec::{AsyncRead, AsyncWrite, Framed}; use actix_http::{body, h1, ws, Error, HttpService, Request, Response}; use actix_http_test::test_server; use actix_service::{fn_factory, Service}; -use actix_utils::framed::Dispatcher; +use actix_utils::dispatcher::Dispatcher; use bytes::Bytes; use futures_util::future; use futures_util::task::{Context, Poll}; @@ -59,7 +59,7 @@ where .await .unwrap(); - Dispatcher::new(framed.into_framed(ws::Codec::new()), service) + Dispatcher::new(framed.replace_codec(ws::Codec::new()), service) .await .map_err(|_| panic!()) }; diff --git a/actix-multipart/Cargo.toml b/actix-multipart/Cargo.toml index 04c3415e0..58f7113e5 100644 --- a/actix-multipart/Cargo.toml +++ b/actix-multipart/Cargo.toml @@ -18,7 +18,7 @@ path = "src/lib.rs" [dependencies] actix-web = { version = "3.0.0-beta.3", default-features = false } actix-service = "1.0.1" -actix-utils = "1.0.3" +actix-utils = "2.0.0" bytes = "0.5.3" derive_more = "0.99.2" httparse = "1.3" diff --git a/actix-web-actors/Cargo.toml b/actix-web-actors/Cargo.toml index a5f682cd5..b33acc222 100644 --- a/actix-web-actors/Cargo.toml +++ b/actix-web-actors/Cargo.toml @@ -19,7 +19,7 @@ path = "src/lib.rs" actix = "0.10.0-alpha.2" actix-web = { version = "3.0.0-beta.3", default-features = false } actix-http = "2.0.0-beta.3" -actix-codec = "0.2.0" +actix-codec = "0.3.0" bytes = "0.5.2" futures-channel = { version = "0.3.5", default-features = false } futures-core = { version = "0.3.5", default-features = false } diff --git a/awc/CHANGES.md b/awc/CHANGES.md index f4b31aef6..8d1b58856 100644 --- a/awc/CHANGES.md +++ b/awc/CHANGES.md @@ -1,5 +1,10 @@ # Changes +## Unreleased - 2020-xx-xx +### Changed +* Update actix-codec dependency. + + ## 2.0.0-beta.3 - 2020-08-17 ### Changed * Update `rustls` to 0.18 diff --git a/awc/Cargo.toml b/awc/Cargo.toml index ea4450bb2..ff0afaa1c 100644 --- a/awc/Cargo.toml +++ b/awc/Cargo.toml @@ -37,7 +37,7 @@ rustls = ["rust-tls", "actix-http/rustls"] compress = ["actix-http/compress"] [dependencies] -actix-codec = "0.2.0" +actix-codec = "0.3.0" actix-service = "1.0.1" actix-http = "2.0.0-beta.3" actix-rt = "1.0.0" @@ -61,7 +61,7 @@ actix-connect = { version = "2.0.0-alpha.4", features = ["openssl"] } actix-web = { version = "3.0.0-beta.2", features = ["openssl"] } actix-http = { version = "2.0.0-beta.3", features = ["openssl"] } actix-http-test = { version = "2.0.0-alpha.1", features = ["openssl"] } -actix-utils = "1.0.3" +actix-utils = "2.0.0" actix-server = "1.0.0" actix-tls = { version = "2.0.0-alpha.2", features = ["openssl", "rustls"] } brotli2 = "0.3.2" diff --git a/awc/src/connect.rs b/awc/src/connect.rs index 618d653f5..7fbe1543a 100644 --- a/awc/src/connect.rs +++ b/awc/src/connect.rs @@ -152,7 +152,7 @@ where let (head, framed) = connection.open_tunnel(RequestHeadType::from(head)).await?; - let framed = framed.map_io(|io| BoxedSocket(Box::new(Socket(io)))); + let framed = framed.into_map_io(|io| BoxedSocket(Box::new(Socket(io)))); Ok((head, framed)) }) } @@ -186,7 +186,7 @@ where .open_tunnel(RequestHeadType::Rc(head, extra_headers)) .await?; - let framed = framed.map_io(|io| BoxedSocket(Box::new(Socket(io)))); + let framed = framed.into_map_io(|io| BoxedSocket(Box::new(Socket(io)))); Ok((head, framed)) }) } diff --git a/awc/src/ws.rs b/awc/src/ws.rs index 6ad660c41..8b01e5716 100644 --- a/awc/src/ws.rs +++ b/awc/src/ws.rs @@ -366,7 +366,7 @@ impl WebsocketsRequest { // response and ws framed Ok(( ClientResponse::new(head, Payload::None), - framed.map_codec(|_| { + framed.into_map_codec(|_| { if server_mode { ws::Codec::new().max_size(max_size) } else { diff --git a/awc/tests/test_ws.rs b/awc/tests/test_ws.rs index d3f66814f..1c1068668 100644 --- a/awc/tests/test_ws.rs +++ b/awc/tests/test_ws.rs @@ -32,7 +32,7 @@ async fn test_simple() { .await?; // start websocket service - let framed = framed.into_framed(ws::Codec::new()); + let framed = framed.replace_codec(ws::Codec::new()); ws::Dispatcher::with(framed, ws_service).await } }) diff --git a/test-server/CHANGES.md b/test-server/CHANGES.md index 079cad74a..71b906b9f 100644 --- a/test-server/CHANGES.md +++ b/test-server/CHANGES.md @@ -1,5 +1,8 @@ # Changes +## Unreleased - 2020-xx-xx +* Update actix-codec and actix-utils dependencies. + ## [2.0.0-alpha.1] - 2020-05-23 * Update the `time` dependency to 0.2.7 diff --git a/test-server/Cargo.toml b/test-server/Cargo.toml index f3df6d1f6..13f27ab59 100644 --- a/test-server/Cargo.toml +++ b/test-server/Cargo.toml @@ -30,9 +30,9 @@ openssl = ["open-ssl", "awc/openssl"] [dependencies] actix-service = "1.0.1" -actix-codec = "0.2.0" +actix-codec = "0.3.0" actix-connect = "2.0.0-alpha.4" -actix-utils = "1.0.3" +actix-utils = "2.0.0" actix-rt = "1.0.0" actix-server = "1.0.0" actix-testing = "1.0.0" From 01cbef700fd9d7ce20f44bed06c649f6b238b9bb Mon Sep 17 00:00:00 2001 From: Matt Kantor Date: Fri, 28 Aug 2020 14:16:41 -0700 Subject: [PATCH 02/20] Fix a small typo in a doc comment. (#1649) --- src/middleware/logger.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/middleware/logger.rs b/src/middleware/logger.rs index dc6468ab3..51d4722d7 100644 --- a/src/middleware/logger.rs +++ b/src/middleware/logger.rs @@ -85,7 +85,7 @@ use crate::HttpResponse; /// [`ConnectionInfo::realip_remote_addr()`](../dev/struct.ConnectionInfo.html#method.realip_remote_addr) /// /// If you use this value ensure that all requests come from trusted hosts, since it is trivial -/// for the remote client to simulate been another client. +/// for the remote client to simulate being another client. /// pub struct Logger(Rc); From 4e321595bcf4a450efcfe5655e68b7c917c38fa8 Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Wed, 2 Sep 2020 22:12:07 +0100 Subject: [PATCH 03/20] extract more config types from Data as well (#1641) --- CHANGES.md | 9 +++++-- src/types/form.rs | 38 +++++++++++++++++++++++------ src/types/json.rs | 58 +++++++++++++++++++++++++++++++++----------- src/types/payload.rs | 19 ++++++--------- 4 files changed, 89 insertions(+), 35 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 0d7311748..82c562f5c 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,11 +3,16 @@ ## Unreleased - 2020-xx-xx ### Added * `middleware::NormalizePath` now has configurable behaviour for either always having a trailing - slash, or as the new addition, always trimming trailing slashes. + slash, or as the new addition, always trimming trailing slashes. [#1639] ### Changed -* Update actix-codec and actix-utils dependencies. +* Update actix-codec and actix-utils dependencies. [#1634] +* `FormConfig` and `JsonConfig` configurations are now also considered when set + using `App::data`. [#1641] +[#1639]: https://github.com/actix/actix-web/pull/1639 +[#1641]: https://github.com/actix/actix-web/pull/1641 +[#1634]: https://github.com/actix/actix-web/pull/1634 ## 3.0.0-beta.3 - 2020-08-17 ### Changed diff --git a/src/types/form.rs b/src/types/form.rs index ea061d553..de88c2a94 100644 --- a/src/types/form.rs +++ b/src/types/form.rs @@ -23,7 +23,7 @@ use crate::http::{ StatusCode, }; use crate::request::HttpRequest; -use crate::responder::Responder; +use crate::{responder::Responder, web}; /// Form data helper (`application/x-www-form-urlencoded`) /// @@ -121,8 +121,12 @@ where fn from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future { let req2 = req.clone(); let (limit, err) = req - .app_data::() - .map(|c| (c.limit, c.ehandler.clone())) + .app_data::() + .or_else(|| { + req.app_data::>() + .map(|d| d.as_ref()) + }) + .map(|c| (c.limit, c.err_handler.clone())) .unwrap_or((16384, None)); UrlEncoded::new(req, payload) @@ -200,7 +204,7 @@ impl Responder for Form { #[derive(Clone)] pub struct FormConfig { limit: usize, - ehandler: Option Error>>, + err_handler: Option Error>>, } impl FormConfig { @@ -215,7 +219,7 @@ impl FormConfig { where F: Fn(UrlencodedError, &HttpRequest) -> Error + 'static, { - self.ehandler = Some(Rc::new(f)); + self.err_handler = Some(Rc::new(f)); self } } @@ -223,8 +227,8 @@ impl FormConfig { impl Default for FormConfig { fn default() -> Self { FormConfig { - limit: 16384, - ehandler: None, + limit: 16_384, // 2^14 bytes (~16kB) + err_handler: None, } } } @@ -378,7 +382,7 @@ mod tests { use serde::{Deserialize, Serialize}; use super::*; - use crate::http::header::{HeaderValue, CONTENT_TYPE}; + use crate::http::header::{HeaderValue, CONTENT_LENGTH, CONTENT_TYPE}; use crate::test::TestRequest; #[derive(Deserialize, Serialize, Debug, PartialEq)] @@ -499,4 +503,22 @@ mod tests { use crate::responder::tests::BodyTest; assert_eq!(resp.body().bin_ref(), b"hello=world&counter=123"); } + + #[actix_rt::test] + async fn test_with_config_in_data_wrapper() { + let ctype = HeaderValue::from_static("application/x-www-form-urlencoded"); + + let (req, mut pl) = TestRequest::default() + .header(CONTENT_TYPE, ctype) + .header(CONTENT_LENGTH, HeaderValue::from_static("20")) + .set_payload(Bytes::from_static(b"hello=test&counter=4")) + .app_data(web::Data::new(FormConfig::default().limit(10))) + .to_http_parts(); + + let s = Form::::from_request(&req, &mut pl).await; + assert!(s.is_err()); + + let err_str = s.err().unwrap().to_string(); + assert!(err_str.contains("Urlencoded payload size is bigger")); + } } diff --git a/src/types/json.rs b/src/types/json.rs index 527b4b611..ab7978dff 100644 --- a/src/types/json.rs +++ b/src/types/json.rs @@ -20,7 +20,7 @@ use crate::dev::Decompress; use crate::error::{Error, JsonPayloadError}; use crate::extract::FromRequest; use crate::request::HttpRequest; -use crate::responder::Responder; +use crate::{responder::Responder, web}; /// Json helper /// @@ -179,10 +179,11 @@ where #[inline] fn from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future { let req2 = req.clone(); - let (limit, err, ctype) = req - .app_data::() - .map(|c| (c.limit, c.ehandler.clone(), c.content_type.clone())) - .unwrap_or((32768, None, None)); + let config = JsonConfig::from_req(req); + + let limit = config.limit; + let ctype = config.content_type.clone(); + let err_handler = config.err_handler.clone(); JsonBody::new(req, payload, ctype) .limit(limit) @@ -193,7 +194,8 @@ where Request path: {}", req2.path() ); - if let Some(err) = err { + + if let Some(err) = err_handler { Err((*err)(e, &req2)) } else { Err(e.into()) @@ -255,7 +257,8 @@ where #[derive(Clone)] pub struct JsonConfig { limit: usize, - ehandler: Option Error + Send + Sync>>, + err_handler: + Option Error + Send + Sync>>, content_type: Option bool + Send + Sync>>, } @@ -271,7 +274,7 @@ impl JsonConfig { where F: Fn(JsonPayloadError, &HttpRequest) -> Error + Send + Sync + 'static, { - self.ehandler = Some(Arc::new(f)); + self.err_handler = Some(Arc::new(f)); self } @@ -283,15 +286,26 @@ impl JsonConfig { self.content_type = Some(Arc::new(predicate)); self } + + /// Extract payload config from app data. Check both `T` and `Data`, in that order, and fall + /// back to the default payload config. + fn from_req(req: &HttpRequest) -> &Self { + req.app_data::() + .or_else(|| req.app_data::>().map(|d| d.as_ref())) + .unwrap_or_else(|| &DEFAULT_CONFIG) + } } +// Allow shared refs to default. +const DEFAULT_CONFIG: JsonConfig = JsonConfig { + limit: 32_768, // 2^15 bytes, (~32kB) + err_handler: None, + content_type: None, +}; + impl Default for JsonConfig { fn default() -> Self { - JsonConfig { - limit: 32768, - ehandler: None, - content_type: None, - } + DEFAULT_CONFIG.clone() } } @@ -422,7 +436,7 @@ mod tests { use super::*; use crate::error::InternalError; - use crate::http::header; + use crate::http::header::{self, HeaderValue, CONTENT_LENGTH, CONTENT_TYPE}; use crate::test::{load_stream, TestRequest}; use crate::HttpResponse; @@ -659,4 +673,20 @@ mod tests { let s = Json::::from_request(&req, &mut pl).await; assert!(s.is_err()) } + + #[actix_rt::test] + async fn test_with_config_in_data_wrapper() { + let (req, mut pl) = TestRequest::default() + .header(CONTENT_TYPE, HeaderValue::from_static("application/json")) + .header(CONTENT_LENGTH, HeaderValue::from_static("16")) + .set_payload(Bytes::from_static(b"{\"name\": \"test\"}")) + .app_data(web::Data::new(JsonConfig::default().limit(10))) + .to_http_parts(); + + let s = Json::::from_request(&req, &mut pl).await; + assert!(s.is_err()); + + let err_str = s.err().unwrap().to_string(); + assert!(err_str.contains("Json payload size is bigger than allowed")); + } } diff --git a/src/types/payload.rs b/src/types/payload.rs index 653abf089..bbdd89525 100644 --- a/src/types/payload.rs +++ b/src/types/payload.rs @@ -279,27 +279,24 @@ impl PayloadConfig { Ok(()) } - /// Allow payload config extraction from app data checking both `T` and `Data`, in that - /// order, and falling back to the default payload config. - fn from_req(req: &HttpRequest) -> &PayloadConfig { - req.app_data::() - .or_else(|| { - req.app_data::>() - .map(|d| d.as_ref()) - }) - .unwrap_or_else(|| &DEFAULT_PAYLOAD_CONFIG) + /// Extract payload config from app data. Check both `T` and `Data`, in that order, and fall + /// back to the default payload config. + fn from_req(req: &HttpRequest) -> &Self { + req.app_data::() + .or_else(|| req.app_data::>().map(|d| d.as_ref())) + .unwrap_or_else(|| &DEFAULT_CONFIG) } } // Allow shared refs to default. -static DEFAULT_PAYLOAD_CONFIG: PayloadConfig = PayloadConfig { +const DEFAULT_CONFIG: PayloadConfig = PayloadConfig { limit: 262_144, // 2^18 bytes (~256kB) mimetype: None, }; impl Default for PayloadConfig { fn default() -> Self { - DEFAULT_PAYLOAD_CONFIG.clone() + DEFAULT_CONFIG.clone() } } From 9a9d4b182eff659894f32ddab360e3060c747e3c Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Thu, 3 Sep 2020 10:00:24 +0100 Subject: [PATCH 04/20] document all remaining unsafe usages (#1642) adds some debug assertions where appropriate --- actix-http/src/config.rs | 3 +- actix-http/src/h1/decoder.rs | 4 +- actix-http/src/h1/dispatcher.rs | 4 ++ actix-http/src/h1/encoder.rs | 69 +++++++++++++++++++++++++++------ actix-http/src/h2/dispatcher.rs | 8 ++-- actix-http/src/macros.rs | 5 ++- actix-http/src/ws/mask.rs | 15 ++++--- 7 files changed, 84 insertions(+), 24 deletions(-) diff --git a/actix-http/src/config.rs b/actix-http/src/config.rs index abf3d8ff9..b314d4c99 100644 --- a/actix-http/src/config.rs +++ b/actix-http/src/config.rs @@ -17,7 +17,7 @@ const DATE_VALUE_LENGTH: usize = 29; pub enum KeepAlive { /// Keep alive in seconds Timeout(usize), - /// Relay on OS to shutdown tcp connection + /// Rely on OS to shutdown tcp connection Os, /// Disabled Disabled, @@ -209,6 +209,7 @@ impl Date { date.update(); date } + fn update(&mut self) { self.pos = 0; write!( diff --git a/actix-http/src/h1/decoder.rs b/actix-http/src/h1/decoder.rs index 8fdd11be5..8e891dc5c 100644 --- a/actix-http/src/h1/decoder.rs +++ b/actix-http/src/h1/decoder.rs @@ -76,12 +76,14 @@ pub(crate) trait MessageType: Sized { let name = HeaderName::from_bytes(&slice[idx.name.0..idx.name.1]).unwrap(); - // SAFETY: httparse checks header value is valid UTF-8 + // SAFETY: httparse already checks header value is only visible ASCII bytes + // from_maybe_shared_unchecked contains debug assertions so they are omitted here let value = unsafe { HeaderValue::from_maybe_shared_unchecked( slice.slice(idx.value.0..idx.value.1), ) }; + match name { header::CONTENT_LENGTH => { if let Ok(s) = value.to_str() { diff --git a/actix-http/src/h1/dispatcher.rs b/actix-http/src/h1/dispatcher.rs index 00b36562e..7c4de9707 100644 --- a/actix-http/src/h1/dispatcher.rs +++ b/actix-http/src/h1/dispatcher.rs @@ -314,11 +314,15 @@ where Poll::Ready(Err(err)) => return Err(DispatchError::Io(err)), } } + if written == write_buf.len() { + // SAFETY: setting length to 0 is safe + // skips one length check vs truncate unsafe { write_buf.set_len(0) } } else { write_buf.advance(written); } + Ok(false) } diff --git a/actix-http/src/h1/encoder.rs b/actix-http/src/h1/encoder.rs index eb8c337dd..e16b4c3dc 100644 --- a/actix-http/src/h1/encoder.rs +++ b/actix-http/src/h1/encoder.rs @@ -129,89 +129,133 @@ pub(crate) trait MessageType: Sized { .chain(extra_headers.inner.iter()); // write headers - let mut pos = 0; + let mut has_date = false; - let mut remaining = dst.capacity() - dst.len(); + let mut buf = dst.bytes_mut().as_mut_ptr() as *mut u8; + let mut remaining = dst.capacity() - dst.len(); + + // tracks bytes written since last buffer resize + // since buf is a raw pointer to a bytes container storage but is written to without the + // container's knowledge, this is used to sync the containers cursor after data is written + let mut pos = 0; + for (key, value) in headers { match *key { CONNECTION => continue, TRANSFER_ENCODING | CONTENT_LENGTH if skip_len => continue, - DATE => { - has_date = true; - } + DATE => has_date = true, _ => (), } + let k = key.as_str().as_bytes(); + let k_len = k.len(); + match value { map::Value::One(ref val) => { let v = val.as_ref(); let v_len = v.len(); - let k_len = k.len(); + + // key length + value length + colon + space + \r\n let len = k_len + v_len + 4; + if len > remaining { + // not enough room in buffer for this header; reserve more space + + // SAFETY: all the bytes written up to position "pos" are initialized + // the written byte count and pointer advancement are kept in sync unsafe { dst.advance_mut(pos); } + pos = 0; dst.reserve(len * 2); remaining = dst.capacity() - dst.len(); + + // re-assign buf raw pointer since it's possible that the buffer was + // reallocated and/or resized buf = dst.bytes_mut().as_mut_ptr() as *mut u8; } - // use upper Camel-Case + + // SAFETY: on each write, it is enough to ensure that the advancement of the + // cursor matches the number of bytes written unsafe { + // use upper Camel-Case if camel_case { write_camel_case(k, from_raw_parts_mut(buf, k_len)) } else { write_data(k, buf, k_len) } + buf = buf.add(k_len); + write_data(b": ", buf, 2); buf = buf.add(2); + write_data(v, buf, v_len); buf = buf.add(v_len); + write_data(b"\r\n", buf, 2); buf = buf.add(2); - pos += len; - remaining -= len; } + + pos += len; + remaining -= len; } + map::Value::Multi(ref vec) => { for val in vec { let v = val.as_ref(); let v_len = v.len(); - let k_len = k.len(); let len = k_len + v_len + 4; + if len > remaining { + // SAFETY: all the bytes written up to position "pos" are initialized + // the written byte count and pointer advancement are kept in sync unsafe { dst.advance_mut(pos); } pos = 0; dst.reserve(len * 2); remaining = dst.capacity() - dst.len(); + + // re-assign buf raw pointer since it's possible that the buffer was + // reallocated and/or resized buf = dst.bytes_mut().as_mut_ptr() as *mut u8; } - // use upper Camel-Case + + // SAFETY: on each write, it is enough to ensure that the advancement of + // the cursor matches the number of bytes written unsafe { if camel_case { write_camel_case(k, from_raw_parts_mut(buf, k_len)); } else { write_data(k, buf, k_len); } + buf = buf.add(k_len); + write_data(b": ", buf, 2); buf = buf.add(2); + write_data(v, buf, v_len); buf = buf.add(v_len); + write_data(b"\r\n", buf, 2); buf = buf.add(2); }; + pos += len; remaining -= len; } } } } + + // final cursor synchronization with the bytes container + // + // SAFETY: all the bytes written up to position "pos" are initialized + // the written byte count and pointer advancement are kept in sync unsafe { dst.advance_mut(pos); } @@ -477,7 +521,10 @@ impl<'a> io::Write for Writer<'a> { } } +/// # Safety +/// Callers must ensure that the given length matches given value length. unsafe fn write_data(value: &[u8], buf: *mut u8, len: usize) { + debug_assert_eq!(value.len(), len); copy_nonoverlapping(value.as_ptr(), buf, len); } diff --git a/actix-http/src/h2/dispatcher.rs b/actix-http/src/h2/dispatcher.rs index 534ce928a..daa651f4d 100644 --- a/actix-http/src/h2/dispatcher.rs +++ b/actix-http/src/h2/dispatcher.rs @@ -227,9 +227,11 @@ where if !has_date { let mut bytes = BytesMut::with_capacity(29); self.config.set_date_header(&mut bytes); - res.headers_mut().insert(DATE, unsafe { - HeaderValue::from_maybe_shared_unchecked(bytes.freeze()) - }); + res.headers_mut().insert( + DATE, + // SAFETY: serialized date-times are known ASCII strings + unsafe { HeaderValue::from_maybe_shared_unchecked(bytes.freeze()) }, + ); } res diff --git a/actix-http/src/macros.rs b/actix-http/src/macros.rs index b970b14f2..e08d62ba6 100644 --- a/actix-http/src/macros.rs +++ b/actix-http/src/macros.rs @@ -38,7 +38,7 @@ macro_rules! downcast { /// Downcasts generic body to a specific type. pub fn downcast_ref(&self) -> Option<&T> { if self.__private_get_type_id__().0 == std::any::TypeId::of::() { - // Safety: external crates cannot override the default + // SAFETY: external crates cannot override the default // implementation of `__private_get_type_id__`, since // it requires returning a private type. We can therefore // rely on the returned `TypeId`, which ensures that this @@ -48,10 +48,11 @@ macro_rules! downcast { None } } + /// Downcasts a generic body to a mutable specific type. pub fn downcast_mut(&mut self) -> Option<&mut T> { if self.__private_get_type_id__().0 == std::any::TypeId::of::() { - // Safety: external crates cannot override the default + // SAFETY: external crates cannot override the default // implementation of `__private_get_type_id__`, since // it requires returning a private type. We can therefore // rely on the returned `TypeId`, which ensures that this diff --git a/actix-http/src/ws/mask.rs b/actix-http/src/ws/mask.rs index 367fb0212..726b1a4a1 100644 --- a/actix-http/src/ws/mask.rs +++ b/actix-http/src/ws/mask.rs @@ -7,6 +7,8 @@ use std::slice; struct ShortSlice<'a>(&'a mut [u8]); impl<'a> ShortSlice<'a> { + /// # Safety + /// Given slice must be shorter than 8 bytes. unsafe fn new(slice: &'a mut [u8]) -> Self { // Sanity check for debug builds debug_assert!(slice.len() < 8); @@ -46,13 +48,13 @@ pub(crate) fn apply_mask(buf: &mut [u8], mask_u32: u32) { } } -#[inline] // TODO: copy_nonoverlapping here compiles to call memcpy. While it is not so // inefficient, it could be done better. The compiler does not understand that // a `ShortSlice` must be smaller than a u64. +#[inline] #[allow(clippy::needless_pass_by_value)] fn xor_short(buf: ShortSlice<'_>, mask: u64) { - // Unsafe: we know that a `ShortSlice` fits in a u64 + // SAFETY: we know that a `ShortSlice` fits in a u64 unsafe { let (ptr, len) = (buf.0.as_mut_ptr(), buf.0.len()); let mut b: u64 = 0; @@ -64,8 +66,9 @@ fn xor_short(buf: ShortSlice<'_>, mask: u64) { } } +/// # Safety +/// Caller must ensure the buffer has the correct size and alignment. #[inline] -// Unsafe: caller must ensure the buffer has the correct size and alignment unsafe fn cast_slice(buf: &mut [u8]) -> &mut [u64] { // Assert correct size and alignment in debug builds debug_assert!(buf.len().trailing_zeros() >= 3); @@ -74,9 +77,9 @@ unsafe fn cast_slice(buf: &mut [u8]) -> &mut [u64] { slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut u64, buf.len() >> 3) } -#[inline] // Splits a slice into three parts: an unaligned short head and tail, plus an aligned // u64 mid section. +#[inline] fn align_buf(buf: &mut [u8]) -> (ShortSlice<'_>, &mut [u64], ShortSlice<'_>) { let start_ptr = buf.as_ptr() as usize; let end_ptr = start_ptr + buf.len(); @@ -91,13 +94,13 @@ fn align_buf(buf: &mut [u8]) -> (ShortSlice<'_>, &mut [u64], ShortSlice<'_>) { let (tmp, tail) = buf.split_at_mut(end_aligned - start_ptr); let (head, mid) = tmp.split_at_mut(start_aligned - start_ptr); - // Unsafe: we know the middle section is correctly aligned, and the outer + // SAFETY: we know the middle section is correctly aligned, and the outer // sections are smaller than 8 bytes unsafe { (ShortSlice::new(head), cast_slice(mid), ShortSlice(tail)) } } else { // We didn't cross even one aligned boundary! - // Unsafe: The outer sections are smaller than 8 bytes + // SAFETY: The outer sections are smaller than 8 bytes unsafe { (ShortSlice::new(buf), &mut [], ShortSlice::new(&mut [])) } } } From c54d73e0bbf517284ef2d0092e0e77746db2b60e Mon Sep 17 00:00:00 2001 From: Igor Aleksanov Date: Mon, 7 Sep 2020 14:04:54 +0300 Subject: [PATCH 05/20] Improve awc websocket docs (#1654) Co-authored-by: Rob Ede --- awc/src/lib.rs | 3 ++- awc/src/ws.rs | 27 +++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/awc/src/lib.rs b/awc/src/lib.rs index 1cc31a194..a98d6767d 100644 --- a/awc/src/lib.rs +++ b/awc/src/lib.rs @@ -193,7 +193,8 @@ impl Client { self.request(Method::OPTIONS, url) } - /// Construct WebSockets request. + /// Initialize a WebSocket connection. + /// Returns a WebSocket connection builder. pub fn ws(&self, url: U) -> ws::WebsocketsRequest where Uri: TryFrom, diff --git a/awc/src/ws.rs b/awc/src/ws.rs index 8b01e5716..96687ac74 100644 --- a/awc/src/ws.rs +++ b/awc/src/ws.rs @@ -1,4 +1,31 @@ //! Websockets client +//! +//! Type definitions required to use [`awc::Client`](../struct.Client.html) as a WebSocket client. +//! +//! # Example +//! +//! ``` +//! use awc::{Client, ws}; +//! use futures_util::{sink::SinkExt, stream::StreamExt}; +//! +//! #[actix_rt::main] +//! async fn main() { +//! let (_resp, mut connection) = Client::new() +//! .ws("ws://echo.websocket.org") +//! .connect() +//! .await +//! .unwrap(); +//! +//! connection +//! .send(ws::Message::Text("Echo".to_string())) +//! .await +//! .unwrap(); +//! let response = connection.next().await.unwrap().unwrap(); +//! +//! assert_eq!(response, ws::Frame::Text("Echo".as_bytes().into())); +//! } +//! ``` + use std::convert::TryFrom; use std::net::SocketAddr; use std::rc::Rc; From 9d0534999d91bb512581021e85da552cf91badc0 Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Wed, 9 Sep 2020 09:20:54 +0100 Subject: [PATCH 06/20] bump connect and tls versions (#1655) --- CHANGES.md | 4 ++++ Cargo.toml | 2 +- MIGRATION.md | 4 ++++ actix-http/Cargo.toml | 8 ++++---- actix-http/src/h1/service.rs | 16 ++++++++-------- actix-http/src/h2/service.rs | 16 ++++++++-------- actix-http/src/service.rs | 16 ++++++++-------- awc/Cargo.toml | 4 ++-- docs/graphs/net-only.dot | 2 +- docs/graphs/web-focus.dot | 2 +- src/server.rs | 29 ++++++++++++++++------------- test-server/Cargo.toml | 2 +- tests/test_httpserver.rs | 4 ++-- 13 files changed, 60 insertions(+), 49 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 82c562f5c..291aa8227 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -9,10 +9,14 @@ * Update actix-codec and actix-utils dependencies. [#1634] * `FormConfig` and `JsonConfig` configurations are now also considered when set using `App::data`. [#1641] +* `HttpServer::maxconn` is renamed to the more expressive `HttpServer::max_connections`. [#1655] +* `HttpServer::maxconnrate` is renamed to the more expressive + `HttpServer::max_connection_rate`. [#1655] [#1639]: https://github.com/actix/actix-web/pull/1639 [#1641]: https://github.com/actix/actix-web/pull/1641 [#1634]: https://github.com/actix/actix-web/pull/1634 +[#1655]: https://github.com/actix/actix-web/pull/1655 ## 3.0.0-beta.3 - 2020-08-17 ### Changed diff --git a/Cargo.toml b/Cargo.toml index dbdab5937..6a02b30f9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -74,7 +74,7 @@ actix-server = "1.0.0" actix-testing = "1.0.0" actix-macros = "0.1.0" actix-threadpool = "0.3.1" -actix-tls = "2.0.0-alpha.2" +actix-tls = "2.0.0" actix-web-codegen = "0.3.0-beta.1" actix-http = "2.0.0-beta.3" diff --git a/MIGRATION.md b/MIGRATION.md index 0e73b7d47..15045ed69 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -36,6 +36,10 @@ It will need `middleware::normalize::TrailingSlash` when being constructed with `NormalizePath::new(...)`, or for an easier migration you can replace `wrap(middleware::NormalizePath)` with `wrap(middleware::NormalizePath::default())`. +* `HttpServer::maxconn` is renamed to the more expressive `HttpServer::max_connections`. + +* `HttpServer::maxconnrate` is renamed to the more expressive `HttpServer::max_connection_rate`. + ## 2.0.0 * `HttpServer::start()` renamed to `HttpServer::run()`. It also possible to diff --git a/actix-http/Cargo.toml b/actix-http/Cargo.toml index 750d1e0af..3c8fb2e21 100644 --- a/actix-http/Cargo.toml +++ b/actix-http/Cargo.toml @@ -42,11 +42,11 @@ actors = ["actix"] [dependencies] actix-service = "1.0.5" actix-codec = "0.3.0" -actix-connect = "2.0.0-alpha.4" +actix-connect = "2.0.0" actix-utils = "2.0.0" actix-rt = "1.0.0" actix-threadpool = "0.3.1" -actix-tls = { version = "2.0.0-alpha.2", optional = true } +actix-tls = { version = "2.0.0", optional = true } actix = { version = "0.10.0-alpha.1", optional = true } base64 = "0.12" @@ -87,9 +87,9 @@ flate2 = { version = "1.0.13", optional = true } [dev-dependencies] actix-server = "1.0.1" -actix-connect = { version = "2.0.0-alpha.4", features = ["openssl"] } +actix-connect = { version = "2.0.0", features = ["openssl"] } actix-http-test = { version = "2.0.0-alpha.1", features = ["openssl"] } -actix-tls = { version = "2.0.0-alpha.2", features = ["openssl"] } +actix-tls = { version = "2.0.0", features = ["openssl"] } criterion = "0.3" env_logger = "0.7" serde_derive = "1.0" diff --git a/actix-http/src/h1/service.rs b/actix-http/src/h1/service.rs index 339a0f538..6aafd4089 100644 --- a/actix-http/src/h1/service.rs +++ b/actix-http/src/h1/service.rs @@ -98,7 +98,7 @@ mod openssl { use super::*; use actix_tls::openssl::{Acceptor, SslAcceptor, SslStream}; - use actix_tls::{openssl::HandshakeError, SslError}; + use actix_tls::{openssl::HandshakeError, TlsError}; impl H1Service, S, B, X, U> where @@ -126,19 +126,19 @@ mod openssl { Config = (), Request = TcpStream, Response = (), - Error = SslError, DispatchError>, + Error = TlsError, DispatchError>, InitError = (), > { pipeline_factory( Acceptor::new(acceptor) - .map_err(SslError::Ssl) + .map_err(TlsError::Tls) .map_init_err(|_| panic!()), ) .and_then(|io: SslStream| { let peer_addr = io.get_ref().peer_addr().ok(); ok((io, peer_addr)) }) - .and_then(self.map_err(SslError::Service)) + .and_then(self.map_err(TlsError::Service)) } } } @@ -147,7 +147,7 @@ mod openssl { mod rustls { use super::*; use actix_tls::rustls::{Acceptor, ServerConfig, TlsStream}; - use actix_tls::SslError; + use actix_tls::TlsError; use std::{fmt, io}; impl H1Service, S, B, X, U> @@ -176,19 +176,19 @@ mod rustls { Config = (), Request = TcpStream, Response = (), - Error = SslError, + Error = TlsError, InitError = (), > { pipeline_factory( Acceptor::new(config) - .map_err(SslError::Ssl) + .map_err(TlsError::Tls) .map_init_err(|_| panic!()), ) .and_then(|io: TlsStream| { let peer_addr = io.get_ref().0.peer_addr().ok(); ok((io, peer_addr)) }) - .and_then(self.map_err(SslError::Service)) + .and_then(self.map_err(TlsError::Service)) } } } diff --git a/actix-http/src/h2/service.rs b/actix-http/src/h2/service.rs index eef5dd02c..6b5620e02 100644 --- a/actix-http/src/h2/service.rs +++ b/actix-http/src/h2/service.rs @@ -97,7 +97,7 @@ where mod openssl { use actix_service::{fn_factory, fn_service}; use actix_tls::openssl::{Acceptor, SslAcceptor, SslStream}; - use actix_tls::{openssl::HandshakeError, SslError}; + use actix_tls::{openssl::HandshakeError, TlsError}; use super::*; @@ -117,12 +117,12 @@ mod openssl { Config = (), Request = TcpStream, Response = (), - Error = SslError, DispatchError>, + Error = TlsError, DispatchError>, InitError = S::InitError, > { pipeline_factory( Acceptor::new(acceptor) - .map_err(SslError::Ssl) + .map_err(TlsError::Tls) .map_init_err(|_| panic!()), ) .and_then(fn_factory(|| { @@ -131,7 +131,7 @@ mod openssl { ok((io, peer_addr)) })) })) - .and_then(self.map_err(SslError::Service)) + .and_then(self.map_err(TlsError::Service)) } } } @@ -140,7 +140,7 @@ mod openssl { mod rustls { use super::*; use actix_tls::rustls::{Acceptor, ServerConfig, TlsStream}; - use actix_tls::SslError; + use actix_tls::TlsError; use std::io; impl H2Service, S, B> @@ -159,7 +159,7 @@ mod rustls { Config = (), Request = TcpStream, Response = (), - Error = SslError, + Error = TlsError, InitError = S::InitError, > { let protos = vec!["h2".to_string().into()]; @@ -167,7 +167,7 @@ mod rustls { pipeline_factory( Acceptor::new(config) - .map_err(SslError::Ssl) + .map_err(TlsError::Tls) .map_init_err(|_| panic!()), ) .and_then(fn_factory(|| { @@ -176,7 +176,7 @@ mod rustls { ok((io, peer_addr)) })) })) - .and_then(self.map_err(SslError::Service)) + .and_then(self.map_err(TlsError::Service)) } } } diff --git a/actix-http/src/service.rs b/actix-http/src/service.rs index 94cdbc828..9ee579702 100644 --- a/actix-http/src/service.rs +++ b/actix-http/src/service.rs @@ -195,7 +195,7 @@ where mod openssl { use super::*; use actix_tls::openssl::{Acceptor, SslAcceptor, SslStream}; - use actix_tls::{openssl::HandshakeError, SslError}; + use actix_tls::{openssl::HandshakeError, TlsError}; impl HttpService, S, B, X, U> where @@ -226,12 +226,12 @@ mod openssl { Config = (), Request = TcpStream, Response = (), - Error = SslError, DispatchError>, + Error = TlsError, DispatchError>, InitError = (), > { pipeline_factory( Acceptor::new(acceptor) - .map_err(SslError::Ssl) + .map_err(TlsError::Tls) .map_init_err(|_| panic!()), ) .and_then(|io: SslStream| { @@ -247,7 +247,7 @@ mod openssl { let peer_addr = io.get_ref().peer_addr().ok(); ok((io, proto, peer_addr)) }) - .and_then(self.map_err(SslError::Service)) + .and_then(self.map_err(TlsError::Service)) } } } @@ -256,7 +256,7 @@ mod openssl { mod rustls { use super::*; use actix_tls::rustls::{Acceptor, ServerConfig, Session, TlsStream}; - use actix_tls::SslError; + use actix_tls::TlsError; use std::io; impl HttpService, S, B, X, U> @@ -288,7 +288,7 @@ mod rustls { Config = (), Request = TcpStream, Response = (), - Error = SslError, + Error = TlsError, InitError = (), > { let protos = vec!["h2".to_string().into(), "http/1.1".to_string().into()]; @@ -296,7 +296,7 @@ mod rustls { pipeline_factory( Acceptor::new(config) - .map_err(SslError::Ssl) + .map_err(TlsError::Tls) .map_init_err(|_| panic!()), ) .and_then(|io: TlsStream| { @@ -312,7 +312,7 @@ mod rustls { let peer_addr = io.get_ref().0.peer_addr().ok(); ok((io, proto, peer_addr)) }) - .and_then(self.map_err(SslError::Service)) + .and_then(self.map_err(TlsError::Service)) } } } diff --git a/awc/Cargo.toml b/awc/Cargo.toml index ff0afaa1c..054f465c0 100644 --- a/awc/Cargo.toml +++ b/awc/Cargo.toml @@ -57,13 +57,13 @@ open-ssl = { version = "0.10", package = "openssl", optional = true } rust-tls = { version = "0.18.0", package = "rustls", optional = true, features = ["dangerous_configuration"] } [dev-dependencies] -actix-connect = { version = "2.0.0-alpha.4", features = ["openssl"] } +actix-connect = { version = "2.0.0", features = ["openssl"] } actix-web = { version = "3.0.0-beta.2", features = ["openssl"] } actix-http = { version = "2.0.0-beta.3", features = ["openssl"] } actix-http-test = { version = "2.0.0-alpha.1", features = ["openssl"] } actix-utils = "2.0.0" actix-server = "1.0.0" -actix-tls = { version = "2.0.0-alpha.2", features = ["openssl", "rustls"] } +actix-tls = { version = "2.0.0", features = ["openssl", "rustls"] } brotli2 = "0.3.2" flate2 = "1.0.13" futures-util = { version = "0.3.5", default-features = false } diff --git a/docs/graphs/net-only.dot b/docs/graphs/net-only.dot index d9f2317a1..0eebf2a6f 100644 --- a/docs/graphs/net-only.dot +++ b/docs/graphs/net-only.dot @@ -17,7 +17,7 @@ digraph { "actix-utils" -> { "actix-service" "actix-rt" "actix-codec" } "actix-tracing" -> { "actix-service" } - "actix-tls" -> { "actix-service" "actix-codec" "actix-utils" "actix-rt" } + "actix-tls" -> { "actix-service" "actix-codec" "actix-utils" } "actix-testing" -> { "actix-rt" "actix-macros" "actix-server" "actix-service" } "actix-server" -> { "actix-service" "actix-rt" "actix-codec" "actix-utils" } "actix-rt" -> { "actix-macros" "actix-threadpool" } diff --git a/docs/graphs/web-focus.dot b/docs/graphs/web-focus.dot index b0ce18d02..7abd51268 100644 --- a/docs/graphs/web-focus.dot +++ b/docs/graphs/web-focus.dot @@ -22,7 +22,7 @@ digraph { "actix-utils" -> { "actix-service" "actix-rt" "actix-codec" } "actix-tracing" -> { "actix-service" } - "actix-tls" -> { "actix-service" "actix-codec" "actix-utils" "actix-rt" } + "actix-tls" -> { "actix-service" "actix-codec" "actix-utils" } "actix-testing" -> { "actix-rt" "actix-macros" "actix-server" "actix-service" } "actix-server" -> { "actix-service" "actix-rt" "actix-codec" "actix-utils" } "actix-rt" -> { "actix-macros" "actix-threadpool" } diff --git a/src/server.rs b/src/server.rs index b2695b004..2b86f7416 100644 --- a/src/server.rs +++ b/src/server.rs @@ -122,23 +122,23 @@ where /// Sets the maximum per-worker number of concurrent connections. /// - /// All socket listeners will stop accepting connections when this limit is reached - /// for each worker. + /// All socket listeners will stop accepting connections when this limit is reached for + /// each worker. /// /// By default max connections is set to a 25k. - pub fn maxconn(mut self, num: usize) -> Self { + pub fn max_connections(mut self, num: usize) -> Self { self.builder = self.builder.maxconn(num); self } /// Sets the maximum per-worker concurrent connection establish process. /// - /// All listeners will stop accepting connections when this limit is reached. It - /// can be used to limit the global SSL CPU usage. + /// All listeners will stop accepting connections when this limit is reached. It can be used to + /// limit the global TLS CPU usage. /// /// By default max connections is set to a 256. - pub fn maxconnrate(self, num: usize) -> Self { - actix_tls::max_concurrent_ssl_connect(num); + pub fn max_connection_rate(self, num: usize) -> Self { + actix_tls::max_concurrent_tls_connect(num); self } @@ -375,19 +375,20 @@ where addr: A, ) -> io::Result> { let mut err = None; - let mut succ = false; + let mut success = false; let mut sockets = Vec::new(); + for addr in addr.to_socket_addrs()? { match create_tcp_listener(addr, self.backlog) { Ok(lst) => { - succ = true; + success = true; sockets.push(lst); } Err(e) => err = Some(e), } } - if !succ { + if !success { if let Some(e) = err.take() { Err(e) } else { @@ -575,17 +576,19 @@ fn create_tcp_listener( #[cfg(feature = "openssl")] /// Configure `SslAcceptorBuilder` with custom server flags. fn openssl_acceptor(mut builder: SslAcceptorBuilder) -> io::Result { - builder.set_alpn_select_callback(|_, protos| { + builder.set_alpn_select_callback(|_, protocols| { const H2: &[u8] = b"\x02h2"; const H11: &[u8] = b"\x08http/1.1"; - if protos.windows(3).any(|window| window == H2) { + + if protocols.windows(3).any(|window| window == H2) { Ok(b"h2") - } else if protos.windows(9).any(|window| window == H11) { + } else if protocols.windows(9).any(|window| window == H11) { Ok(b"http/1.1") } else { Err(AlpnError::NOACK) } }); + builder.set_alpn_protos(b"\x08http/1.1\x02h2")?; Ok(builder.build()) diff --git a/test-server/Cargo.toml b/test-server/Cargo.toml index 13f27ab59..b82dc5432 100644 --- a/test-server/Cargo.toml +++ b/test-server/Cargo.toml @@ -31,7 +31,7 @@ openssl = ["open-ssl", "awc/openssl"] [dependencies] actix-service = "1.0.1" actix-codec = "0.3.0" -actix-connect = "2.0.0-alpha.4" +actix-connect = "2.0.0" actix-utils = "2.0.0" actix-rt = "1.0.0" actix-server = "1.0.0" diff --git a/tests/test_httpserver.rs b/tests/test_httpserver.rs index 750084fdc..50c0a7649 100644 --- a/tests/test_httpserver.rs +++ b/tests/test_httpserver.rs @@ -22,8 +22,8 @@ async fn test_start() { }) .workers(1) .backlog(1) - .maxconn(10) - .maxconnrate(10) + .max_connections(10) + .max_connection_rate(10) .keep_alive(10) .client_timeout(5000) .client_shutdown(0) From 3a27580ebe89ad7bb082bcb7bc2c1c26b2be2690 Mon Sep 17 00:00:00 2001 From: Igor Aleksanov Date: Wed, 9 Sep 2020 16:24:12 +0300 Subject: [PATCH 07/20] awc: improve module documentation (#1656) Co-authored-by: Rob Ede --- awc/src/lib.rs | 101 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 86 insertions(+), 15 deletions(-) diff --git a/awc/src/lib.rs b/awc/src/lib.rs index a98d6767d..7167dbb96 100644 --- a/awc/src/lib.rs +++ b/awc/src/lib.rs @@ -4,24 +4,93 @@ clippy::borrow_interior_mutable_const, clippy::needless_doctest_main )] -//! An HTTP Client + +//! `awc` is a HTTP and WebSocket client library built using the Actix ecosystem. +//! +//! ## Making a GET request //! //! ```rust -//! use actix_rt::System; -//! use awc::Client; +//! # #[actix_rt::main] +//! # async fn main() -> Result<(), awc::error::SendRequestError> { +//! let mut client = awc::Client::default(); +//! let response = client.get("http://www.rust-lang.org") // <- Create request builder +//! .header("User-Agent", "Actix-web") +//! .send() // <- Send http request +//! .await?; //! -//! #[actix_rt::main] -//! async fn main() { -//! let mut client = Client::default(); -//! -//! let response = client.get("http://www.rust-lang.org") // <- Create request builder -//! .header("User-Agent", "Actix-web") -//! .send() // <- Send http request -//! .await; -//! -//! println!("Response: {:?}", response); -//! } +//! println!("Response: {:?}", response); +//! # Ok(()) +//! # } //! ``` +//! +//! ## Making POST requests +//! +//! ### Raw body contents +//! +//! ```rust +//! # #[actix_rt::main] +//! # async fn main() -> Result<(), awc::error::SendRequestError> { +//! let mut client = awc::Client::default(); +//! let response = client.post("http://httpbin.org/post") +//! .send_body("Raw body contents") +//! .await?; +//! # Ok(()) +//! # } +//! ``` +//! +//! ### Forms +//! +//! ```rust +//! # #[actix_rt::main] +//! # async fn main() -> Result<(), awc::error::SendRequestError> { +//! let params = [("foo", "bar"), ("baz", "quux")]; +//! +//! let mut client = awc::Client::default(); +//! let response = client.post("http://httpbin.org/post") +//! .send_form(¶ms) +//! .await?; +//! # Ok(()) +//! # } +//! ``` +//! +//! ### JSON +//! +//! ```rust +//! # #[actix_rt::main] +//! # async fn main() -> Result<(), awc::error::SendRequestError> { +//! let request = serde_json::json!({ +//! "lang": "rust", +//! "body": "json" +//! }); +//! +//! let mut client = awc::Client::default(); +//! let response = client.post("http://httpbin.org/post") +//! .send_json(&request) +//! .await?; +//! # Ok(()) +//! # } +//! ``` +//! +//! ## WebSocket support +//! +//! ``` +//! # #[actix_rt::main] +//! # async fn main() -> Result<(), Box> { +//! use futures_util::{sink::SinkExt, stream::StreamExt}; +//! let (_resp, mut connection) = awc::Client::new() +//! .ws("ws://echo.websocket.org") +//! .connect() +//! .await?; +//! +//! connection +//! .send(awc::ws::Message::Text("Echo".to_string())) +//! .await?; +//! let response = connection.next().await.unwrap()?; +//! # assert_eq!(response, awc::ws::Frame::Text("Echo".as_bytes().into())); +//! # Ok(()) +//! # } +//! ``` + use std::cell::RefCell; use std::convert::TryFrom; use std::rc::Rc; @@ -51,7 +120,9 @@ pub use self::sender::SendClientRequest; use self::connect::{Connect, ConnectorWrapper}; -/// An HTTP Client +/// An asynchronous HTTP and WebSocket client. +/// +/// ## Examples /// /// ```rust /// use awc::Client; From 059d1671d7649aad833b5271bcd8172235352bc7 Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Wed, 9 Sep 2020 22:14:11 +0100 Subject: [PATCH 08/20] prepare release beta 4 (#1659) --- Cargo.toml | 6 +- actix-files/Cargo.toml | 6 +- actix-http/CHANGES.md | 7 +- actix-http/Cargo.toml | 2 +- actix-http/LICENSE-APACHE | 202 +---------------------------------- actix-http/LICENSE-MIT | 26 +---- actix-multipart/Cargo.toml | 4 +- actix-web-actors/Cargo.toml | 4 +- actix-web-codegen/Cargo.toml | 2 +- awc/CHANGES.md | 5 +- awc/Cargo.toml | 8 +- test-server/Cargo.toml | 6 +- 12 files changed, 31 insertions(+), 247 deletions(-) mode change 100644 => 120000 actix-http/LICENSE-APACHE mode change 100644 => 120000 actix-http/LICENSE-MIT diff --git a/Cargo.toml b/Cargo.toml index 6a02b30f9..11559bcae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "actix-web" -version = "3.0.0-beta.3" +version = "3.0.0-beta.4" authors = ["Nikolay Kim "] description = "Actix web is a simple, pragmatic and extremely fast web framework for Rust." readme = "README.md" @@ -77,8 +77,8 @@ actix-threadpool = "0.3.1" actix-tls = "2.0.0" actix-web-codegen = "0.3.0-beta.1" -actix-http = "2.0.0-beta.3" -awc = { version = "2.0.0-beta.3", default-features = false } +actix-http = "2.0.0-beta.4" +awc = { version = "2.0.0-beta.4", default-features = false } bytes = "0.5.3" derive_more = "0.99.2" diff --git a/actix-files/Cargo.toml b/actix-files/Cargo.toml index c3444809e..4c6441324 100644 --- a/actix-files/Cargo.toml +++ b/actix-files/Cargo.toml @@ -17,8 +17,8 @@ name = "actix_files" path = "src/lib.rs" [dependencies] -actix-web = { version = "3.0.0-beta.3", default-features = false } -actix-http = "2.0.0-beta.3" +actix-web = { version = "3.0.0-beta.4", default-features = false } +actix-http = "2.0.0-beta.4" actix-service = "1.0.1" bitflags = "1" bytes = "0.5.3" @@ -33,4 +33,4 @@ v_htmlescape = "0.10" [dev-dependencies] actix-rt = "1.0.0" -actix-web = { version = "3.0.0-beta.3", features = ["openssl"] } +actix-web = { version = "3.0.0-beta.4", features = ["openssl"] } diff --git a/actix-http/CHANGES.md b/actix-http/CHANGES.md index d8d674fb1..dfa55e7f1 100644 --- a/actix-http/CHANGES.md +++ b/actix-http/CHANGES.md @@ -1,8 +1,13 @@ # Changes -## Unreleased +## Unreleased - 2020-xx-xx + + +## 2.0.0-beta.4 - 2020-09-09 ### Changed * Update actix-codec and actix-utils dependencies. +* Update actix-connect and actix-tls dependencies. + ## [2.0.0-beta.3] - 2020-08-14 diff --git a/actix-http/Cargo.toml b/actix-http/Cargo.toml index 3c8fb2e21..6d8d143ed 100644 --- a/actix-http/Cargo.toml +++ b/actix-http/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "actix-http" -version = "2.0.0-beta.3" +version = "2.0.0-beta.4" authors = ["Nikolay Kim "] description = "Actix HTTP primitives" readme = "README.md" diff --git a/actix-http/LICENSE-APACHE b/actix-http/LICENSE-APACHE deleted file mode 100644 index 6cdf2d16c..000000000 --- a/actix-http/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2017-NOW Nikolay Kim - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/actix-http/LICENSE-APACHE b/actix-http/LICENSE-APACHE new file mode 120000 index 000000000..965b606f3 --- /dev/null +++ b/actix-http/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/actix-http/LICENSE-MIT b/actix-http/LICENSE-MIT deleted file mode 100644 index 0f80296ae..000000000 --- a/actix-http/LICENSE-MIT +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2017 Nikolay Kim - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/actix-http/LICENSE-MIT b/actix-http/LICENSE-MIT new file mode 120000 index 000000000..76219eb72 --- /dev/null +++ b/actix-http/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/actix-multipart/Cargo.toml b/actix-multipart/Cargo.toml index 58f7113e5..1ea2c7aac 100644 --- a/actix-multipart/Cargo.toml +++ b/actix-multipart/Cargo.toml @@ -16,7 +16,7 @@ name = "actix_multipart" path = "src/lib.rs" [dependencies] -actix-web = { version = "3.0.0-beta.3", default-features = false } +actix-web = { version = "3.0.0-beta.4", default-features = false } actix-service = "1.0.1" actix-utils = "2.0.0" bytes = "0.5.3" @@ -29,4 +29,4 @@ twoway = "0.2" [dev-dependencies] actix-rt = "1.0.0" -actix-http = "2.0.0-beta.3" +actix-http = "2.0.0-beta.4" diff --git a/actix-web-actors/Cargo.toml b/actix-web-actors/Cargo.toml index b33acc222..0ca340605 100644 --- a/actix-web-actors/Cargo.toml +++ b/actix-web-actors/Cargo.toml @@ -17,8 +17,8 @@ path = "src/lib.rs" [dependencies] actix = "0.10.0-alpha.2" -actix-web = { version = "3.0.0-beta.3", default-features = false } -actix-http = "2.0.0-beta.3" +actix-web = { version = "3.0.0-beta.4", default-features = false } +actix-http = "2.0.0-beta.4" actix-codec = "0.3.0" bytes = "0.5.2" futures-channel = { version = "0.3.5", default-features = false } diff --git a/actix-web-codegen/Cargo.toml b/actix-web-codegen/Cargo.toml index 62cbf2941..ddd886c40 100644 --- a/actix-web-codegen/Cargo.toml +++ b/actix-web-codegen/Cargo.toml @@ -20,5 +20,5 @@ proc-macro2 = "1" [dev-dependencies] actix-rt = "1.0.0" -actix-web = "3.0.0-beta.3" +actix-web = "3.0.0-beta.4" futures-util = { version = "0.3.5", default-features = false } diff --git a/awc/CHANGES.md b/awc/CHANGES.md index 8d1b58856..4a830b8fc 100644 --- a/awc/CHANGES.md +++ b/awc/CHANGES.md @@ -1,8 +1,11 @@ # Changes ## Unreleased - 2020-xx-xx + + +## 2.0.0-beta.4 - 2020-09-09 ### Changed -* Update actix-codec dependency. +* Update actix-codec & actix-tls dependencies. ## 2.0.0-beta.3 - 2020-08-17 diff --git a/awc/Cargo.toml b/awc/Cargo.toml index 054f465c0..b55f4dabb 100644 --- a/awc/Cargo.toml +++ b/awc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "awc" -version = "2.0.0-beta.3" +version = "2.0.0-beta.4" authors = ["Nikolay Kim "] description = "Async HTTP client library that uses the Actix runtime." readme = "README.md" @@ -39,7 +39,7 @@ compress = ["actix-http/compress"] [dependencies] actix-codec = "0.3.0" actix-service = "1.0.1" -actix-http = "2.0.0-beta.3" +actix-http = "2.0.0-beta.4" actix-rt = "1.0.0" base64 = "0.12" @@ -58,8 +58,8 @@ rust-tls = { version = "0.18.0", package = "rustls", optional = true, features = [dev-dependencies] actix-connect = { version = "2.0.0", features = ["openssl"] } -actix-web = { version = "3.0.0-beta.2", features = ["openssl"] } -actix-http = { version = "2.0.0-beta.3", features = ["openssl"] } +actix-web = { version = "3.0.0-beta.4", features = ["openssl"] } +actix-http = { version = "2.0.0-beta.4", features = ["openssl"] } actix-http-test = { version = "2.0.0-alpha.1", features = ["openssl"] } actix-utils = "2.0.0" actix-server = "1.0.0" diff --git a/test-server/Cargo.toml b/test-server/Cargo.toml index b82dc5432..8aecda401 100644 --- a/test-server/Cargo.toml +++ b/test-server/Cargo.toml @@ -36,7 +36,7 @@ actix-utils = "2.0.0" actix-rt = "1.0.0" actix-server = "1.0.0" actix-testing = "1.0.0" -awc = "2.0.0-beta.3" +awc = "2.0.0-beta.4" base64 = "0.12" bytes = "0.5.3" @@ -52,5 +52,5 @@ time = { version = "0.2.7", default-features = false, features = ["std"] } open-ssl = { version = "0.10", package = "openssl", optional = true } [dev-dependencies] -actix-web = "3.0.0-beta.3" -actix-http = "2.0.0-beta.3" +actix-web = "3.0.0-beta.4" +actix-http = "2.0.0-beta.4" From e39d166a1751dfc03e39613f015b164ed6061cfb Mon Sep 17 00:00:00 2001 From: Mufeed VH Date: Thu, 10 Sep 2020 04:42:50 +0530 Subject: [PATCH 09/20] Fix examples hyperlink in README (#1660) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a42a1a6f8..48f9d1442 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ ## Documentation * [Website & User Guide](https://actix.rs) -* [Examples Repository](https://actix.rs/actix-web/actix_web) +* [Examples Repository](https://github.com/actix/examples) * [API Documentation](https://docs.rs/actix-web) * [API Documentation (master branch)](https://actix.rs/actix-web/actix_web) From 2f6e9738c4bbb7478671a0e92f178524febf2fea Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Thu, 10 Sep 2020 12:54:27 +0100 Subject: [PATCH 10/20] prepare multipart and actors releases (#1663) --- CHANGES.md | 3 +++ actix-multipart/CHANGES.md | 4 ++++ actix-multipart/Cargo.toml | 2 +- actix-multipart/src/lib.rs | 2 ++ actix-web-actors/CHANGES.md | 6 +++++- actix-web-actors/Cargo.toml | 2 +- actix-web-actors/src/lib.rs | 4 +++- 7 files changed, 19 insertions(+), 4 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 291aa8227..1779af9ee 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,9 @@ # Changes ## Unreleased - 2020-xx-xx + + +## 3.0.0-beta.4 - 2020-09-09 ### Added * `middleware::NormalizePath` now has configurable behaviour for either always having a trailing slash, or as the new addition, always trimming trailing slashes. [#1639] diff --git a/actix-multipart/CHANGES.md b/actix-multipart/CHANGES.md index 261836223..7149f6713 100644 --- a/actix-multipart/CHANGES.md +++ b/actix-multipart/CHANGES.md @@ -3,6 +3,10 @@ ## Unreleased - 2020-xx-xx +## 3.0.0-beta.2 - 2020-09-10 +* Update `actix-*` dependencies to latest versions. + + ## 0.3.0-beta.1 - 2020-07-15 * Update `actix-web` to 3.0.0-beta.1 diff --git a/actix-multipart/Cargo.toml b/actix-multipart/Cargo.toml index 1ea2c7aac..0fd5d0922 100644 --- a/actix-multipart/Cargo.toml +++ b/actix-multipart/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "actix-multipart" -version = "0.3.0-beta.1" +version = "0.3.0-beta.2" authors = ["Nikolay Kim "] description = "Multipart support for actix web framework." readme = "README.md" diff --git a/actix-multipart/src/lib.rs b/actix-multipart/src/lib.rs index 43eb048ca..b502c63d8 100644 --- a/actix-multipart/src/lib.rs +++ b/actix-multipart/src/lib.rs @@ -1,3 +1,5 @@ +//! Multipart form support for Actix web. + #![allow(clippy::borrow_interior_mutable_const)] mod error; diff --git a/actix-web-actors/CHANGES.md b/actix-web-actors/CHANGES.md index 868f17e2a..4dcd403a3 100644 --- a/actix-web-actors/CHANGES.md +++ b/actix-web-actors/CHANGES.md @@ -1,6 +1,10 @@ # Changes -## [Unreleased] - 2020-xx-xx +## Unreleased - 2020-xx-xx + + +## 3.0.0-beta.2 - 2020-09-10 +* Update `actix-*` dependencies to latest versions. ## [3.0.0-beta.1] - 2020-xx-xx diff --git a/actix-web-actors/Cargo.toml b/actix-web-actors/Cargo.toml index 0ca340605..cb7fd3a80 100644 --- a/actix-web-actors/Cargo.toml +++ b/actix-web-actors/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "actix-web-actors" -version = "3.0.0-beta.1" +version = "3.0.0-beta.2" authors = ["Nikolay Kim "] description = "Actix actors support for actix web framework." readme = "README.md" diff --git a/actix-web-actors/src/lib.rs b/actix-web-actors/src/lib.rs index 6360917cd..d6be5eeaf 100644 --- a/actix-web-actors/src/lib.rs +++ b/actix-web-actors/src/lib.rs @@ -1,5 +1,7 @@ -#![allow(clippy::borrow_interior_mutable_const)] //! Actix actors integration for Actix web framework + +#![allow(clippy::borrow_interior_mutable_const)] + mod context; pub mod ws; From 7787638f262cf84c86556a2f3538ee8fe7226a26 Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Thu, 10 Sep 2020 14:46:35 +0100 Subject: [PATCH 11/20] fix CI clippy warnings (#1664) --- actix-files/src/lib.rs | 27 +++++++++++++++------------ actix-http/src/body.rs | 2 +- actix-http/src/client/pool.rs | 4 ++-- actix-http/src/lib.rs | 3 ++- actix-http/src/macros.rs | 2 +- actix-multipart/src/lib.rs | 1 + actix-multipart/src/server.rs | 18 +++++++++++------- actix-web-actors/src/lib.rs | 1 + awc/src/lib.rs | 2 +- awc/src/sender.rs | 6 +----- src/lib.rs | 2 +- 11 files changed, 37 insertions(+), 31 deletions(-) diff --git a/actix-files/src/lib.rs b/actix-files/src/lib.rs index ae0204a71..91c054947 100644 --- a/actix-files/src/lib.rs +++ b/actix-files/src/lib.rs @@ -1,6 +1,8 @@ -#![allow(clippy::borrow_interior_mutable_const, clippy::type_complexity)] - //! Static files support + +#![deny(rust_2018_idioms)] +#![allow(clippy::borrow_interior_mutable_const)] + use std::cell::RefCell; use std::fmt::Write; use std::fs::{DirEntry, File}; @@ -62,6 +64,7 @@ pub struct ChunkedReadFile { size: u64, offset: u64, file: Option, + #[allow(clippy::type_complexity)] fut: Option>>>, counter: u64, @@ -72,7 +75,7 @@ impl Stream for ChunkedReadFile { fn poll_next( mut self: Pin<&mut Self>, - cx: &mut Context, + cx: &mut Context<'_>, ) -> Poll> { if let Some(ref mut fut) = self.fut { return match Pin::new(fut).poll(cx) { @@ -224,7 +227,7 @@ fn directory_listing( )) } -type MimeOverride = dyn Fn(&mime::Name) -> DispositionType; +type MimeOverride = dyn Fn(&mime::Name<'_>) -> DispositionType; /// Static files handling /// @@ -232,12 +235,10 @@ type MimeOverride = dyn Fn(&mime::Name) -> DispositionType; /// /// ```rust /// use actix_web::App; -/// use actix_files as fs; +/// use actix_files::Files; /// -/// fn main() { -/// let app = App::new() -/// .service(fs::Files::new("/static", ".")); -/// } +/// let app = App::new() +/// .service(Files::new("/static", ".")); /// ``` pub struct Files { path: String, @@ -330,7 +331,7 @@ impl Files { /// Specifies mime override callback pub fn mime_override(mut self, f: F) -> Self where - F: Fn(&mime::Name) -> DispositionType + 'static, + F: Fn(&mime::Name<'_>) -> DispositionType + 'static, { self.mime_override = Some(Rc::new(f)); self @@ -469,6 +470,7 @@ pub struct FilesService { } impl FilesService { + #[allow(clippy::type_complexity)] fn handle_err( &mut self, e: io::Error, @@ -490,12 +492,13 @@ impl Service for FilesService { type Request = ServiceRequest; type Response = ServiceResponse; type Error = Error; + #[allow(clippy::type_complexity)] type Future = Either< Ready>, LocalBoxFuture<'static, Result>, >; - fn poll_ready(&mut self, _: &mut Context) -> Poll> { + fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll> { Poll::Ready(Ok(())) } @@ -898,7 +901,7 @@ mod tests { #[actix_rt::test] async fn test_mime_override() { - fn all_attachment(_: &mime::Name) -> DispositionType { + fn all_attachment(_: &mime::Name<'_>) -> DispositionType { DispositionType::Attachment } diff --git a/actix-http/src/body.rs b/actix-http/src/body.rs index 8bea8e6b8..c5d831c45 100644 --- a/actix-http/src/body.rs +++ b/actix-http/src/body.rs @@ -714,7 +714,7 @@ mod tests { let body = resp_body.downcast_ref::().unwrap(); assert_eq!(body, "hello cast"); let body = &mut resp_body.downcast_mut::().unwrap(); - body.push_str("!"); + body.push('!'); let body = resp_body.downcast_ref::().unwrap(); assert_eq!(body, "hello cast!"); let not_body = resp_body.downcast_ref::<()>(); diff --git a/actix-http/src/client/pool.rs b/actix-http/src/client/pool.rs index 013a79671..08abc6277 100644 --- a/actix-http/src/client/pool.rs +++ b/actix-http/src/client/pool.rs @@ -119,11 +119,11 @@ where match poll_fn(|cx| Poll::Ready(inner.borrow_mut().acquire(&key, cx))).await { Acquire::Acquired(io, created) => { // use existing connection - return Ok(IoConnection::new( + Ok(IoConnection::new( io, created, Some(Acquired(key, Some(inner))), - )); + )) } Acquire::Available => { // open tcp connection diff --git a/actix-http/src/lib.rs b/actix-http/src/lib.rs index dd8f5ee12..b52e8179c 100644 --- a/actix-http/src/lib.rs +++ b/actix-http/src/lib.rs @@ -1,5 +1,6 @@ //! Basic http primitives for actix-net framework. -#![warn(rust_2018_idioms, warnings)] + +#![deny(rust_2018_idioms)] #![allow( clippy::type_complexity, clippy::too_many_arguments, diff --git a/actix-http/src/macros.rs b/actix-http/src/macros.rs index e08d62ba6..8973aa39b 100644 --- a/actix-http/src/macros.rs +++ b/actix-http/src/macros.rs @@ -87,7 +87,7 @@ mod tests { let body = resp_body.downcast_ref::().unwrap(); assert_eq!(body, "hello cast"); let body = &mut resp_body.downcast_mut::().unwrap(); - body.push_str("!"); + body.push('!'); let body = resp_body.downcast_ref::().unwrap(); assert_eq!(body, "hello cast!"); let not_body = resp_body.downcast_ref::<()>(); diff --git a/actix-multipart/src/lib.rs b/actix-multipart/src/lib.rs index b502c63d8..46dd0ee9b 100644 --- a/actix-multipart/src/lib.rs +++ b/actix-multipart/src/lib.rs @@ -1,5 +1,6 @@ //! Multipart form support for Actix web. +#![deny(rust_2018_idioms)] #![allow(clippy::borrow_interior_mutable_const)] mod error; diff --git a/actix-multipart/src/server.rs b/actix-multipart/src/server.rs index 449c7da29..1507959b8 100644 --- a/actix-multipart/src/server.rs +++ b/actix-multipart/src/server.rs @@ -1,4 +1,5 @@ //! Multipart payload support + use std::cell::{Cell, RefCell, RefMut}; use std::convert::TryFrom; use std::marker::PhantomData; @@ -108,7 +109,7 @@ impl Stream for Multipart { fn poll_next( mut self: Pin<&mut Self>, - cx: &mut Context, + cx: &mut Context<'_>, ) -> Poll> { if let Some(err) = self.error.take() { Poll::Ready(Some(Err(err))) @@ -244,7 +245,7 @@ impl InnerMultipart { fn poll( &mut self, safety: &Safety, - cx: &mut Context, + cx: &mut Context<'_>, ) -> Poll>> { if self.state == InnerState::Eof { Poll::Ready(None) @@ -416,7 +417,10 @@ impl Field { impl Stream for Field { type Item = Result; - fn poll_next(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { + fn poll_next( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { if self.safety.current() { let mut inner = self.inner.borrow_mut(); if let Some(mut payload) = @@ -434,7 +438,7 @@ impl Stream for Field { } impl fmt::Debug for Field { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { writeln!(f, "\nField: {}", self.ct)?; writeln!(f, " boundary: {}", self.inner.borrow().boundary)?; writeln!(f, " headers:")?; @@ -689,7 +693,7 @@ impl Safety { self.clean.get() } - fn clone(&self, cx: &mut Context) -> Safety { + fn clone(&self, cx: &mut Context<'_>) -> Safety { let payload = Rc::clone(&self.payload); let s = Safety { task: LocalWaker::new(), @@ -734,7 +738,7 @@ impl PayloadBuffer { } } - fn poll_stream(&mut self, cx: &mut Context) -> Result<(), PayloadError> { + fn poll_stream(&mut self, cx: &mut Context<'_>) -> Result<(), PayloadError> { loop { match Pin::new(&mut self.stream).poll_next(cx) { Poll::Ready(Some(Ok(data))) => self.buf.extend_from_slice(&data), @@ -887,7 +891,7 @@ mod tests { fn poll_next( self: Pin<&mut Self>, - cx: &mut Context, + cx: &mut Context<'_>, ) -> Poll> { let this = self.get_mut(); if !this.ready { diff --git a/actix-web-actors/src/lib.rs b/actix-web-actors/src/lib.rs index d6be5eeaf..0421f05fb 100644 --- a/actix-web-actors/src/lib.rs +++ b/actix-web-actors/src/lib.rs @@ -1,5 +1,6 @@ //! Actix actors integration for Actix web framework +#![deny(rust_2018_idioms)] #![allow(clippy::borrow_interior_mutable_const)] mod context; diff --git a/awc/src/lib.rs b/awc/src/lib.rs index 7167dbb96..4850b78f0 100644 --- a/awc/src/lib.rs +++ b/awc/src/lib.rs @@ -1,4 +1,4 @@ -#![warn(rust_2018_idioms, warnings)] +#![deny(rust_2018_idioms)] #![allow( clippy::type_complexity, clippy::borrow_interior_mutable_const, diff --git a/awc/src/sender.rs b/awc/src/sender.rs index 5e0f5beec..0bcdf4307 100644 --- a/awc/src/sender.rs +++ b/awc/src/sender.rs @@ -193,11 +193,7 @@ impl RequestSender { } }; - SendClientRequest::new( - fut, - response_decompress, - timeout.or_else(|| config.timeout), - ) + SendClientRequest::new(fut, response_decompress, timeout.or(config.timeout)) } pub(crate) fn send_json( diff --git a/src/lib.rs b/src/lib.rs index 3f65e49dd..97141599c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -#![warn(rust_2018_idioms, warnings)] +#![deny(rust_2018_idioms)] #![allow(clippy::needless_doctest_main, clippy::type_complexity)] //! Actix web is a powerful, pragmatic, and extremely fast web framework for Rust. From 22089aff8773b8197a2d6adae6b87fe6853f056a Mon Sep 17 00:00:00 2001 From: Robert Gabriel Jakabosky Date: Thu, 10 Sep 2020 22:40:20 +0800 Subject: [PATCH 12/20] Improve json, form and query extractor config docs (#1661) --- src/types/form.rs | 2 +- src/types/json.rs | 37 ++++++++++++++----------------------- src/types/query.rs | 6 +++--- 3 files changed, 18 insertions(+), 27 deletions(-) diff --git a/src/types/form.rs b/src/types/form.rs index de88c2a94..2a7101287 100644 --- a/src/types/form.rs +++ b/src/types/form.rs @@ -195,7 +195,7 @@ impl Responder for Form { /// web::resource("/index.html") /// // change `Form` extractor configuration /// .app_data( -/// web::Form::::configure(|cfg| cfg.limit(4097)) +/// web::FormConfig::default().limit(4097) /// ) /// .route(web::get().to(index)) /// ); diff --git a/src/types/json.rs b/src/types/json.rs index ab7978dff..8da5a3bdb 100644 --- a/src/types/json.rs +++ b/src/types/json.rs @@ -209,10 +209,10 @@ where /// Json extractor configuration /// -/// # Examples +/// # Example /// /// ```rust -/// use actix_web::{error, web, App, FromRequest, HttpRequest, HttpResponse}; +/// use actix_web::{error, web, App, FromRequest, HttpResponse}; /// use serde_derive::Deserialize; /// /// #[derive(Deserialize)] @@ -225,35 +225,26 @@ where /// format!("Welcome {}!", info.username) /// } /// -/// /// Return either a 400 or 415, and include the error message from serde -/// /// in the response body -/// fn json_error_handler(err: error::JsonPayloadError, _req: &HttpRequest) -> error::Error { -/// let detail = err.to_string(); -/// let response = match &err { -/// error::JsonPayloadError::ContentType => { -/// HttpResponse::UnsupportedMediaType().content_type("text/plain").body(detail) -/// } -/// _ => HttpResponse::BadRequest().content_type("text/plain").body(detail), -/// }; -/// error::InternalError::from_response(err, response).into() -/// } -/// /// fn main() { /// let app = App::new().service( /// web::resource("/index.html") /// .app_data( -/// // change json extractor configuration -/// web::Json::::configure(|cfg| { -/// cfg.limit(4096) -/// .content_type(|mime| { // <- accept text/plain content type -/// mime.type_() == mime::TEXT && mime.subtype() == mime::PLAIN -/// }) -/// .error_handler(json_error_handler) // Use our custom error response -/// })) +/// // Json extractor configuration for this resource. +/// web::JsonConfig::default() +/// .limit(4096) // Limit request payload size +/// .content_type(|mime| { // <- accept text/plain content type +/// mime.type_() == mime::TEXT && mime.subtype() == mime::PLAIN +/// }) +/// .error_handler(|err, req| { // <- create custom error response +/// error::InternalError::from_response( +/// err, HttpResponse::Conflict().finish()).into() +/// }) +/// ) /// .route(web::post().to(index)) /// ); /// } /// ``` +/// #[derive(Clone)] pub struct JsonConfig { limit: usize, diff --git a/src/types/query.rs b/src/types/query.rs index cf1a8930d..f9440e1b4 100644 --- a/src/types/query.rs +++ b/src/types/query.rs @@ -188,12 +188,12 @@ where /// let app = App::new().service( /// web::resource("/index.html").app_data( /// // change query extractor configuration -/// web::Query::::configure(|cfg| { -/// cfg.error_handler(|err, req| { // <- create custom error response +/// web::QueryConfig::default() +/// .error_handler(|err, req| { // <- create custom error response /// error::InternalError::from_response( /// err, HttpResponse::Conflict().finish()).into() /// }) -/// })) +/// ) /// .route(web::post().to(index)) /// ); /// } From 121075c1effdf210973fedc4ee4fe072ca3f87d5 Mon Sep 17 00:00:00 2001 From: Igor Aleksanov Date: Fri, 11 Sep 2020 11:24:39 +0300 Subject: [PATCH 13/20] awc: Rename Client::build to Client::builder (#1665) --- awc/CHANGES.md | 2 ++ awc/src/lib.rs | 5 +++-- awc/src/request.rs | 4 ++-- awc/src/ws.rs | 2 +- awc/tests/test_client.rs | 8 ++++---- awc/tests/test_connector.rs | 2 +- awc/tests/test_rustls_client.rs | 2 +- awc/tests/test_ssl_client.rs | 2 +- src/test.rs | 2 +- test-server/src/lib.rs | 2 +- tests/test_httpserver.rs | 4 ++-- 11 files changed, 19 insertions(+), 16 deletions(-) diff --git a/awc/CHANGES.md b/awc/CHANGES.md index 4a830b8fc..38faba459 100644 --- a/awc/CHANGES.md +++ b/awc/CHANGES.md @@ -1,6 +1,8 @@ # Changes ## Unreleased - 2020-xx-xx +### Changed +* `Client::build` was renamed to `Client::builder`. ## 2.0.0-beta.4 - 2020-09-09 diff --git a/awc/src/lib.rs b/awc/src/lib.rs index 4850b78f0..45c52092a 100644 --- a/awc/src/lib.rs +++ b/awc/src/lib.rs @@ -166,8 +166,9 @@ impl Client { Client::default() } - /// Build client instance. - pub fn build() -> ClientBuilder { + /// Create `Client` builder. + /// This function is equivalent of `ClientBuilder::new()`. + pub fn builder() -> ClientBuilder { ClientBuilder::new() } diff --git a/awc/src/request.rs b/awc/src/request.rs index c34a8e221..dcada2c6d 100644 --- a/awc/src/request.rs +++ b/awc/src/request.rs @@ -623,7 +623,7 @@ mod tests { #[actix_rt::test] async fn test_client_header() { - let req = Client::build() + let req = Client::builder() .header(header::CONTENT_TYPE, "111") .finish() .get("/"); @@ -641,7 +641,7 @@ mod tests { #[actix_rt::test] async fn test_client_header_override() { - let req = Client::build() + let req = Client::builder() .header(header::CONTENT_TYPE, "111") .finish() .get("/") diff --git a/awc/src/ws.rs b/awc/src/ws.rs index 96687ac74..57e80bd46 100644 --- a/awc/src/ws.rs +++ b/awc/src/ws.rs @@ -434,7 +434,7 @@ mod tests { #[actix_rt::test] async fn test_header_override() { - let req = Client::build() + let req = Client::builder() .header(header::CONTENT_TYPE, "111") .finish() .ws("/") diff --git a/awc/tests/test_client.rs b/awc/tests/test_client.rs index 21be155e8..a9552d0d5 100644 --- a/awc/tests/test_client.rs +++ b/awc/tests/test_client.rs @@ -120,7 +120,7 @@ async fn test_timeout() { .timeout(Duration::from_secs(15)) .finish(); - let client = awc::Client::build() + let client = awc::Client::builder() .connector(connector) .timeout(Duration::from_millis(50)) .finish(); @@ -141,7 +141,7 @@ async fn test_timeout_override() { }))) }); - let client = awc::Client::build() + let client = awc::Client::builder() .timeout(Duration::from_millis(50000)) .finish(); let request = client @@ -291,7 +291,7 @@ async fn test_connection_wait_queue() { }) .await; - let client = awc::Client::build() + let client = awc::Client::builder() .connector(awc::Connector::new().limit(1).finish()) .finish(); @@ -340,7 +340,7 @@ async fn test_connection_wait_queue_force_close() { }) .await; - let client = awc::Client::build() + let client = awc::Client::builder() .connector(awc::Connector::new().limit(1).finish()) .finish(); diff --git a/awc/tests/test_connector.rs b/awc/tests/test_connector.rs index 633ac2d50..888f7a900 100644 --- a/awc/tests/test_connector.rs +++ b/awc/tests/test_connector.rs @@ -47,7 +47,7 @@ async fn test_connection_window_size() { .set_alpn_protos(b"\x02h2\x08http/1.1") .map_err(|e| log::error!("Can not set alpn protocol: {:?}", e)); - let client = awc::Client::build() + let client = awc::Client::builder() .connector(awc::Connector::new().ssl(builder.build()).finish()) .initial_window_size(100) .initial_connection_window_size(100) diff --git a/awc/tests/test_rustls_client.rs b/awc/tests/test_rustls_client.rs index 8fb43c439..0df6b154c 100644 --- a/awc/tests/test_rustls_client.rs +++ b/awc/tests/test_rustls_client.rs @@ -82,7 +82,7 @@ async fn _test_connection_reuse_h2() { .dangerous() .set_certificate_verifier(Arc::new(danger::NoCertificateVerification {})); - let client = awc::Client::build() + let client = awc::Client::builder() .connector(awc::Connector::new().rustls(Arc::new(config)).finish()) .finish(); diff --git a/awc/tests/test_ssl_client.rs b/awc/tests/test_ssl_client.rs index ca65fb248..eced5f14b 100644 --- a/awc/tests/test_ssl_client.rs +++ b/awc/tests/test_ssl_client.rs @@ -62,7 +62,7 @@ async fn test_connection_reuse_h2() { .set_alpn_protos(b"\x02h2\x08http/1.1") .map_err(|e| log::error!("Can not set alpn protocol: {:?}", e)); - let client = awc::Client::build() + let client = awc::Client::builder() .connector(awc::Connector::new().ssl(builder.build()).finish()) .finish(); diff --git a/src/test.rs b/src/test.rs index 49c5cc214..3cc6ae45e 100644 --- a/src/test.rs +++ b/src/test.rs @@ -822,7 +822,7 @@ where } }; - Client::build().connector(connector).finish() + Client::builder().connector(connector).finish() }; TestServer { diff --git a/test-server/src/lib.rs b/test-server/src/lib.rs index f6c1183b4..5d5750279 100644 --- a/test-server/src/lib.rs +++ b/test-server/src/lib.rs @@ -90,7 +90,7 @@ pub async fn test_server>(factory: F) -> TestServer } }; - Client::build().connector(connector).finish() + Client::builder().connector(connector).finish() }; actix_connect::start_default_resolver().await.unwrap(); diff --git a/tests/test_httpserver.rs b/tests/test_httpserver.rs index 50c0a7649..118640aca 100644 --- a/tests/test_httpserver.rs +++ b/tests/test_httpserver.rs @@ -43,7 +43,7 @@ async fn test_start() { { use actix_http::client; - let client = awc::Client::build() + let client = awc::Client::builder() .connector( client::Connector::new() .timeout(Duration::from_millis(100)) @@ -115,7 +115,7 @@ async fn test_start_ssl() { .set_alpn_protos(b"\x02h2\x08http/1.1") .map_err(|e| log::error!("Can not set alpn protocol: {:?}", e)); - let client = awc::Client::build() + let client = awc::Client::builder() .connector( awc::Connector::new() .ssl(builder.build()) From cf5138e740d4377dfc26fa595987fea5e5759bc3 Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Fri, 11 Sep 2020 11:29:17 +0100 Subject: [PATCH 14/20] fix clippy async_yields_async lints (#1667) --- src/route.rs | 2 +- src/scope.rs | 10 +++++----- src/test.rs | 43 +++++++++++++++++++++---------------------- 3 files changed, 27 insertions(+), 28 deletions(-) diff --git a/src/route.rs b/src/route.rs index 3a833bdf3..129a67332 100644 --- a/src/route.rs +++ b/src/route.rs @@ -368,7 +368,7 @@ mod tests { })) .route(web::post().to(|| async { delay_for(Duration::from_millis(100)).await; - HttpResponse::Created() + Ok::<_, ()>(HttpResponse::Created()) })) .route(web::delete().to(|| async { delay_for(Duration::from_millis(100)).await; diff --git a/src/scope.rs b/src/scope.rs index c4b01d266..25b5366d8 100644 --- a/src/scope.rs +++ b/src/scope.rs @@ -826,7 +826,7 @@ mod tests { async fn test_scope_variable_segment() { let mut srv = init_service(App::new().service(web::scope("/ab-{project}").service( - web::resource("/path1").to(|r: HttpRequest| async move { + web::resource("/path1").to(|r: HttpRequest| { HttpResponse::Ok() .body(format!("project: {}", &r.match_info()["project"])) }), @@ -926,7 +926,7 @@ mod tests { async fn test_nested_scope_with_variable_segment() { let mut srv = init_service(App::new().service(web::scope("/app").service( web::scope("/{project_id}").service(web::resource("/path1").to( - |r: HttpRequest| async move { + |r: HttpRequest| { HttpResponse::Created() .body(format!("project: {}", &r.match_info()["project_id"])) }, @@ -951,7 +951,7 @@ mod tests { async fn test_nested2_scope_with_variable_segment() { let mut srv = init_service(App::new().service(web::scope("/app").service( web::scope("/{project}").service(web::scope("/{id}").service( - web::resource("/path1").to(|r: HttpRequest| async move { + web::resource("/path1").to(|r: HttpRequest| { HttpResponse::Created().body(format!( "project: {} - {}", &r.match_info()["project"], @@ -1178,7 +1178,7 @@ mod tests { ); s.route( "/", - web::get().to(|req: HttpRequest| async move { + web::get().to(|req: HttpRequest| { HttpResponse::Ok().body( req.url_for("youtube", &["xxxxxx"]).unwrap().to_string(), ) @@ -1199,7 +1199,7 @@ mod tests { async fn test_url_for_nested() { let mut srv = init_service(App::new().service(web::scope("/a").service( web::scope("/b").service(web::resource("/c/{stuff}").name("c").route( - web::get().to(|req: HttpRequest| async move { + web::get().to(|req: HttpRequest| { HttpResponse::Ok() .body(format!("{}", req.url_for("c", &["12345"]).unwrap())) }), diff --git a/src/test.rs b/src/test.rs index 3cc6ae45e..2620e190e 100644 --- a/src/test.rs +++ b/src/test.rs @@ -1072,14 +1072,9 @@ mod tests { let mut app = init_service( App::new().service( web::resource("/index.html") - .route(web::put().to(|| async { HttpResponse::Ok().body("put!") })) - .route( - web::patch().to(|| async { HttpResponse::Ok().body("patch!") }), - ) - .route( - web::delete() - .to(|| async { HttpResponse::Ok().body("delete!") }), - ), + .route(web::put().to(|| HttpResponse::Ok().body("put!"))) + .route(web::patch().to(|| HttpResponse::Ok().body("patch!"))) + .route(web::delete().to(|| HttpResponse::Ok().body("delete!"))), ), ) .await; @@ -1107,11 +1102,13 @@ mod tests { #[actix_rt::test] async fn test_response() { - let mut app = - init_service(App::new().service(web::resource("/index.html").route( - web::post().to(|| async { HttpResponse::Ok().body("welcome!") }), - ))) - .await; + let mut app = init_service( + App::new().service( + web::resource("/index.html") + .route(web::post().to(|| HttpResponse::Ok().body("welcome!"))), + ), + ) + .await; let req = TestRequest::post() .uri("/index.html") @@ -1124,11 +1121,13 @@ mod tests { #[actix_rt::test] async fn test_send_request() { - let mut app = - init_service(App::new().service(web::resource("/index.html").route( - web::get().to(|| async { HttpResponse::Ok().body("welcome!") }), - ))) - .await; + let mut app = init_service( + App::new().service( + web::resource("/index.html") + .route(web::get().to(|| HttpResponse::Ok().body("welcome!"))), + ), + ) + .await; let resp = TestRequest::get() .uri("/index.html") @@ -1148,7 +1147,7 @@ mod tests { #[actix_rt::test] async fn test_response_json() { let mut app = init_service(App::new().service(web::resource("/people").route( - web::post().to(|person: web::Json| async { + web::post().to(|person: web::Json| { HttpResponse::Ok().json(person.into_inner()) }), ))) @@ -1169,7 +1168,7 @@ mod tests { #[actix_rt::test] async fn test_body_json() { let mut app = init_service(App::new().service(web::resource("/people").route( - web::post().to(|person: web::Json| async { + web::post().to(|person: web::Json| { HttpResponse::Ok().json(person.into_inner()) }), ))) @@ -1191,7 +1190,7 @@ mod tests { #[actix_rt::test] async fn test_request_response_form() { let mut app = init_service(App::new().service(web::resource("/people").route( - web::post().to(|person: web::Form| async { + web::post().to(|person: web::Form| { HttpResponse::Ok().json(person.into_inner()) }), ))) @@ -1217,7 +1216,7 @@ mod tests { #[actix_rt::test] async fn test_request_response_json() { let mut app = init_service(App::new().service(web::resource("/people").route( - web::post().to(|person: web::Json| async { + web::post().to(|person: web::Json| { HttpResponse::Ok().json(person.into_inner()) }), ))) From bf53fe5a22449bb99da2192f2b3cc363f7302969 Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Fri, 11 Sep 2020 12:09:52 +0100 Subject: [PATCH 15/20] bump actix dependency to v0.10 (#1666) --- Cargo.toml | 5 +- actix-http/Cargo.toml | 2 +- .../src/header/common/content_disposition.rs | 6 +- actix-web-actors/Cargo.toml | 2 +- src/lib.rs | 2 +- src/test.rs | 93 ++++++++++--------- 6 files changed, 56 insertions(+), 54 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 11559bcae..8d55ffe11 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -92,7 +92,7 @@ mime = "0.3" socket2 = "0.3" pin-project = "0.4.17" regex = "1.3" -serde = { version = "1.0", features=["derive"] } +serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" serde_urlencoded = "0.6.1" time = { version = "0.2.7", default-features = false, features = ["std"] } @@ -102,7 +102,8 @@ rust-tls = { package = "rustls", version = "0.18.0", optional = true } tinyvec = { version = "0.3", features = ["alloc"] } [dev-dependencies] -actix = "0.10.0-alpha.1" +actix = "0.10.0" +actix-http = { version = "2.0.0-beta.4", features = ["actors"] } rand = "0.7" env_logger = "0.7" serde_derive = "1.0" diff --git a/actix-http/Cargo.toml b/actix-http/Cargo.toml index 6d8d143ed..fa002b309 100644 --- a/actix-http/Cargo.toml +++ b/actix-http/Cargo.toml @@ -47,7 +47,7 @@ actix-utils = "2.0.0" actix-rt = "1.0.0" actix-threadpool = "0.3.1" actix-tls = { version = "2.0.0", optional = true } -actix = { version = "0.10.0-alpha.1", optional = true } +actix = { version = "0.10.0", optional = true } base64 = "0.12" bitflags = "1.2" diff --git a/actix-http/src/header/common/content_disposition.rs b/actix-http/src/header/common/content_disposition.rs index 051dcfe80..37da830ca 100644 --- a/actix-http/src/header/common/content_disposition.rs +++ b/actix-http/src/header/common/content_disposition.rs @@ -283,11 +283,11 @@ impl DispositionParam { /// Some("\u{1f600}.svg".as_bytes())); /// ``` /// -/// # WARN +/// # Security Note +/// /// If "filename" parameter is supplied, do not use the file name blindly, check and possibly /// change to match local file system conventions if applicable, and do not use directory path -/// information that may be present. See [RFC2183](https://tools.ietf.org/html/rfc2183#section-2.3) -/// . +/// information that may be present. See [RFC2183](https://tools.ietf.org/html/rfc2183#section-2.3). #[derive(Clone, Debug, PartialEq)] pub struct ContentDisposition { /// The disposition type diff --git a/actix-web-actors/Cargo.toml b/actix-web-actors/Cargo.toml index cb7fd3a80..917f0cd94 100644 --- a/actix-web-actors/Cargo.toml +++ b/actix-web-actors/Cargo.toml @@ -16,7 +16,7 @@ name = "actix_web_actors" path = "src/lib.rs" [dependencies] -actix = "0.10.0-alpha.2" +actix = "0.10.0" actix-web = { version = "3.0.0-beta.4", default-features = false } actix-http = "2.0.0-beta.4" actix-codec = "0.3.0" diff --git a/src/lib.rs b/src/lib.rs index 97141599c..0eced5b42 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -59,7 +59,7 @@ //! * Middlewares ([Logger, Session, CORS, etc](https://actix.rs/docs/middleware/)) //! * Includes an async [HTTP client](https://actix.rs/actix-web/actix_web/client/index.html) //! * Supports [Actix actor framework](https://github.com/actix/actix) -//! * Runs on stable Rust 1.41+ +//! * Runs on stable Rust 1.42+ //! //! ## Crate Features //! diff --git a/src/test.rs b/src/test.rs index 2620e190e..ee51b71ee 100644 --- a/src/test.rs +++ b/src/test.rs @@ -1281,53 +1281,54 @@ mod tests { assert!(res.status().is_success()); } - /* + #[actix_rt::test] + async fn test_actor() { + use crate::Error; + use actix::prelude::*; - Comment out until actix decoupled of actix-http: - https://github.com/actix/actix/issues/321 + struct MyActor; - use futures::FutureExt; - - #[actix_rt::test] - async fn test_actor() { - use actix::Actor; - - struct MyActor; - - struct Num(usize); - impl actix::Message for Num { - type Result = usize; - } - impl actix::Actor for MyActor { - type Context = actix::Context; - } - impl actix::Handler for MyActor { - type Result = usize; - fn handle(&mut self, msg: Num, _: &mut Self::Context) -> Self::Result { - msg.0 - } - } - - - let mut app = init_service(App::new().service(web::resource("/index.html").to( - move || { - addr.send(Num(1)).map(|res| match res { - Ok(res) => { - if res == 1 { - Ok(HttpResponse::Ok()) - } else { - Ok(HttpResponse::BadRequest()) - } - } - Err(err) => Err(err), - }) - }, - ))) - .await; - - let req = TestRequest::post().uri("/index.html").to_request(); - let res = app.call(req).await.unwrap(); - assert!(res.status().is_success()); + impl Actor for MyActor { + type Context = Context; } - */ + + struct Num(usize); + + impl Message for Num { + type Result = usize; + } + + impl Handler for MyActor { + type Result = usize; + + fn handle(&mut self, msg: Num, _: &mut Self::Context) -> Self::Result { + msg.0 + } + } + + let addr = MyActor.start(); + + async fn actor_handler( + addr: Data>, + ) -> Result { + // `?` operator tests "actors" feature flag on actix-http + let res = addr.send(Num(1)).await?; + + if res == 1 { + Ok(HttpResponse::Ok()) + } else { + Ok(HttpResponse::BadRequest()) + } + } + + let srv = App::new() + .data(addr.clone()) + .service(web::resource("/").to(actor_handler)); + + let mut app = init_service(srv).await; + + let req = TestRequest::post().uri("/").to_request(); + let res = app.call(req).await.unwrap(); + assert!(res.status().is_success()); + } } From 64a2c13cdfed3616bf6f3ac2c39a5e1b40bfada4 Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Fri, 11 Sep 2020 13:50:10 +0100 Subject: [PATCH 16/20] the big three point oh (#1668) --- CHANGES.md | 4 ++++ Cargo.toml | 8 ++++---- LICENSE-APACHE | 2 +- LICENSE-MIT | 2 +- MIGRATION.md | 4 ++++ README.md | 5 ----- actix-cors/README.md | 11 ----------- actix-files/Cargo.toml | 10 +++++----- actix-framed/README.md | 3 --- actix-http/CHANGES.md | 4 ++++ actix-http/Cargo.toml | 6 +++--- actix-identity/README.md | 11 ----------- actix-multipart/CHANGES.md | 4 ++++ actix-multipart/Cargo.toml | 8 ++++---- actix-session/README.md | 11 ----------- actix-web-actors/CHANGES.md | 4 ++++ actix-web-actors/Cargo.toml | 8 ++++---- actix-web-codegen/CHANGES.md | 4 ++++ actix-web-codegen/Cargo.toml | 4 ++-- awc/CHANGES.md | 3 +++ awc/Cargo.toml | 12 ++++++------ test-server/CHANGES.md | 5 ++++- test-server/Cargo.toml | 12 ++++++------ 23 files changed, 67 insertions(+), 78 deletions(-) delete mode 100644 actix-cors/README.md delete mode 100644 actix-framed/README.md delete mode 100644 actix-identity/README.md delete mode 100644 actix-session/README.md diff --git a/CHANGES.md b/CHANGES.md index 1779af9ee..995ef884a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,6 +3,10 @@ ## Unreleased - 2020-xx-xx +## 3.0.0 - 2020-09-11 +* No significant changes from `3.0.0-beta.4`. + + ## 3.0.0-beta.4 - 2020-09-09 ### Added * `middleware::NormalizePath` now has configurable behaviour for either always having a trailing diff --git a/Cargo.toml b/Cargo.toml index 8d55ffe11..ce33097be 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "actix-web" -version = "3.0.0-beta.4" +version = "3.0.0" authors = ["Nikolay Kim "] description = "Actix web is a simple, pragmatic and extremely fast web framework for Rust." readme = "README.md" @@ -76,9 +76,9 @@ actix-macros = "0.1.0" actix-threadpool = "0.3.1" actix-tls = "2.0.0" -actix-web-codegen = "0.3.0-beta.1" -actix-http = "2.0.0-beta.4" -awc = { version = "2.0.0-beta.4", default-features = false } +actix-web-codegen = "0.3.0" +actix-http = "2.0.0" +awc = { version = "2.0.0", default-features = false } bytes = "0.5.3" derive_more = "0.99.2" diff --git a/LICENSE-APACHE b/LICENSE-APACHE index 6cdf2d16c..8f5ba39b8 100644 --- a/LICENSE-APACHE +++ b/LICENSE-APACHE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2017-NOW Nikolay Kim + Copyright 2017-NOW Actix Team Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/LICENSE-MIT b/LICENSE-MIT index 0f80296ae..95938ef15 100644 --- a/LICENSE-MIT +++ b/LICENSE-MIT @@ -1,4 +1,4 @@ -Copyright (c) 2017 Nikolay Kim +Copyright (c) 2017 Actix Team Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated diff --git a/MIGRATION.md b/MIGRATION.md index 15045ed69..fd940651f 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -1,5 +1,8 @@ ## Unreleased + +## 3.0.0 + * Setting a cookie's SameSite property, explicitly, to `SameSite::None` will now result in `SameSite=None` being sent with the response Set-Cookie header. To create a cookie without a SameSite attribute, remove any calls setting same_site. @@ -40,6 +43,7 @@ * `HttpServer::maxconnrate` is renamed to the more expressive `HttpServer::max_connection_rate`. + ## 2.0.0 * `HttpServer::start()` renamed to `HttpServer::run()`. It also possible to diff --git a/README.md b/README.md index 48f9d1442..3e3ce8bf1 100644 --- a/README.md +++ b/README.md @@ -43,11 +43,6 @@ ## Example -

- WARNING: This example is for the master branch which is currently in beta stages for v3. For - Actix web v2 see the getting started guide. -

- Dependencies: ```toml diff --git a/actix-cors/README.md b/actix-cors/README.md deleted file mode 100644 index c860ec5ae..000000000 --- a/actix-cors/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# Cors Middleware for actix web framework [![Build Status](https://travis-ci.org/actix/actix-web.svg?branch=master)](https://travis-ci.org/actix/actix-web) [![codecov](https://codecov.io/gh/actix/actix-web/branch/master/graph/badge.svg)](https://codecov.io/gh/actix/actix-web) [![crates.io](https://meritbadge.herokuapp.com/actix-cors)](https://crates.io/crates/actix-cors) [![Join the chat at https://gitter.im/actix/actix](https://badges.gitter.im/actix/actix.svg)](https://gitter.im/actix/actix?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) - -**This crate moved to https://github.com/actix/actix-extras.** - -## Documentation & community resources - -* [User Guide](https://actix.rs/docs/) -* [API Documentation](https://docs.rs/actix-cors/) -* [Chat on gitter](https://gitter.im/actix/actix) -* Cargo package: [actix-cors](https://crates.io/crates/actix-cors) -* Minimum supported Rust version: 1.34 or later diff --git a/actix-files/Cargo.toml b/actix-files/Cargo.toml index 4c6441324..8841f7fb1 100644 --- a/actix-files/Cargo.toml +++ b/actix-files/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "actix-files" -version = "0.3.0-beta.1" +version = "0.3.0" authors = ["Nikolay Kim "] description = "Static files support for actix web." readme = "README.md" @@ -17,9 +17,9 @@ name = "actix_files" path = "src/lib.rs" [dependencies] -actix-web = { version = "3.0.0-beta.4", default-features = false } -actix-http = "2.0.0-beta.4" -actix-service = "1.0.1" +actix-web = { version = "3.0.0", default-features = false } +actix-http = "2.0.0" +actix-service = "1.0.6" bitflags = "1" bytes = "0.5.3" futures-core = { version = "0.3.5", default-features = false } @@ -33,4 +33,4 @@ v_htmlescape = "0.10" [dev-dependencies] actix-rt = "1.0.0" -actix-web = { version = "3.0.0-beta.4", features = ["openssl"] } +actix-web = { version = "3.0.0", features = ["openssl"] } diff --git a/actix-framed/README.md b/actix-framed/README.md deleted file mode 100644 index a4eaadf21..000000000 --- a/actix-framed/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Framed app for actix web - -**This crate has been deprecated and removed.** diff --git a/actix-http/CHANGES.md b/actix-http/CHANGES.md index dfa55e7f1..6a98c4ca7 100644 --- a/actix-http/CHANGES.md +++ b/actix-http/CHANGES.md @@ -3,6 +3,10 @@ ## Unreleased - 2020-xx-xx +## 2.0.0 - 2020-09-11 +* No significant changes from `2.0.0-beta.4`. + + ## 2.0.0-beta.4 - 2020-09-09 ### Changed * Update actix-codec and actix-utils dependencies. diff --git a/actix-http/Cargo.toml b/actix-http/Cargo.toml index fa002b309..0bbde881d 100644 --- a/actix-http/Cargo.toml +++ b/actix-http/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "actix-http" -version = "2.0.0-beta.4" +version = "2.0.0" authors = ["Nikolay Kim "] description = "Actix HTTP primitives" readme = "README.md" @@ -40,7 +40,7 @@ secure-cookies = ["cookie/secure"] actors = ["actix"] [dependencies] -actix-service = "1.0.5" +actix-service = "1.0.6" actix-codec = "0.3.0" actix-connect = "2.0.0" actix-utils = "2.0.0" @@ -88,7 +88,7 @@ flate2 = { version = "1.0.13", optional = true } [dev-dependencies] actix-server = "1.0.1" actix-connect = { version = "2.0.0", features = ["openssl"] } -actix-http-test = { version = "2.0.0-alpha.1", features = ["openssl"] } +actix-http-test = { version = "2.0.0", features = ["openssl"] } actix-tls = { version = "2.0.0", features = ["openssl"] } criterion = "0.3" env_logger = "0.7" diff --git a/actix-identity/README.md b/actix-identity/README.md deleted file mode 100644 index 62a40137f..000000000 --- a/actix-identity/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# Identity service for actix web framework [![Build Status](https://travis-ci.org/actix/actix-web.svg?branch=master)](https://travis-ci.org/actix/actix-web) [![codecov](https://codecov.io/gh/actix/actix-web/branch/master/graph/badge.svg)](https://codecov.io/gh/actix/actix-web) [![crates.io](https://meritbadge.herokuapp.com/actix-identity)](https://crates.io/crates/actix-identity) [![Join the chat at https://gitter.im/actix/actix](https://badges.gitter.im/actix/actix.svg)](https://gitter.im/actix/actix?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) - -**This crate moved to https://github.com/actix/actix-extras.** - -## Documentation & community resources - -* [User Guide](https://actix.rs/docs/) -* [API Documentation](https://docs.rs/actix-identity/) -* [Chat on gitter](https://gitter.im/actix/actix) -* Cargo package: [actix-session](https://crates.io/crates/actix-identity) -* Minimum supported Rust version: 1.34 or later diff --git a/actix-multipart/CHANGES.md b/actix-multipart/CHANGES.md index 7149f6713..b25053025 100644 --- a/actix-multipart/CHANGES.md +++ b/actix-multipart/CHANGES.md @@ -3,6 +3,10 @@ ## Unreleased - 2020-xx-xx +## 3.0.0 - 2020-09-11 +* No significant changes from `3.0.0-beta.2`. + + ## 3.0.0-beta.2 - 2020-09-10 * Update `actix-*` dependencies to latest versions. diff --git a/actix-multipart/Cargo.toml b/actix-multipart/Cargo.toml index 0fd5d0922..e2e9dbf14 100644 --- a/actix-multipart/Cargo.toml +++ b/actix-multipart/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "actix-multipart" -version = "0.3.0-beta.2" +version = "0.3.0" authors = ["Nikolay Kim "] description = "Multipart support for actix web framework." readme = "README.md" @@ -16,8 +16,8 @@ name = "actix_multipart" path = "src/lib.rs" [dependencies] -actix-web = { version = "3.0.0-beta.4", default-features = false } -actix-service = "1.0.1" +actix-web = { version = "3.0.0", default-features = false } +actix-service = "1.0.6" actix-utils = "2.0.0" bytes = "0.5.3" derive_more = "0.99.2" @@ -29,4 +29,4 @@ twoway = "0.2" [dev-dependencies] actix-rt = "1.0.0" -actix-http = "2.0.0-beta.4" +actix-http = "2.0.0" diff --git a/actix-session/README.md b/actix-session/README.md deleted file mode 100644 index 00e580120..000000000 --- a/actix-session/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# Session for actix web framework [![Build Status](https://travis-ci.org/actix/actix-web.svg?branch=master)](https://travis-ci.org/actix/actix-web) [![codecov](https://codecov.io/gh/actix/actix-web/branch/master/graph/badge.svg)](https://codecov.io/gh/actix/actix-web) [![crates.io](https://meritbadge.herokuapp.com/actix-session)](https://crates.io/crates/actix-session) [![Join the chat at https://gitter.im/actix/actix](https://badges.gitter.im/actix/actix.svg)](https://gitter.im/actix/actix?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) - -**This crate moved to https://github.com/actix/actix-extras.** - -## Documentation & community resources - -* [User Guide](https://actix.rs/docs/) -* [API Documentation](https://docs.rs/actix-session/) -* [Chat on gitter](https://gitter.im/actix/actix) -* Cargo package: [actix-session](https://crates.io/crates/actix-session) -* Minimum supported Rust version: 1.34 or later diff --git a/actix-web-actors/CHANGES.md b/actix-web-actors/CHANGES.md index 4dcd403a3..4b9381a33 100644 --- a/actix-web-actors/CHANGES.md +++ b/actix-web-actors/CHANGES.md @@ -3,6 +3,10 @@ ## Unreleased - 2020-xx-xx +## 3.0.0 - 2020-09-11 +* No significant changes from `3.0.0-beta.2`. + + ## 3.0.0-beta.2 - 2020-09-10 * Update `actix-*` dependencies to latest versions. diff --git a/actix-web-actors/Cargo.toml b/actix-web-actors/Cargo.toml index 917f0cd94..2f3c63022 100644 --- a/actix-web-actors/Cargo.toml +++ b/actix-web-actors/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "actix-web-actors" -version = "3.0.0-beta.2" +version = "3.0.0" authors = ["Nikolay Kim "] description = "Actix actors support for actix web framework." readme = "README.md" @@ -17,8 +17,8 @@ path = "src/lib.rs" [dependencies] actix = "0.10.0" -actix-web = { version = "3.0.0-beta.4", default-features = false } -actix-http = "2.0.0-beta.4" +actix-web = { version = "3.0.0", default-features = false } +actix-http = "2.0.0" actix-codec = "0.3.0" bytes = "0.5.2" futures-channel = { version = "0.3.5", default-features = false } @@ -26,6 +26,6 @@ futures-core = { version = "0.3.5", default-features = false } pin-project = "0.4.17" [dev-dependencies] -actix-rt = "1.0.0" +actix-rt = "1.1.1" env_logger = "0.7" futures-util = { version = "0.3.5", default-features = false } diff --git a/actix-web-codegen/CHANGES.md b/actix-web-codegen/CHANGES.md index 242c5f8de..b735be9ce 100644 --- a/actix-web-codegen/CHANGES.md +++ b/actix-web-codegen/CHANGES.md @@ -3,6 +3,10 @@ ## Unreleased - 2020-xx-xx +## 0.3.0 - 2020-09-11 +* No significant changes from `0.3.0-beta.1`. + + ## 0.3.0-beta.1 - 2020-07-14 * Add main entry-point macro that uses re-exported runtime. [#1559] diff --git a/actix-web-codegen/Cargo.toml b/actix-web-codegen/Cargo.toml index ddd886c40..05b52c9db 100644 --- a/actix-web-codegen/Cargo.toml +++ b/actix-web-codegen/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "actix-web-codegen" -version = "0.3.0-beta.1" +version = "0.3.0" description = "Actix web proc macros" readme = "README.md" homepage = "https://actix.rs" @@ -20,5 +20,5 @@ proc-macro2 = "1" [dev-dependencies] actix-rt = "1.0.0" -actix-web = "3.0.0-beta.4" +actix-web = "3.0.0" futures-util = { version = "0.3.5", default-features = false } diff --git a/awc/CHANGES.md b/awc/CHANGES.md index 38faba459..07a469746 100644 --- a/awc/CHANGES.md +++ b/awc/CHANGES.md @@ -1,6 +1,9 @@ # Changes ## Unreleased - 2020-xx-xx + + +## 2.0.0 - 2020-09-11 ### Changed * `Client::build` was renamed to `Client::builder`. diff --git a/awc/Cargo.toml b/awc/Cargo.toml index b55f4dabb..c67b6ba6f 100644 --- a/awc/Cargo.toml +++ b/awc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "awc" -version = "2.0.0-beta.4" +version = "2.0.0" authors = ["Nikolay Kim "] description = "Async HTTP client library that uses the Actix runtime." readme = "README.md" @@ -38,8 +38,8 @@ compress = ["actix-http/compress"] [dependencies] actix-codec = "0.3.0" -actix-service = "1.0.1" -actix-http = "2.0.0-beta.4" +actix-service = "1.0.6" +actix-http = "2.0.0" actix-rt = "1.0.0" base64 = "0.12" @@ -58,9 +58,9 @@ rust-tls = { version = "0.18.0", package = "rustls", optional = true, features = [dev-dependencies] actix-connect = { version = "2.0.0", features = ["openssl"] } -actix-web = { version = "3.0.0-beta.4", features = ["openssl"] } -actix-http = { version = "2.0.0-beta.4", features = ["openssl"] } -actix-http-test = { version = "2.0.0-alpha.1", features = ["openssl"] } +actix-web = { version = "3.0.0", features = ["openssl"] } +actix-http = { version = "2.0.0", features = ["openssl"] } +actix-http-test = { version = "2.0.0", features = ["openssl"] } actix-utils = "2.0.0" actix-server = "1.0.0" actix-tls = { version = "2.0.0", features = ["openssl", "rustls"] } diff --git a/test-server/CHANGES.md b/test-server/CHANGES.md index 71b906b9f..e71e9d0b8 100644 --- a/test-server/CHANGES.md +++ b/test-server/CHANGES.md @@ -1,10 +1,13 @@ # Changes ## Unreleased - 2020-xx-xx + + +## 2.0.0 - 2020-09-11 * Update actix-codec and actix-utils dependencies. -## [2.0.0-alpha.1] - 2020-05-23 +## 2.0.0-alpha.1 - 2020-05-23 * Update the `time` dependency to 0.2.7 * Update `actix-connect` dependency to 2.0.0-alpha.2 * Make `test_server` `async` fn. diff --git a/test-server/Cargo.toml b/test-server/Cargo.toml index 8aecda401..d06bd5dec 100644 --- a/test-server/Cargo.toml +++ b/test-server/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "actix-http-test" -version = "2.0.0-alpha.1" +version = "2.0.0" authors = ["Nikolay Kim "] description = "Actix HTTP test server" readme = "README.md" @@ -29,14 +29,14 @@ default = [] openssl = ["open-ssl", "awc/openssl"] [dependencies] -actix-service = "1.0.1" +actix-service = "1.0.6" actix-codec = "0.3.0" actix-connect = "2.0.0" actix-utils = "2.0.0" -actix-rt = "1.0.0" +actix-rt = "1.1.1" actix-server = "1.0.0" actix-testing = "1.0.0" -awc = "2.0.0-beta.4" +awc = "2.0.0" base64 = "0.12" bytes = "0.5.3" @@ -52,5 +52,5 @@ time = { version = "0.2.7", default-features = false, features = ["std"] } open-ssl = { version = "0.10", package = "openssl", optional = true } [dev-dependencies] -actix-web = "3.0.0-beta.4" -actix-http = "2.0.0-beta.4" +actix-web = "3.0.0" +actix-http = "2.0.0" From a4546f02d2924b23c689cf08f47341b885aece80 Mon Sep 17 00:00:00 2001 From: Damian Lesiuk Date: Sun, 13 Sep 2020 01:55:39 +0200 Subject: [PATCH 17/20] make TrailingSlash enum accessible (#1673) Co-authored-by: Damian Lesiuk --- .gitignore | 3 +++ CHANGES.md | 3 ++- src/middleware/mod.rs | 2 +- tests/test_server.rs | 17 ++++++++++++++++- 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 11a3b5f37..638a4397a 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,6 @@ guide/build/ # These are backup files generated by rustfmt **/*.rs.bk + +# Configuration directory generated by CLion +.idea diff --git a/CHANGES.md b/CHANGES.md index 995ef884a..bc5f7136f 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,7 +1,8 @@ # Changes ## Unreleased - 2020-xx-xx - +### Changed +* `middleware::normalize::TrailingSlash` enum is now accessible. [#1673] ## 3.0.0 - 2020-09-11 * No significant changes from `3.0.0-beta.4`. diff --git a/src/middleware/mod.rs b/src/middleware/mod.rs index f0d42cc2a..12c12a98c 100644 --- a/src/middleware/mod.rs +++ b/src/middleware/mod.rs @@ -9,7 +9,7 @@ mod condition; mod defaultheaders; pub mod errhandlers; mod logger; -mod normalize; +pub mod normalize; pub use self::condition::Condition; pub use self::defaultheaders::DefaultHeaders; diff --git a/tests/test_server.rs b/tests/test_server.rs index fa8a93f06..f8a9ab86d 100644 --- a/tests/test_server.rs +++ b/tests/test_server.rs @@ -16,7 +16,8 @@ use futures_util::ready; use rand::{distributions::Alphanumeric, Rng}; use actix_web::dev::BodyEncoding; -use actix_web::middleware::Compress; +use actix_web::middleware::normalize::TrailingSlash; +use actix_web::middleware::{Compress, NormalizePath}; use actix_web::{dev, test, web, App, Error, HttpResponse}; const STR: &str = "Hello World Hello World Hello World Hello World Hello World \ @@ -866,6 +867,20 @@ async fn test_slow_request() { assert!(data.starts_with("HTTP/1.1 408 Request Timeout")); } +#[actix_rt::test] +async fn test_normalize() { + let srv = test::start_with(test::config().h1(), || { + App::new() + .wrap(NormalizePath::new(TrailingSlash::Trim)) + .service( + web::resource("/one").route(web::to(|| HttpResponse::Ok().finish())), + ) + }); + + let response = srv.get("/one/").send().await.unwrap(); + assert!(response.status().is_success()); +} + // #[cfg(feature = "openssl")] // #[actix_rt::test] // async fn test_ssl_handshake_timeout() { From f8615087893863a35f3e835068dd833ce5c5af5b Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Sun, 13 Sep 2020 03:24:44 +0100 Subject: [PATCH 18/20] prepare web release 3.0.1 (#1676) --- CHANGES.md | 6 ++++++ Cargo.toml | 4 ++-- src/lib.rs | 8 +++++--- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index bc5f7136f..aadf627bc 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,9 +1,15 @@ # Changes ## Unreleased - 2020-xx-xx + + +## 3.0.1 - 2020-09-13 ### Changed * `middleware::normalize::TrailingSlash` enum is now accessible. [#1673] +[#1673]: https://github.com/actix/actix-web/pull/1673 + + ## 3.0.0 - 2020-09-11 * No significant changes from `3.0.0-beta.4`. diff --git a/Cargo.toml b/Cargo.toml index ce33097be..b2cffbc48 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "actix-web" -version = "3.0.0" +version = "3.0.1" authors = ["Nikolay Kim "] -description = "Actix web is a simple, pragmatic and extremely fast web framework for Rust." +description = "Actix web is a powerful, pragmatic, and extremely fast web framework for Rust." readme = "README.md" keywords = ["actix", "http", "web", "framework", "async"] homepage = "https://actix.rs" diff --git a/src/lib.rs b/src/lib.rs index 0eced5b42..327cba954 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,3 @@ -#![deny(rust_2018_idioms)] -#![allow(clippy::needless_doctest_main, clippy::type_complexity)] - //! Actix web is a powerful, pragmatic, and extremely fast web framework for Rust. //! //! ## Example @@ -68,6 +65,11 @@ //! * `rustls` - HTTPS support via `rustls` crate, supports `HTTP/2` //! * `secure-cookies` - secure cookies support +#![deny(rust_2018_idioms)] +#![allow(clippy::needless_doctest_main, clippy::type_complexity)] +#![doc(html_logo_url = "https://actix.rs/img/logo.png")] +#![doc(html_favicon_url = "https://actix.rs/favicon.ico")] + mod app; mod app_service; mod config; From 3fde3be3d863a42fab6799bdfd4552bcb43d7e8e Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Sun, 13 Sep 2020 16:31:08 +0100 Subject: [PATCH 19/20] add trybuild tests to routing codegen (#1677) --- actix-web-codegen/CHANGES.md | 3 ++ actix-web-codegen/Cargo.toml | 1 + actix-web-codegen/README.md | 24 ++++++++++--- actix-web-codegen/src/lib.rs | 34 +++++++++---------- actix-web-codegen/tests/trybuild.rs | 7 ++++ .../tests/trybuild/simple-fail.rs | 25 ++++++++++++++ .../tests/trybuild/simple-fail.stderr | 23 +++++++++++++ actix-web-codegen/tests/trybuild/simple.rs | 15 ++++++++ 8 files changed, 110 insertions(+), 22 deletions(-) create mode 100644 actix-web-codegen/tests/trybuild.rs create mode 100644 actix-web-codegen/tests/trybuild/simple-fail.rs create mode 100644 actix-web-codegen/tests/trybuild/simple-fail.stderr create mode 100644 actix-web-codegen/tests/trybuild/simple.rs diff --git a/actix-web-codegen/CHANGES.md b/actix-web-codegen/CHANGES.md index b735be9ce..5c0ce828a 100644 --- a/actix-web-codegen/CHANGES.md +++ b/actix-web-codegen/CHANGES.md @@ -1,6 +1,9 @@ # Changes ## Unreleased - 2020-xx-xx +* Added compile success and failure testing. [#1677] + +[#1677]: https://github.com/actix/actix-web/pull/1677 ## 0.3.0 - 2020-09-11 diff --git a/actix-web-codegen/Cargo.toml b/actix-web-codegen/Cargo.toml index 05b52c9db..1bf78f997 100644 --- a/actix-web-codegen/Cargo.toml +++ b/actix-web-codegen/Cargo.toml @@ -22,3 +22,4 @@ proc-macro2 = "1" actix-rt = "1.0.0" actix-web = "3.0.0" futures-util = { version = "0.3.5", default-features = false } +trybuild = "1" diff --git a/actix-web-codegen/README.md b/actix-web-codegen/README.md index 45eb82c2c..6eca847b8 100644 --- a/actix-web-codegen/README.md +++ b/actix-web-codegen/README.md @@ -1,8 +1,22 @@ -# Helper and convenience macros for Actix-web. [![Build Status](https://travis-ci.org/actix/actix-web.svg?branch=master)](https://travis-ci.org/actix/actix-web) [![codecov](https://codecov.io/gh/actix/actix-web/branch/master/graph/badge.svg)](https://codecov.io/gh/actix/actix-web) [![crates.io](https://meritbadge.herokuapp.com/actix-web-codegen)](https://crates.io/crates/actix-web-codegen) [![Join the chat at https://gitter.im/actix/actix](https://badges.gitter.im/actix/actix.svg)](https://gitter.im/actix/actix?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +# actix-web-codegen + +> Helper and convenience macros for Actix Web + +[![crates.io](https://meritbadge.herokuapp.com/actix-web-codegen)](https://crates.io/crates/actix-web-codegen) +[![Documentation](https://docs.rs/actix-web-codegen/badge.svg)](https://docs.rs/actix-web) +[![Version](https://img.shields.io/badge/rustc-1.42+-ab6000.svg)](https://blog.rust-lang.org/2020/03/12/Rust-1.42.html) +[![Build Status](https://travis-ci.org/actix/actix-web.svg?branch=master)](https://travis-ci.org/actix/actix-web) +[![codecov](https://codecov.io/gh/actix/actix-web/branch/master/graph/badge.svg)](https://codecov.io/gh/actix/actix-web) +[![Join the chat at https://gitter.im/actix/actix](https://badges.gitter.im/actix/actix.svg)](https://gitter.im/actix/actix?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) ## Documentation & Resources -* [API Documentation](https://docs.rs/actix-web-codegen/) -* [Chat on gitter](https://gitter.im/actix/actix) -* Cargo package: [actix-web-codegen](https://crates.io/crates/actix-web-codegen) -* Minimum supported Rust version: 1.40 or later +- [API Documentation](https://docs.rs/actix-web-codegen) +- [Chat on Gitter](https://gitter.im/actix/actix-web) +- Cargo package: [actix-web-codegen](https://crates.io/crates/actix-web-codegen) +- Minimum supported Rust version: 1.42 or later. + +## Compile Testing +Uses the [`trybuild`] crate. All compile fail tests should include a stderr file generated by `trybuild`. See the [workflow section](https://github.com/dtolnay/trybuild#workflow) of the trybuild docs for info on how to do this. + +[`trybuild`]: https://github.com/dtolnay/trybuild diff --git a/actix-web-codegen/src/lib.rs b/actix-web-codegen/src/lib.rs index b6df3f0dd..445fe924d 100644 --- a/actix-web-codegen/src/lib.rs +++ b/actix-web-codegen/src/lib.rs @@ -49,13 +49,13 @@ use proc_macro::TokenStream; /// Creates route handler with `GET` method guard. /// -/// Syntax: `#[get("path"[, attributes])]` +/// Syntax: `#[get("path" [, attributes])]` /// /// ## Attributes: /// /// - `"path"` - Raw literal string with path for which to register handler. Mandatory. -/// - `guard="function_name"` - Registers function as guard using `actix_web::guard::fn_guard` -/// - `wrap="Middleware"` - Registers a resource middleware. +/// - `guard = "function_name"` - Registers function as guard using `actix_web::guard::fn_guard` +/// - `wrap = "Middleware"` - Registers a resource middleware. #[proc_macro_attribute] pub fn get(args: TokenStream, input: TokenStream) -> TokenStream { route::generate(args, input, route::GuardType::Get) @@ -63,7 +63,7 @@ pub fn get(args: TokenStream, input: TokenStream) -> TokenStream { /// Creates route handler with `POST` method guard. /// -/// Syntax: `#[post("path"[, attributes])]` +/// Syntax: `#[post("path" [, attributes])]` /// /// Attributes are the same as in [get](attr.get.html) #[proc_macro_attribute] @@ -73,7 +73,7 @@ pub fn post(args: TokenStream, input: TokenStream) -> TokenStream { /// Creates route handler with `PUT` method guard. /// -/// Syntax: `#[put("path"[, attributes])]` +/// Syntax: `#[put("path" [, attributes])]` /// /// Attributes are the same as in [get](attr.get.html) #[proc_macro_attribute] @@ -83,9 +83,9 @@ pub fn put(args: TokenStream, input: TokenStream) -> TokenStream { /// Creates route handler with `DELETE` method guard. /// -/// Syntax: `#[delete("path"[, attributes])]` +/// Syntax: `#[delete("path" [, attributes])]` /// -/// Attributes are the same as in [get](attr.get.html) +/// Attributes are the same as in [get](attr.get.html). #[proc_macro_attribute] pub fn delete(args: TokenStream, input: TokenStream) -> TokenStream { route::generate(args, input, route::GuardType::Delete) @@ -93,9 +93,9 @@ pub fn delete(args: TokenStream, input: TokenStream) -> TokenStream { /// Creates route handler with `HEAD` method guard. /// -/// Syntax: `#[head("path"[, attributes])]` +/// Syntax: `#[head("path" [, attributes])]` /// -/// Attributes are the same as in [head](attr.head.html) +/// Attributes are the same as in [get](attr.get.html). #[proc_macro_attribute] pub fn head(args: TokenStream, input: TokenStream) -> TokenStream { route::generate(args, input, route::GuardType::Head) @@ -103,9 +103,9 @@ pub fn head(args: TokenStream, input: TokenStream) -> TokenStream { /// Creates route handler with `CONNECT` method guard. /// -/// Syntax: `#[connect("path"[, attributes])]` +/// Syntax: `#[connect("path" [, attributes])]` /// -/// Attributes are the same as in [connect](attr.connect.html) +/// Attributes are the same as in [get](attr.get.html). #[proc_macro_attribute] pub fn connect(args: TokenStream, input: TokenStream) -> TokenStream { route::generate(args, input, route::GuardType::Connect) @@ -113,9 +113,9 @@ pub fn connect(args: TokenStream, input: TokenStream) -> TokenStream { /// Creates route handler with `OPTIONS` method guard. /// -/// Syntax: `#[options("path"[, attributes])]` +/// Syntax: `#[options("path" [, attributes])]` /// -/// Attributes are the same as in [options](attr.options.html) +/// Attributes are the same as in [get](attr.get.html). #[proc_macro_attribute] pub fn options(args: TokenStream, input: TokenStream) -> TokenStream { route::generate(args, input, route::GuardType::Options) @@ -123,9 +123,9 @@ pub fn options(args: TokenStream, input: TokenStream) -> TokenStream { /// Creates route handler with `TRACE` method guard. /// -/// Syntax: `#[trace("path"[, attributes])]` +/// Syntax: `#[trace("path" [, attributes])]` /// -/// Attributes are the same as in [trace](attr.trace.html) +/// Attributes are the same as in [get](attr.get.html). #[proc_macro_attribute] pub fn trace(args: TokenStream, input: TokenStream) -> TokenStream { route::generate(args, input, route::GuardType::Trace) @@ -133,9 +133,9 @@ pub fn trace(args: TokenStream, input: TokenStream) -> TokenStream { /// Creates route handler with `PATCH` method guard. /// -/// Syntax: `#[patch("path"[, attributes])]` +/// Syntax: `#[patch("path" [, attributes])]` /// -/// Attributes are the same as in [patch](attr.patch.html) +/// Attributes are the same as in [get](attr.get.html). #[proc_macro_attribute] pub fn patch(args: TokenStream, input: TokenStream) -> TokenStream { route::generate(args, input, route::GuardType::Patch) diff --git a/actix-web-codegen/tests/trybuild.rs b/actix-web-codegen/tests/trybuild.rs new file mode 100644 index 000000000..b675947d3 --- /dev/null +++ b/actix-web-codegen/tests/trybuild.rs @@ -0,0 +1,7 @@ +#[test] +fn compile_macros() { + let t = trybuild::TestCases::new(); + + t.pass("tests/trybuild/simple.rs"); + t.compile_fail("tests/trybuild/simple-fail.rs"); +} diff --git a/actix-web-codegen/tests/trybuild/simple-fail.rs b/actix-web-codegen/tests/trybuild/simple-fail.rs new file mode 100644 index 000000000..140497687 --- /dev/null +++ b/actix-web-codegen/tests/trybuild/simple-fail.rs @@ -0,0 +1,25 @@ +use actix_web::*; + +#[get("/one", other)] +async fn one() -> impl Responder { + HttpResponse::Ok() +} + +#[post(/two)] +async fn two() -> impl Responder { + HttpResponse::Ok() +} + +static PATCH_PATH: &str = "/three"; + +#[patch(PATCH_PATH)] +async fn three() -> impl Responder { + HttpResponse::Ok() +} + +#[delete("/four", "/five")] +async fn four() -> impl Responder { + HttpResponse::Ok() +} + +fn main() {} diff --git a/actix-web-codegen/tests/trybuild/simple-fail.stderr b/actix-web-codegen/tests/trybuild/simple-fail.stderr new file mode 100644 index 000000000..12c32c00d --- /dev/null +++ b/actix-web-codegen/tests/trybuild/simple-fail.stderr @@ -0,0 +1,23 @@ +error: Unknown attribute. + --> $DIR/simple-fail.rs:3:15 + | +3 | #[get("/one", other)] + | ^^^^^ + +error: expected identifier or literal + --> $DIR/simple-fail.rs:8:8 + | +8 | #[post(/two)] + | ^ + +error: Unknown attribute. + --> $DIR/simple-fail.rs:15:9 + | +15 | #[patch(PATCH_PATH)] + | ^^^^^^^^^^ + +error: Multiple paths specified! Should be only one! + --> $DIR/simple-fail.rs:20:19 + | +20 | #[delete("/four", "/five")] + | ^^^^^^^ diff --git a/actix-web-codegen/tests/trybuild/simple.rs b/actix-web-codegen/tests/trybuild/simple.rs new file mode 100644 index 000000000..6b1e67442 --- /dev/null +++ b/actix-web-codegen/tests/trybuild/simple.rs @@ -0,0 +1,15 @@ +use actix_web::*; + +#[get("/config")] +async fn config() -> impl Responder { + HttpResponse::Ok() +} + +#[actix_web::main] +async fn main() { + let srv = test::start(|| App::new().service(config)); + + let request = srv.get("/config"); + let response = request.send().await.unwrap(); + assert!(response.status().is_success()); +} From 4b4c9d1b9341f1316157ed29e4f27223228f6009 Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Mon, 14 Sep 2020 22:26:03 +0100 Subject: [PATCH 20/20] update migration guide closes #1680 --- MIGRATION.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/MIGRATION.md b/MIGRATION.md index fd940651f..98b22ae4e 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -3,12 +3,23 @@ ## 3.0.0 +* The return type for `ServiceRequest::app_data::()` was changed from returning a `Data` to + simply a `T`. To access a `Data` use `ServiceRequest::app_data::>()`. + +* Cookie handling has been offloaded to the `cookie` crate: + * `USERINFO_ENCODE_SET` is no longer exposed. Percent-encoding is still supported; check docs. + * Some types now require lifetime parameters. + +* The time crate was updated to `v0.2`, a major breaking change to the time crate, which affects + any `actix-web` method previously expecting a time v0.1 input. + * Setting a cookie's SameSite property, explicitly, to `SameSite::None` will now result in `SameSite=None` being sent with the response Set-Cookie header. To create a cookie without a SameSite attribute, remove any calls setting same_site. * actix-http support for Actors messages was moved to actix-http crate and is enabled with feature `actors` + * content_length function is removed from actix-http. You can set Content-Length by normally setting the response body or calling no_chunking function.