rewrk to send origin-form URL in HTTP request line
Hi David,
Thanks for making rewrk. I wrote a web server (servlin) and I'm adding it to https://github.com/programatik29/rust-web-benchmarks which uses rewrk. The benchmark runs essentially rewrk -c 1 -d 1s -h http://127.0.0.1:3000/ but the requests are failing. I tracked down the root cause.
RFC 7230 says that ordinary HTTP requests must use the /path?query part of the URL, excluding the http://host part:
5.3.1. origin-form
The most common form of request-target is the origin-form.
origin-form = absolute-path [ "?" query ]When making a request directly to an origin server, other than a CONNECT or server-wide OPTIONS request (as detailed below), a client MUST send only the absolute path and query components of the target URI as the request-target. If the target URI's path component is empty, the client MUST send "/" as the path within the origin-form of request-target. A Host header field is also sent, as defined in Section 5.4.
For example, a client wishing to retrieve a representation of the resource identified as
http://www.example.org/where?q=nowdirectly from the origin server would open (or reuse) a TCP connection to port 80 of the host "www.example.org" and send the lines:
GET /where?q=now HTTP/1.1 Host: www.example.orgfollowed by the remainder of the request message.
It looks like we're sending the absolute-form url http://127.0.0.1:3000/ when we want to send the origin-form url /.
We're also omitting the port number in the Location header.
Send the request:
% rewrk -c 1 -d 1s -h http://127.0.0.1:3000/
Beginning round 1...
Benchmarking 1 connections @ http://127.0.0.1:3000/ for 1 second(s)
No requests completed successfully
%
Capture the request:
% nc -l 3000
GET http://127.0.0.1:3000/ HTTP/1.1
host: 127.0.0.1
%
The fix would go in crate::http::benchmark where we set http::Request.uri:
https://github.com/lnx-search/rewrk/blob/d811b98a60f227cac7da75bb665cd94d24b389d9/src/http/mod.rs#L112-L115
I think the fix would be something like this:
let mut uri_parts = user_input.into_parts();
uri_parts.scheme = None;
uri_parts.authority = None;
*request.uri_mut() = uri_parts.into();
Tangent: It's interesting that all of the popular Rust HTTP servers accept such invalid HTTP requests.
Cheers, Michael