1
0
mirror of https://github.com/fafhrd91/actix-web synced 2024-11-27 17:52:56 +01:00

refactor(multipart): move lints to manifest

This commit is contained in:
Rob Ede 2024-07-04 01:12:17 +01:00
parent 7326707599
commit 00c185f617
No known key found for this signature in database
GPG Key ID: 97C636207D3EF933
4 changed files with 61 additions and 59 deletions

View File

@ -69,3 +69,8 @@ futures-util = { version = "0.3.17", default-features = false, features = ["allo
multer = "3" multer = "3"
tokio = { version = "1.24.2", features = ["sync"] } tokio = { version = "1.24.2", features = ["sync"] }
tokio-stream = "0.1" tokio-stream = "0.1"
[lints.rust]
future_incompatible = { level = "deny" }
rust_2018_idioms = { level = "deny" }
nonstandard_style = { level = "deny" }

View File

@ -46,9 +46,6 @@
//! -F file=@./Cargo.lock //! -F file=@./Cargo.lock
//! ``` //! ```
#![deny(rust_2018_idioms, nonstandard_style)]
#![warn(future_incompatible)]
#![allow(clippy::borrow_interior_mutable_const)]
#![doc(html_logo_url = "https://actix.rs/img/logo.png")] #![doc(html_logo_url = "https://actix.rs/img/logo.png")]
#![doc(html_favicon_url = "https://actix.rs/favicon.ico")] #![doc(html_favicon_url = "https://actix.rs/favicon.ico")]
#![cfg_attr(docsrs, feature(doc_auto_cfg))] #![cfg_attr(docsrs, feature(doc_auto_cfg))]

View File

@ -1,5 +1,6 @@
use std::{ use std::{
cell::{RefCell, RefMut}, cell::{RefCell, RefMut},
cmp,
pin::Pin, pin::Pin,
rc::Rc, rc::Rc,
task::{Context, Poll}, task::{Context, Poll},
@ -75,7 +76,7 @@ impl PayloadBuffer {
} }
} }
/// Read exact number of bytes /// Read exact number of bytes.
#[cfg(test)] #[cfg(test)]
pub(crate) fn read_exact(&mut self, size: usize) -> Option<Bytes> { pub(crate) fn read_exact(&mut self, size: usize) -> Option<Bytes> {
if size <= self.buf.len() { if size <= self.buf.len() {
@ -87,7 +88,7 @@ impl PayloadBuffer {
pub(crate) fn read_max(&mut self, size: u64) -> Result<Option<Bytes>, MultipartError> { pub(crate) fn read_max(&mut self, size: u64) -> Result<Option<Bytes>, MultipartError> {
if !self.buf.is_empty() { if !self.buf.is_empty() {
let size = std::cmp::min(self.buf.len() as u64, size) as usize; let size = cmp::min(self.buf.len() as u64, size) as usize;
Ok(Some(self.buf.split_to(size).freeze())) Ok(Some(self.buf.split_to(size).freeze()))
} else if self.eof { } else if self.eof {
Err(MultipartError::Incomplete) Err(MultipartError::Incomplete)
@ -96,7 +97,7 @@ impl PayloadBuffer {
} }
} }
/// Read until specified ending /// Read until specified ending.
pub(crate) fn read_until(&mut self, line: &[u8]) -> Result<Option<Bytes>, MultipartError> { pub(crate) fn read_until(&mut self, line: &[u8]) -> Result<Option<Bytes>, MultipartError> {
let res = memchr::memmem::find(&self.buf, line) let res = memchr::memmem::find(&self.buf, line)
.map(|idx| self.buf.split_to(idx + line.len()).freeze()); .map(|idx| self.buf.split_to(idx + line.len()).freeze());
@ -108,12 +109,12 @@ impl PayloadBuffer {
} }
} }
/// Read bytes until new line delimiter /// Read bytes until new line delimiter.
pub(crate) fn readline(&mut self) -> Result<Option<Bytes>, MultipartError> { pub(crate) fn readline(&mut self) -> Result<Option<Bytes>, MultipartError> {
self.read_until(b"\n") self.read_until(b"\n")
} }
/// Read bytes until new line delimiter or eof /// Read bytes until new line delimiter or EOF.
pub(crate) fn readline_or_eof(&mut self) -> Result<Option<Bytes>, MultipartError> { pub(crate) fn readline_or_eof(&mut self) -> Result<Option<Bytes>, MultipartError> {
match self.readline() { match self.readline() {
Err(MultipartError::Incomplete) if self.eof => Ok(Some(self.buf.split().freeze())), Err(MultipartError::Incomplete) if self.eof => Ok(Some(self.buf.split().freeze())),
@ -121,7 +122,7 @@ impl PayloadBuffer {
} }
} }
/// Put unprocessed data back to the buffer /// Put unprocessed data back to the buffer.
pub(crate) fn unprocessed(&mut self, data: Bytes) { pub(crate) fn unprocessed(&mut self, data: Bytes) {
let buf = BytesMut::from(data.as_ref()); let buf = BytesMut::from(data.as_ref());
let buf = std::mem::replace(&mut self.buf, buf); let buf = std::mem::replace(&mut self.buf, buf);

View File

@ -34,7 +34,7 @@ const MAX_HEADERS: usize = 32;
/// used for nested multipart streams. /// used for nested multipart streams.
pub struct Multipart { pub struct Multipart {
safety: Safety, safety: Safety,
inner: Option<InnerMultipart>, inner: Option<Inner>,
error: Option<MultipartError>, error: Option<MultipartError>,
} }
@ -90,12 +90,12 @@ impl Multipart {
{ {
Multipart { Multipart {
safety: Safety::new(), safety: Safety::new(),
inner: Some(InnerMultipart { inner: Some(Inner {
payload: PayloadRef::new(PayloadBuffer::new(stream)), payload: PayloadRef::new(PayloadBuffer::new(stream)),
content_type: ct, content_type: ct,
boundary, boundary,
state: InnerState::FirstBoundary, state: State::FirstBoundary,
item: InnerMultipartItem::None, item: Item::None,
}), }),
error: None, error: None,
} }
@ -155,10 +155,7 @@ impl Stream for Multipart {
} }
#[derive(PartialEq, Debug)] #[derive(PartialEq, Debug)]
enum InnerState { enum State {
/// Stream EOF.
Eof,
/// Skip data until first boundary. /// Skip data until first boundary.
FirstBoundary, FirstBoundary,
@ -167,14 +164,17 @@ enum InnerState {
/// Reading Headers. /// Reading Headers.
Headers, Headers,
/// Stream EOF.
Eof,
} }
enum InnerMultipartItem { enum Item {
None, None,
Field(Rc<RefCell<InnerField>>), Field(Rc<RefCell<InnerField>>),
} }
struct InnerMultipart { struct Inner {
/// Request's payload stream & buffer. /// Request's payload stream & buffer.
payload: PayloadRef, payload: PayloadRef,
@ -186,11 +186,11 @@ struct InnerMultipart {
/// Field boundary. /// Field boundary.
boundary: String, boundary: String,
state: InnerState, state: State,
item: InnerMultipartItem, item: Item,
} }
impl InnerMultipart { impl Inner {
fn read_field_headers( fn read_field_headers(
payload: &mut PayloadBuffer, payload: &mut PayloadBuffer,
) -> Result<Option<HeaderMap>, MultipartError> { ) -> Result<Option<HeaderMap>, MultipartError> {
@ -265,6 +265,7 @@ impl InnerMultipart {
boundary: &str, boundary: &str,
) -> Result<Option<bool>, MultipartError> { ) -> Result<Option<bool>, MultipartError> {
let mut eof = false; let mut eof = false;
loop { loop {
match payload.readline()? { match payload.readline()? {
Some(chunk) => { Some(chunk) => {
@ -306,7 +307,7 @@ impl InnerMultipart {
safety: &Safety, safety: &Safety,
cx: &Context<'_>, cx: &Context<'_>,
) -> Poll<Option<Result<Field, MultipartError>>> { ) -> Poll<Option<Result<Field, MultipartError>>> {
if self.state == InnerState::Eof { if self.state == State::Eof {
Poll::Ready(None) Poll::Ready(None)
} else { } else {
// release field // release field
@ -315,20 +316,18 @@ impl InnerMultipart {
// before switching to next // before switching to next
if safety.current() { if safety.current() {
let stop = match self.item { let stop = match self.item {
InnerMultipartItem::Field(ref mut field) => { Item::Field(ref mut field) => match field.borrow_mut().poll(safety) {
match field.borrow_mut().poll(safety) {
Poll::Pending => return Poll::Pending, Poll::Pending => return Poll::Pending,
Poll::Ready(Some(Ok(_))) => continue, Poll::Ready(Some(Ok(_))) => continue,
Poll::Ready(Some(Err(err))) => return Poll::Ready(Some(Err(err))), Poll::Ready(Some(Err(err))) => return Poll::Ready(Some(Err(err))),
Poll::Ready(None) => true, Poll::Ready(None) => true,
} },
} Item::None => false,
InnerMultipartItem::None => false,
}; };
if stop { if stop {
self.item = InnerMultipartItem::None; self.item = Item::None;
} }
if let InnerMultipartItem::None = self.item { if let Item::None = self.item {
break; break;
} }
} }
@ -337,40 +336,40 @@ impl InnerMultipart {
let field_headers = if let Some(mut payload) = self.payload.get_mut(safety) { let field_headers = if let Some(mut payload) = self.payload.get_mut(safety) {
match self.state { match self.state {
// read until first boundary // read until first boundary
InnerState::FirstBoundary => { State::FirstBoundary => {
match InnerMultipart::skip_until_boundary(&mut payload, &self.boundary)? { match Inner::skip_until_boundary(&mut payload, &self.boundary)? {
Some(eof) => { Some(eof) => {
if eof { if eof {
self.state = InnerState::Eof; self.state = State::Eof;
return Poll::Ready(None); return Poll::Ready(None);
} else { } else {
self.state = InnerState::Headers; self.state = State::Headers;
} }
} }
None => return Poll::Pending, None => return Poll::Pending,
} }
} }
// read boundary // read boundary
InnerState::Boundary => { State::Boundary => match Inner::read_boundary(&mut payload, &self.boundary)? {
match InnerMultipart::read_boundary(&mut payload, &self.boundary)? {
None => return Poll::Pending, None => return Poll::Pending,
Some(eof) => { Some(eof) => {
if eof { if eof {
self.state = InnerState::Eof; self.state = State::Eof;
return Poll::Ready(None); return Poll::Ready(None);
} else { } else {
self.state = InnerState::Headers; self.state = State::Headers;
}
}
} }
} }
},
_ => {} _ => {}
} }
// read field headers for next field // read field headers for next field
if self.state == InnerState::Headers { if self.state == State::Headers {
if let Some(headers) = InnerMultipart::read_field_headers(&mut payload)? { if let Some(headers) = Inner::read_field_headers(&mut payload)? {
self.state = InnerState::Boundary; self.state = State::Boundary;
headers headers
} else { } else {
return Poll::Pending; return Poll::Pending;
@ -418,7 +417,7 @@ impl InnerMultipart {
.and_then(|ct| ct.to_str().ok()) .and_then(|ct| ct.to_str().ok())
.and_then(|ct| ct.parse().ok()); .and_then(|ct| ct.parse().ok());
self.state = InnerState::Boundary; self.state = State::Boundary;
// nested multipart stream is not supported // nested multipart stream is not supported
if let Some(mime) = &field_content_type { if let Some(mime) = &field_content_type {
@ -430,7 +429,7 @@ impl InnerMultipart {
let field_inner = let field_inner =
InnerField::new_in_rc(self.payload.clone(), self.boundary.clone(), &field_headers)?; InnerField::new_in_rc(self.payload.clone(), self.boundary.clone(), &field_headers)?;
self.item = InnerMultipartItem::Field(Rc::clone(&field_inner)); self.item = Item::Field(Rc::clone(&field_inner));
Poll::Ready(Some(Ok(Field::new( Poll::Ready(Some(Ok(Field::new(
field_content_type, field_content_type,
@ -444,10 +443,10 @@ impl InnerMultipart {
} }
} }
impl Drop for InnerMultipart { impl Drop for Inner {
fn drop(&mut self) { fn drop(&mut self) {
// InnerMultipartItem::Field has to be dropped first because of Safety. // InnerMultipartItem::Field has to be dropped first because of Safety.
self.item = InnerMultipartItem::None; self.item = Item::None;
} }
} }
@ -772,7 +771,7 @@ mod tests {
} }
#[actix_rt::test] #[actix_rt::test]
async fn test_readmax() { async fn read_max() {
let (mut sender, payload) = h1::Payload::create(false); let (mut sender, payload) = h1::Payload::create(false);
let mut payload = PayloadBuffer::new(payload); let mut payload = PayloadBuffer::new(payload);
@ -789,7 +788,7 @@ mod tests {
} }
#[actix_rt::test] #[actix_rt::test]
async fn test_readexactly() { async fn read_exactly() {
let (mut sender, payload) = h1::Payload::create(false); let (mut sender, payload) = h1::Payload::create(false);
let mut payload = PayloadBuffer::new(payload); let mut payload = PayloadBuffer::new(payload);
@ -807,7 +806,7 @@ mod tests {
} }
#[actix_rt::test] #[actix_rt::test]
async fn test_readuntil() { async fn read_until() {
let (mut sender, payload) = h1::Payload::create(false); let (mut sender, payload) = h1::Payload::create(false);
let mut payload = PayloadBuffer::new(payload); let mut payload = PayloadBuffer::new(payload);