-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[WIP] Add "read with limit" functionality to DataStream
#990
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've implemented but not fully committed to something similar before (https://git.jebrosen.com/jeb/sirus/src/commit/73faadda126187d88836e865dd8b4138742c71df/sirus-server/src/utils/limited_data.rs). I think doing something like this in Data
or DataStream
is a good idea, and potentially using it in Form and JSON as well.
limit: usize, | ||
f: F, | ||
) -> Result<T, LimitReadError> { | ||
let mut r = self.by_ref().take(limit as u64 + 1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using take
with 1 more than the real limit is clever. Maybe a bit too clever -- I want to double check the edge cases.
Let me add some motivation for my API proposal:
All in all, I'd start off with just the two functions and keep the |
@jebrosen: If you're OK with this approach, I would continue with adding documentation, some tests for the edge cases, and update all the body data consumers in Rocket and contrib. (I'm also unsure whether |
I think it's a good idea to add this in some form, maybe with some name/API changes. Users have often wanted In the documentation, I would definitely want to 1) encourage any potential users of these functions to use a user-configurable Limit and 2) strongly caution against using something like |
74113c3
to
95c981d
Compare
I want to revisit this, and I have some quick thoughts on the API:
For example, let size_limit = r.limits().get("msgpack").unwrap_or(LIMIT);
let mut buf = Vec::new();
let mut reader = d.open().take(size_limit);
match reader.read_to_end(&mut buf).await {
Ok(_) => Borrowed(Success(buf)),
Err(e) => Borrowed(Failure((Status::BadRequest, Error::InvalidDataRead(e)))),
} becomes let size_limit = r.limits().get("msgpack").unwrap_or(LIMIT);
match d.read_to_end_with_limit(size_limit).await {
Ok(buf) => Borrowed(Success(buf)),
Err(e) => Borrowed(Failure((Status::BadRequest, Error::InvalidDataRead(e))))
} This way the methods would do what a lot of users do already, and anyone who needs to do something more complicated can still call @SergioBenitez any thoughts on the above? |
I think we should go even further. Here's my proposed API: impl Data {
fn open(limit: usize) -> DataStream;
fn peek(&self) -> &[u8];
fn peek_complete(&self) -> bool;
}
impl DataStream {
fn stream_to<W: Write>(self, writer: &mut W) -> io::Result<u64>;
fn stream_to_file<P: AsRef<Path>>(self, path: P) -> io::Result<u64>;
fn stream_to_string(self) -> io::Result<String>;
fn stream_to_vec(self) -> io::Result<Vec<u8>>;
}
impl Read for DataStream { /* ... */ } I can't think of a valid reason to ever read without a limit. So, let's enforce it. We might even consider abusing |
I like those methods as well. I suspect The name |
Given that Another thing to consider here is that I think what we'd really like to do is expose an API that requires limits to be set on several properties, with a hard, indelible limit. In particular:
My guess is that a bandwidth-minimum approach to the connection timeout might actually make a bit more sense, especially when we consider very purposefully long-lived connections. That is, after a chosen period of time, assuming the other timeouts/limits haven't been exceeded, require that the bandwidth over a sliding window of time exceeds some factor. Otherwise, kill the connection, ideally in a graceful manner. This approach seems fairly easy to implement in |
I'd like a comprehensive approach to this. I've opened #1325 to track such an effort. Let's move the discussion there until we have a concrete plan. |
Hey there,
as suggested in #973 (comment), Rocket should provide an easy way to read from the HTTP body with an upper limit on the body size. (As this is needed for
Form
,JSON
, etc.)Let's start off with this proof of concept which adds
DataStream::read_to_string_with_limit
andDataStream::read_to_end_with_limit
together with a new error typeLimitReadError
.@jebrosen: What do you think?