Skip to content

Commit 5c83544

Browse files
committed
Ensure buffer len for segment boundary check in multipart
1 parent 67a866c commit 5c83544

1 file changed

Lines changed: 34 additions & 8 deletions

File tree

src/multipart/parse.rs

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use pyo3::{IntoPyObjectExt, exceptions::PyStopIteration, prelude::*, types::PyBy
99
use std::{
1010
borrow::Cow,
1111
collections::VecDeque,
12-
io::{BufRead, Cursor},
12+
io::{BufRead, Cursor, Read},
1313
mem,
1414
sync::Mutex,
1515
};
@@ -64,12 +64,36 @@ impl MultiPartParser {
6464
where
6565
T: AsRef<[u8]>,
6666
{
67+
macro_rules! buffered_read {
68+
($boundary:expr, $target:expr) => {{
69+
let peeker = reader.fill_buf()?;
70+
if peeker.is_empty() {
71+
return Ok(());
72+
}
73+
// if the chunk is not long enough to check for boundary, buffer
74+
if (peeker.len() + self.buffer.len()) < $boundary.len() {
75+
reader.read_to_end(&mut self.buffer)?;
76+
return Ok(());
77+
}
78+
79+
if self.buffer.is_empty() {
80+
reader.stream_until_token($boundary, $target)?
81+
} else {
82+
// we buffered previous contents, chain the two reads
83+
let mut chain = self.buffer.chain(&mut *reader);
84+
let ret = chain.stream_until_token($boundary, $target)?;
85+
self.buffer.truncate(0);
86+
ret
87+
}
88+
}};
89+
}
90+
6791
let (lt, ltlt, lt_boundary) = &self.boundaries;
6892

6993
loop {
70-
let peeker = reader.fill_buf()?;
71-
7294
if let MultiPartParserState::Clean = self.state {
95+
let peeker = reader.fill_buf()?;
96+
7397
// If the last chunk is empty and we're in clean state there's nothing to do.
7498
if peeker.is_empty() {
7599
return Ok(());
@@ -122,6 +146,9 @@ impl MultiPartParser {
122146
}?
123147
};
124148

149+
// clean the buffer
150+
self.buffer.truncate(0);
151+
125152
let mut is_file = false;
126153
let mut missing_mime = false;
127154
if let Some(cd) = part_headers.get(header::CONTENT_DISPOSITION) {
@@ -154,7 +181,7 @@ impl MultiPartParser {
154181
}
155182

156183
if let MultiPartParserState::Value(part) = &mut self.state {
157-
let (read, found) = reader.stream_until_token(lt_boundary, &mut part.value)?;
184+
let (read, found) = buffered_read!(lt_boundary, &mut part.value);
158185
self.read_size += read;
159186
if self.read_size >= self.max_part_size {
160187
return Err(error_size!());
@@ -175,11 +202,10 @@ impl MultiPartParser {
175202
}
176203

177204
if let MultiPartParserState::File(filepart) = &mut self.state {
178-
// potentially allow py threads?
179-
let (read, found) = reader.stream_until_token(
205+
let (read, found) = buffered_read!(
180206
lt_boundary,
181-
&mut filepart.file.as_mut().expect("uninitialized file part"),
182-
)?;
207+
&mut filepart.file.as_mut().expect("uninitialized file part")
208+
);
183209
let size = filepart.size.unwrap_or(0);
184210
filepart.size = Some(size + read);
185211

0 commit comments

Comments
 (0)