>,
}
impl Extensions {
@@ -19,7 +40,7 @@ impl Extensions {
#[inline]
pub fn new() -> Extensions {
Extensions {
- map: AHashMap::new(),
+ map: HashMap::default(),
}
}
diff --git a/actix-http/src/h1/client.rs b/actix-http/src/h1/client.rs
index 75c88d00c..6a0d531d0 100644
--- a/actix-http/src/h1/client.rs
+++ b/actix-http/src/h1/client.rs
@@ -1,9 +1,9 @@
use std::{fmt, io};
-use actix_codec::{Decoder, Encoder};
use bitflags::bitflags;
use bytes::{Bytes, BytesMut};
use http::{Method, Version};
+use tokio_util::codec::{Decoder, Encoder};
use super::{
decoder::{self, PayloadDecoder, PayloadItem, PayloadType},
diff --git a/actix-http/src/h1/codec.rs b/actix-http/src/h1/codec.rs
index 80afd7455..e11f175c9 100644
--- a/actix-http/src/h1/codec.rs
+++ b/actix-http/src/h1/codec.rs
@@ -1,9 +1,9 @@
use std::{fmt, io};
-use actix_codec::{Decoder, Encoder};
use bitflags::bitflags;
use bytes::BytesMut;
use http::{Method, Version};
+use tokio_util::codec::{Decoder, Encoder};
use super::{
decoder::{self, PayloadDecoder, PayloadItem, PayloadType},
diff --git a/actix-http/src/h1/dispatcher.rs b/actix-http/src/h1/dispatcher.rs
index 3267c2aed..e04cb65e1 100644
--- a/actix-http/src/h1/dispatcher.rs
+++ b/actix-http/src/h1/dispatcher.rs
@@ -8,13 +8,15 @@ use std::{
task::{Context, Poll},
};
-use actix_codec::{AsyncRead, AsyncWrite, Decoder as _, Encoder as _, Framed, FramedParts};
+use actix_codec::{Framed, FramedParts};
use actix_rt::time::sleep_until;
use actix_service::Service;
use bitflags::bitflags;
use bytes::{Buf, BytesMut};
use futures_core::ready;
use pin_project_lite::pin_project;
+use tokio::io::{AsyncRead, AsyncWrite};
+use tokio_util::codec::{Decoder as _, Encoder as _};
use tracing::{error, trace};
use crate::{
@@ -1004,7 +1006,7 @@ where
this.read_buf.reserve(HW_BUFFER_SIZE - remaining);
}
- match actix_codec::poll_read_buf(io.as_mut(), cx, this.read_buf) {
+ match tokio_util::io::poll_read_buf(io.as_mut(), cx, this.read_buf) {
Poll::Ready(Ok(n)) => {
this.flags.remove(Flags::FINISHED);
diff --git a/actix-http/src/h1/dispatcher_tests.rs b/actix-http/src/h1/dispatcher_tests.rs
index b3ee3d2bb..3eea859bf 100644
--- a/actix-http/src/h1/dispatcher_tests.rs
+++ b/actix-http/src/h1/dispatcher_tests.rs
@@ -637,7 +637,7 @@ async fn expect_handling() {
if let DispatcherState::Normal { ref inner } = h1.inner {
let io = inner.io.as_ref().unwrap();
- let mut res = (&io.write_buf()[..]).to_owned();
+ let mut res = io.write_buf()[..].to_owned();
stabilize_date_header(&mut res);
assert_eq!(
@@ -699,7 +699,7 @@ async fn expect_eager() {
if let DispatcherState::Normal { ref inner } = h1.inner {
let io = inner.io.as_ref().unwrap();
- let mut res = (&io.write_buf()[..]).to_owned();
+ let mut res = io.write_buf()[..].to_owned();
stabilize_date_header(&mut res);
// Despite the content-length header and even though the request payload has not
diff --git a/actix-http/src/header/map.rs b/actix-http/src/header/map.rs
index 8f6d1cead..28906e835 100644
--- a/actix-http/src/header/map.rs
+++ b/actix-http/src/header/map.rs
@@ -309,7 +309,7 @@ impl HeaderMap {
pub fn get_all(&self, key: impl AsHeaderName) -> std::slice::Iter<'_, HeaderValue> {
match self.get_value(key) {
Some(value) => value.iter(),
- None => (&[]).iter(),
+ None => [].iter(),
}
}
diff --git a/actix-http/src/requests/request.rs b/actix-http/src/requests/request.rs
index 0f8e78d46..ac358e8df 100644
--- a/actix-http/src/requests/request.rs
+++ b/actix-http/src/requests/request.rs
@@ -113,14 +113,14 @@ impl Request
{
#[inline]
/// Http message part of the request
pub fn head(&self) -> &RequestHead {
- &*self.head
+ &self.head
}
#[inline]
#[doc(hidden)]
/// Mutable reference to a HTTP message part of the request
pub fn head_mut(&mut self) -> &mut RequestHead {
- &mut *self.head
+ &mut self.head
}
/// Mutable reference to the message's headers.
diff --git a/actix-http/src/responses/response.rs b/actix-http/src/responses/response.rs
index ceb158f65..03908d9ce 100644
--- a/actix-http/src/responses/response.rs
+++ b/actix-http/src/responses/response.rs
@@ -83,13 +83,13 @@ impl Response {
/// Returns a reference to the head of this response.
#[inline]
pub fn head(&self) -> &ResponseHead {
- &*self.head
+ &self.head
}
/// Returns a mutable reference to the head of this response.
#[inline]
pub fn head_mut(&mut self) -> &mut ResponseHead {
- &mut *self.head
+ &mut self.head
}
/// Returns the status code of this response.
diff --git a/actix-http/src/ws/codec.rs b/actix-http/src/ws/codec.rs
index 4a2e741b6..6a149f9a4 100644
--- a/actix-http/src/ws/codec.rs
+++ b/actix-http/src/ws/codec.rs
@@ -1,7 +1,7 @@
-use actix_codec::{Decoder, Encoder};
use bitflags::bitflags;
use bytes::{Bytes, BytesMut};
use bytestring::ByteString;
+use tokio_util::codec::{Decoder, Encoder};
use tracing::error;
use super::{
diff --git a/actix-http/src/ws/dispatcher.rs b/actix-http/src/ws/dispatcher.rs
index 2f6b2363b..396f1e86c 100644
--- a/actix-http/src/ws/dispatcher.rs
+++ b/actix-http/src/ws/dispatcher.rs
@@ -76,7 +76,9 @@ mod inner {
use pin_project_lite::pin_project;
use tracing::debug;
- use actix_codec::{AsyncRead, AsyncWrite, Decoder, Encoder, Framed};
+ use actix_codec::Framed;
+ use tokio::io::{AsyncRead, AsyncWrite};
+ use tokio_util::codec::{Decoder, Encoder};
use crate::{body::BoxBody, Response};
diff --git a/actix-http/src/ws/frame.rs b/actix-http/src/ws/frame.rs
index 3659b6c3b..c7e0427ea 100644
--- a/actix-http/src/ws/frame.rs
+++ b/actix-http/src/ws/frame.rs
@@ -313,7 +313,7 @@ mod tests {
#[test]
fn test_parse_frame_no_mask() {
let mut buf = BytesMut::from(&[0b0000_0001u8, 0b0000_0001u8][..]);
- buf.extend(&[1u8]);
+ buf.extend([1u8]);
assert!(Parser::parse(&mut buf, true, 1024).is_err());
@@ -326,7 +326,7 @@ mod tests {
#[test]
fn test_parse_frame_max_size() {
let mut buf = BytesMut::from(&[0b0000_0001u8, 0b0000_0010u8][..]);
- buf.extend(&[1u8, 1u8]);
+ buf.extend([1u8, 1u8]);
assert!(Parser::parse(&mut buf, true, 1).is_err());
@@ -340,9 +340,9 @@ mod tests {
fn test_parse_frame_max_size_recoverability() {
let mut buf = BytesMut::new();
// The first text frame with length == 2, payload doesn't matter.
- buf.extend(&[0b0000_0001u8, 0b0000_0010u8, 0b0000_0000u8, 0b0000_0000u8]);
+ buf.extend([0b0000_0001u8, 0b0000_0010u8, 0b0000_0000u8, 0b0000_0000u8]);
// Next binary frame with length == 2 and payload == `[0x1111_1111u8, 0x1111_1111u8]`.
- buf.extend(&[0b0000_0010u8, 0b0000_0010u8, 0b1111_1111u8, 0b1111_1111u8]);
+ buf.extend([0b0000_0010u8, 0b0000_0010u8, 0b1111_1111u8, 0b1111_1111u8]);
assert_eq!(buf.len(), 8);
assert!(matches!(
diff --git a/actix-http/src/ws/proto.rs b/actix-http/src/ws/proto.rs
index 01fe9dd3c..7222168b7 100644
--- a/actix-http/src/ws/proto.rs
+++ b/actix-http/src/ws/proto.rs
@@ -244,7 +244,7 @@ pub fn hash_key(key: &[u8]) -> [u8; 28] {
};
let mut hash_b64 = [0; 28];
- let n = base64::encode_config_slice(&hash, base64::STANDARD, &mut hash_b64);
+ let n = base64::encode_config_slice(hash, base64::STANDARD, &mut hash_b64);
assert_eq!(n, 28);
hash_b64
diff --git a/actix-http/tests/test_rustls.rs b/actix-http/tests/test_rustls.rs
index 2bbf1524b..d9ff42b7d 100644
--- a/actix-http/tests/test_rustls.rs
+++ b/actix-http/tests/test_rustls.rs
@@ -41,7 +41,7 @@ where
let body = stream.as_mut();
match ready!(body.poll_next(cx)) {
- Some(Ok(bytes)) => buf.extend_from_slice(&*bytes),
+ Some(Ok(bytes)) => buf.extend_from_slice(&bytes),
None => return Poll::Ready(Ok(())),
Some(Err(err)) => return Poll::Ready(Err(err)),
}
diff --git a/actix-multipart/CHANGES.md b/actix-multipart/CHANGES.md
index d0da40fb4..655487e54 100644
--- a/actix-multipart/CHANGES.md
+++ b/actix-multipart/CHANGES.md
@@ -2,6 +2,9 @@
## Unreleased - 2022-xx-xx
- Minimum supported Rust version (MSRV) is now 1.59 due to transitive `time` dependency.
+- `Field::content_type()` now returns `Option<&mime::Mime>` [#2880]
+
+[#2880]: https://github.com/actix/actix-web/pull/2880
## 0.4.0 - 2022-02-25
diff --git a/actix-multipart/Cargo.toml b/actix-multipart/Cargo.toml
index 32ea49a24..6f631fcf1 100644
--- a/actix-multipart/Cargo.toml
+++ b/actix-multipart/Cargo.toml
@@ -24,7 +24,7 @@ httparse = "1.3"
local-waker = "0.1"
log = "0.4"
mime = "0.3"
-twoway = "0.2"
+memchr = "2.5"
[dev-dependencies]
actix-rt = "2.2"
diff --git a/actix-multipart/src/server.rs b/actix-multipart/src/server.rs
index 239f7f905..1d0510039 100644
--- a/actix-multipart/src/server.rs
+++ b/actix-multipart/src/server.rs
@@ -289,10 +289,8 @@ impl InnerMultipart {
match self.state {
// read until first boundary
InnerState::FirstBoundary => {
- match InnerMultipart::skip_until_boundary(
- &mut *payload,
- &self.boundary,
- )? {
+ match InnerMultipart::skip_until_boundary(&mut payload, &self.boundary)?
+ {
Some(eof) => {
if eof {
self.state = InnerState::Eof;
@@ -306,7 +304,7 @@ impl InnerMultipart {
}
// read boundary
InnerState::Boundary => {
- match InnerMultipart::read_boundary(&mut *payload, &self.boundary)? {
+ match InnerMultipart::read_boundary(&mut payload, &self.boundary)? {
None => return Poll::Pending,
Some(eof) => {
if eof {
@@ -323,7 +321,7 @@ impl InnerMultipart {
// read field headers for next field
if self.state == InnerState::Headers {
- if let Some(headers) = InnerMultipart::read_headers(&mut *payload)? {
+ if let Some(headers) = InnerMultipart::read_headers(&mut payload)? {
self.state = InnerState::Boundary;
headers
} else {
@@ -361,17 +359,18 @@ impl InnerMultipart {
return Poll::Ready(Some(Err(MultipartError::NoContentDisposition)));
};
- let ct: mime::Mime = headers
+ let ct: Option = headers
.get(&header::CONTENT_TYPE)
.and_then(|ct| ct.to_str().ok())
- .and_then(|ct| ct.parse().ok())
- .unwrap_or(mime::APPLICATION_OCTET_STREAM);
+ .and_then(|ct| ct.parse().ok());
self.state = InnerState::Boundary;
// nested multipart stream is not supported
- if ct.type_() == mime::MULTIPART {
- return Poll::Ready(Some(Err(MultipartError::Nested)));
+ if let Some(mime) = &ct {
+ if mime.type_() == mime::MULTIPART {
+ return Poll::Ready(Some(Err(MultipartError::Nested)));
+ }
}
let field =
@@ -399,7 +398,7 @@ impl Drop for InnerMultipart {
/// A single field in a multipart stream
pub struct Field {
- ct: mime::Mime,
+ ct: Option,
cd: ContentDisposition,
headers: HeaderMap,
inner: Rc>,
@@ -410,7 +409,7 @@ impl Field {
fn new(
safety: Safety,
headers: HeaderMap,
- ct: mime::Mime,
+ ct: Option,
cd: ContentDisposition,
inner: Rc>,
) -> Self {
@@ -428,9 +427,13 @@ impl Field {
&self.headers
}
- /// Returns a reference to the field's content (mime) type.
- pub fn content_type(&self) -> &mime::Mime {
- &self.ct
+ /// Returns a reference to the field's content (mime) type, if it is supplied by the client.
+ ///
+ /// According to [RFC 7578](https://www.rfc-editor.org/rfc/rfc7578#section-4.4), if it is not
+ /// present, it should default to "text/plain". Note it is the responsibility of the client to
+ /// provide the appropriate content type, there is no attempt to validate this by the server.
+ pub fn content_type(&self) -> Option<&mime::Mime> {
+ self.ct.as_ref()
}
/// Returns the field's Content-Disposition.
@@ -482,7 +485,11 @@ impl Stream for Field {
impl fmt::Debug for Field {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- writeln!(f, "\nField: {}", self.ct)?;
+ if let Some(ct) = &self.ct {
+ writeln!(f, "\nField: {}", ct)?;
+ } else {
+ writeln!(f, "\nField:")?;
+ }
writeln!(f, " boundary: {}", self.inner.borrow().boundary)?;
writeln!(f, " headers:")?;
for (key, val) in self.headers.iter() {
@@ -599,7 +606,7 @@ impl InnerField {
}
loop {
- return if let Some(idx) = twoway::find_bytes(&payload.buf[pos..], b"\r") {
+ return if let Some(idx) = memchr::memmem::find(&payload.buf[pos..], b"\r") {
let cur = pos + idx;
// check if we have enough data for boundary detection
@@ -643,9 +650,9 @@ impl InnerField {
let result = if let Some(mut payload) = self.payload.as_ref().unwrap().get_mut(s) {
if !self.eof {
let res = if let Some(ref mut len) = self.length {
- InnerField::read_len(&mut *payload, len)
+ InnerField::read_len(&mut payload, len)
} else {
- InnerField::read_stream(&mut *payload, &self.boundary)
+ InnerField::read_stream(&mut payload, &self.boundary)
};
match res {
@@ -820,7 +827,7 @@ impl PayloadBuffer {
/// Read until specified ending
fn read_until(&mut self, line: &[u8]) -> Result