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

request error = HttpMethodError logs #197

Closed
rictic opened this issue Dec 13, 2014 · 2 comments · Fixed by #310
Closed

request error = HttpMethodError logs #197

rictic opened this issue Dec 13, 2014 · 2 comments · Fixed by #310
Labels
A-server Area: server. C-bug Category: bug. Something is wrong. This is bad!

Comments

@rictic
Copy link

rictic commented Dec 13, 2014

I'm finding the following in my server logs with some frequency:

ERROR:hyper::server: request error = HttpMethodError

After spending some time on this, I've found a simple reproduction that seems to hinge on requests with a chunked transfer encoding, though I couldn't tell if it was the hyper client or the server that was incorrect. Wireshark hinted that it may be the client, but I believe that I've encountered this log message in the wild and not just when testing the hyper server with the hyper client.

The log message is produced when the server is trying to read the http method of a request but encounters unexpected characters. In the case of the error reproduction below, the server appears to be trying to read for a second request on the connection, and it encounters \r\n instead of the expected http method.

extern crate test;
extern crate hyper;

use std::io;
use std::rand;
use hyper::method::Method;
use hyper::client::Request;
use hyper::server;
use hyper::status::StatusCode;

#[test]
fn http_method_error_is_logged() {
    let ts = TestServer::new();
    Request::new(Method::Post, ts.get_url())
        .unwrap().start().unwrap().send().unwrap();
    io::stdio::stderr().write_line(
        "^^^^^^^     That ERROR log message there     ^^^^^^^").unwrap();

    // I couldn't work out how to capture the error logs, stdio::set_stderr()
    // only catches messages sent with panic! I think. As a result this "test" 
    // doesn't assert, you just have to look at the printed output.

    // Things which cause this error to not reproduce:
    //   * changing the request to one with no body, like a GET
    //   * providing a Content-Length on the request
}

fn hello(_: server::Request, mut res: server::Response) {
    *res.status_mut() = StatusCode::Ok;
    let mut res = res.start().unwrap();
    res.write(b"Hello World!").unwrap();
    res.end().unwrap();
}


struct TestServer {
    listen_serv : hyper::server::Listening,
    port : u16,
}

impl TestServer {
    fn new() -> TestServer {
        let host = from_str("127.0.0.1").unwrap();
        // Try to guess a free port that we can bind to:
        for _ in range(0, 100u) {
            let port = rand::random();
            let server = hyper::server::Server::http(host, port);

            match server.listen(hello) {
                Ok(listening) => {
                    return TestServer {
                        listen_serv: listening,
                        port: port
                    }
                },
                Err(_) => (),
            };
        }

        panic!("Could not find a port to bind the test server to!");
    }

    fn get_url(&self) -> hyper::Url {
        let mut url = "http://127.0.0.1:".to_string();
        url.push_str(self.port.to_string().as_slice());
        url.push_str("/");
        hyper::Url::parse(url.as_slice()).unwrap()
    }
}

impl Drop for TestServer {
    fn drop(&mut self) {
        self.listen_serv.close().unwrap();
    }
}
@seanmonstar seanmonstar added C-bug Category: bug. Something is wrong. This is bad! A-server Area: server. labels Dec 13, 2014
@seanmonstar
Copy link
Member

It seems the error is 2-fold:

  1. Most all clients don't send a chunked message when there really isn't a body. The client interface was trying to guess if it was chunked. The newer Client struct should properly set Content-Length: 0 when there is no body.
  2. Even so, if the server handler does not read the whole request body (if a client did POST data), and ignores it, then the data will still be in the pipe. The keep alive loop will read on the socket again to see if the connection has continue, and will find the rest of the POST body. This part means that the server perhaps needs to be adjusted somehow to make sure the full request is read, even if the Handler doesn't do it.

@reem
Copy link
Contributor

reem commented Dec 13, 2014

We could call the appropriate reading/writing functions in Drop, thereby ensuring we always read or write even if the Handler does nothing.

seanmonstar added a commit that referenced this issue Feb 14, 2015
If a client sent an illegal request (like a GET request with a message
body), or if there was a legal request with a body but the Handler
didn't read all of it, the remaining bytes would be left in the stream.
The next request to come from the same client would error, as the server
would confuse the remaining bytes, and think the request was malformed.

Fixes #197
Fixes #309
seanmonstar added a commit that referenced this issue Feb 14, 2015
If a client sent an illegal request (like a GET request with a message
body), or if there was a legal request with a body but the Handler
didn't read all of it, the remaining bytes would be left in the stream.
The next request to come from the same client would error, as the server
would confuse the remaining bytes, and think the request was malformed.

Fixes #197
Fixes #309
@reem reem closed this as completed in #310 Feb 14, 2015
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!
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants