[WIP] Add "read with limit" functionality to DataStream#990
[WIP] Add "read with limit" functionality to DataStream#990Nilix007 wants to merge 1 commit intorwf2:masterfrom
DataStream#990Conversation
There was a problem hiding this comment.
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.
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_limitandDataStream::read_to_end_with_limittogether with a new error typeLimitReadError.@jebrosen: What do you think?