Skip to content
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

hyper does not comply with Expect: 100-continue statement #369

Closed
octplane opened this issue Mar 11, 2015 · 12 comments · Fixed by #377
Closed

hyper does not comply with Expect: 100-continue statement #369

octplane opened this issue Mar 11, 2015 · 12 comments · Fixed by #377
Labels
A-server Area: server. C-bug Category: bug. Something is wrong. This is bad! E-easy Effort: easy. A task that would be a great starting point for a new contributor.

Comments

@octplane
Copy link

I'm using hyper to receive githook commit messages and when the payload is longer than 1024 bytes, request.read_to_string() is much much slower than it probably should be (something like a factor 100 on localhost)...

I have created a very simple test case in https://github.com/octplane/githook-client-rust/tree/slow_read_hyper . It's a simple POST upload that triggers the behavior.

I suspect this might be due to the network packets but I'm not sure and I'm certain somebody here will have a much better idea on how to identify the issue :)

Thanks for your time !

@seanmonstar
Copy link
Member

Hmm. Hyper is using a BufReader, which by default uses 64kbs. Is it significantly bigger than that?

@octplane
Copy link
Author

It is much smaller: 1024 bytes (as indicated by the title of the Issue 😉 ). And the issue starts getting visible at precisely this value.

@seanmonstar
Copy link
Member

Could you try using String::with_capacity(1024) or whichever the size is, and see if that affects things. i'm trying to think where in hyper it might be doing something.

@octplane
Copy link
Author

It makes strictly no difference.

@reem
Copy link
Contributor

reem commented Mar 11, 2015

@octplane Could you try to profile the code?

@seanmonstar
Copy link
Member

Also, would be neat to see actual time values. 1000 bytes can be the size of packet in some cases, so it could just be doing an additional sys call to read the end.

@octplane
Copy link
Author

@reem , @seanmonstar I have no idea on how to profile rust code... I'm on OSX, FWIW...

@octplane
Copy link
Author

Ok, after some investigation (read the wget logs), I found out that hyper does not conform to some expected parf of the HTTP specification:

time curl -vvv -X POST -d @broken.json http://127.0.0.1:5000/hook/                                                              
* Hostname was NOT found in DNS cache
*   Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 5000 (#0)
> POST /hook/ HTTP/1.1
> User-Agent: curl/7.37.1
> Host: 127.0.0.1:5000
> Accept: */*
> Content-Length: 1025
> Content-Type: application/x-www-form-urlencoded
> Expect: 100-continue
>
* Done waiting for 100-continue
< HTTP/1.1 200 OK
< Transfer-Encoding: chunked
< Date: Wed, 11 Mar 2015 20:41:28 GMT
<
* Connection #0 to host 127.0.0.1 left intact
OK.curl -vvv -X POST -d @broken.json http://127.0.0.1:5000/hook/  0,00s user 0,00s system 0% cpu 1,011 total

Because the payload is bigger than 1024 bytes, curl attempts a two step posts using the Expect: 100-continue instruction. After 1s, curl gives up and send the payload:

set->expect_100_timeout = 1000L; /* Wait for a second by default. */

https://github.com/bagder/curl/blob/df5578a7a304a23f9aa3670daff8573ec3ef416f/lib/transfer.c#L1103

Hyper happily receives the payload and call the handler.

@octplane octplane changed the title read_to_string takes a lot of time when payload > 1024 bytes hyper does not comply with Expect: 100-continue statement Mar 11, 2015
@seanmonstar
Copy link
Member

Thanks for finding out the real issue! To fix this, I'd imagine adding a check_continue method to the Handler trait, with a default implementation of just writing continue, and checking for an Expect header in the server loop. This allows it to just work, and allows someone to override the behavior if they need to.

@seanmonstar seanmonstar added C-bug Category: bug. Something is wrong. This is bad! A-server Area: server. E-easy Effort: easy. A task that would be a great starting point for a new contributor. labels Mar 11, 2015
@reem
Copy link
Contributor

reem commented Mar 11, 2015

@seanmonstar I'm not convinced that hyper should actually handle this vs. downstream users/libraries adding features like this.

@seanmonstar
Copy link
Member

@reem according to RFC7231:

An origin server MUST, upon receiving an HTTP/1.1 (or later)
request-line and a complete header section that contains a
100-continue expectation and indicates a request message body will
follow, either send an immediate response with a final status code,
if that status can be determined by examining just the request-line
and header fields, or send an immediate 100 (Continue) response to
encourage the client to send the request's message body. The origin
server MUST NOT wait for the message body before sending the 100
(Continue) response.

@reem
Copy link
Contributor

reem commented Mar 11, 2015

I'm convinced.

seanmonstar added a commit that referenced this issue Mar 16, 2015
Adds a new method to `Handler`, with a default implementation of always
responding with a `100 Continue` when sent an expectation.

Closes #369
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-server Area: server. C-bug Category: bug. Something is wrong. This is bad! E-easy Effort: easy. A task that would be a great starting point for a new contributor.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants