-
-
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
Change 100-continue behavior to send when Body has been polled #838
Comments
Not so much forgotten, I just wanted to come up with a better design. What you outline here seems like it should work on master: fn on_request(&mut self, req: Request) -> Next {
match request.headers().get() {
Some(&ContentLength(len)) if len > 10_000_000 => {
self.status = StatusCode::PayloadTooLarge;
Next::write()
},
None => {
self.status = StatusCode::LengthRequired;
Next::write()
},
Some(&ContentLength(len)) => {
self.length = len;
// hyper looks for Expect-100, and sends 100 status because of this read()
Next::read()
}
}
} |
Yes, about this behavior and I had in mind. I'm sorry if offended. Loss (sometimes temporary) features on full code redesign is a normal and I did not mean anything bad. On the contrary, from my point of view this is a very good time to remind about corner cases :) |
Not offended at all! Thanks for helping think this issue through. On Mon, Jun 20, 2016, 11:42 PM Artem V. Navrotskiy notifications@github.com
|
Hey all, I've literally only been using rust a few days so it is hard for me to follow through the code with inferred type assignments and generics mixed together. Anyway, Here is what I have so far. diff --git a/src/http/conn.rs b/src/http/conn.rs
index 7954fadb..3e90c8ba 100644
--- a/src/http/conn.rs
+++ b/src/http/conn.rs
@@ -116,6 +116,7 @@ impl<I: Io, T: Http1Transaction, K: KeepAlive> Conn<I, T, K> {
}
};
self.state.busy();
+ let wants_continue = head.expecting_continue();
let wants_keep_alive = head.should_keep_alive();
self.state.keep_alive &= wants_keep_alive;
let (body, reading) = if decoder.is_eof() {
@@ -124,6 +125,10 @@ impl<I: Io, T: Http1Transaction, K: KeepAlive> Conn<I, T, K> {
(true, Reading::Body(decoder))
};
self.state.reading = reading;
+ if wants_continue {
+ self.state.reading = Reading::Init;
+ }
+
return Ok(Async::Ready(Some(Frame::Message { message: head, body: body })));
},
_ => {
@@ -674,6 +679,8 @@ mod tests {
Ok(())
}).wait();
}
+
+
#[test]
fn test_conn_closed_write() {
let io = AsyncIo::new_buf(vec![], 0);
diff --git a/src/http/mod.rs b/src/http/mod.rs
index 13c50119..a0ea5a27 100644
--- a/src/http/mod.rs
+++ b/src/http/mod.rs
@@ -2,7 +2,7 @@
use std::borrow::Cow;
use std::fmt;
-use header::{Connection, ConnectionOption};
+use header::{Connection, ConnectionOption, Expect};
use header::Headers;
use method::Method;
use status::StatusCode;
@@ -68,6 +68,10 @@ impl<S> MessageHead<S> {
pub fn should_keep_alive(&self) -> bool {
should_keep_alive(self.version, &self.headers)
}
+
+ pub fn expecting_continue(&self) -> bool {
+ expecting_continue(self.version, &self.headers)
+ }
}
/// The raw status code and reason-phrase.
@@ -115,6 +119,16 @@ pub fn should_keep_alive(version: HttpVersion, headers: &Headers) -> bool {
ret
}
+#[inline]
+pub fn expecting_continue(version: HttpVersion, headers: &Headers) -> bool {
+ let ret = match (version, headers.get::<Expect>()) {
+ (Http11, Some(expect)) if expect == &Expect::Continue => true,
+ _ => false
+ };
+ trace!("expecting_continue(version={:?}, header={:?}) = {:?}", version, headers.get::<Expect>(), ret);
+ ret
+}
+
#[derive(Debug)]
pub enum ServerTransaction {}
The function I added to
Ignoring the changes I made to @seanmonstar can you give me some direction here? |
@martell You've only been using Rust a couple days? That makes this work even more impressive! I'd suggest opening a Pull Request with your work, it makes it easier to discuss changes. As for your current diff, it definitely looks like the right direction. I imagine we would want to add some new states, of which I'm not entirely certain the best combination at the moment. I'll think more, but I can describe the expected behavior. We would need to save somehow that the request would like a 100-continue response. We would also need a way to know whether we should respond with it, and also to know that we already have. A way we could decide to write if !req.headers().has::<ContentLength>()
return Response::new().with_status(StatusCode::LengthRequired);
} else {
req.body().for_each(|chunk| something(chunk))
} In the above example, if the request didn't have a So, we can record that an expectation exists, and then in Does this all make sense? |
Thanks for taking the time to look. Most of that makes sense to me. We have to be compliant with the rfc spec to only send the The use case for this is typically for a REST API server and we only really want to send the body after I see the
I think we want a state like My biggest problem is I can't find where I can write to the |
I've gone back and forth whether it should be The content is written via |
I have a PR open to implement this: #1232. |
@sfackler Added support for immediately replying with Discussions on IRC lead to some work being done in tokio which needed a new future Sink to support this. rust-lang/futures-rs#414 It is still up in the air about how we are going to best solve this. This thread might give the best context on what is needed. |
This should no longer be blocked on any dependencies, on master. We have our own dispatcher, and use a custom channel for the body. I think it wouldn't be too hard to tie |
@seanmonstar was this not fixed by 26417fc? if msg.expect_continue {
let cont = b"HTTP/1.1 100 Continue\r\n\r\n";
self.io.headers_buf().extend_from_slice(cont);
} |
@AlexDvorak no, that's adding the |
So, would modification to the pub struct Body {
kind: Kind,
/// Keep the extra bits in an `Option<Box<Extra>>`, so that
/// Body stays small in the common case (no extras needed).
extra: Option<Box<Extra>>,
UserHasPolled: bool,
} Or should the modification be happenning elsewhere? |
That wouldn't work, since the |
what are you reffering to by channel implementation? I assume your're not reffering to |
Use of the 100 (Continue) Status (https://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html#sec8.2.3):
In my case, for example, I can upload file or reject already uploaded file in one atomic request.
Current state:
check_continue
method. This method is not supported by https://github.com/iron/iron and https://github.com/nickel-org/nickel.rs. Also this method require duplicate logic (it not called on HTTP/1.0) for routing and check permissions;I think, much better to send "100 Continue" status on first Body::read() call (similar logic implemented by https://github.com/frewsxcv/tiny-http project).
In this case no additional logic/callback needed for make desigion about "100 Continue":
I try to change logic on 0.9.x branch by send "100 Continue" status of first read call, but I failed :(
The text was updated successfully, but these errors were encountered: