allow servers to receive requests without an :authority header
This commit is contained in:
@@ -1236,20 +1236,32 @@ impl proto::Peer for Peer {
|
|||||||
// Convert the URI
|
// Convert the URI
|
||||||
let mut parts = uri::Parts::default();
|
let mut parts = uri::Parts::default();
|
||||||
|
|
||||||
if let Some(scheme) = pseudo.scheme {
|
|
||||||
let maybe_scheme = uri::Scheme::from_shared(scheme.clone().into_inner());
|
|
||||||
parts.scheme = Some(maybe_scheme.or_else(|why| malformed!(
|
|
||||||
"malformed headers: malformed scheme ({:?}): {}", scheme, why,
|
|
||||||
))?);
|
|
||||||
} else {
|
|
||||||
malformed!("malformed headers: missing scheme");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// A request translated from HTTP/1 must not include the :authority
|
||||||
|
// header
|
||||||
if let Some(authority) = pseudo.authority {
|
if let Some(authority) = pseudo.authority {
|
||||||
let maybe_authority = uri::Authority::from_shared(authority.clone().into_inner());
|
let maybe_authority = uri::Authority::from_shared(authority.clone().into_inner());
|
||||||
parts.authority = Some(maybe_authority.or_else(|why| malformed!(
|
parts.authority = Some(maybe_authority.or_else(|why| malformed!(
|
||||||
"malformed headers: malformed authority ({:?}): {}", authority, why,
|
"malformed headers: malformed authority ({:?}): {}", authority, why,
|
||||||
))?);
|
))?);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// A :scheme is always required.
|
||||||
|
if let Some(scheme) = pseudo.scheme {
|
||||||
|
let maybe_scheme = uri::Scheme::from_shared(scheme.clone().into_inner());
|
||||||
|
let scheme = maybe_scheme.or_else(|why| malformed!(
|
||||||
|
"malformed headers: malformed scheme ({:?}): {}", scheme, why,
|
||||||
|
))?;
|
||||||
|
|
||||||
|
// It's not possible to build an `Uri` from a scheme and path. So,
|
||||||
|
// after validating is was a valid scheme, we just have to drop it
|
||||||
|
// if there isn't an :authority.
|
||||||
|
if parts.authority.is_some() {
|
||||||
|
parts.scheme = Some(scheme);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
malformed!("malformed headers: missing scheme");
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(path) = pseudo.path {
|
if let Some(path) = pseudo.path {
|
||||||
|
|||||||
@@ -444,15 +444,13 @@ fn http_11_request_without_scheme_or_authority() {
|
|||||||
let h2 = client::handshake(io)
|
let h2 = client::handshake(io)
|
||||||
.expect("handshake")
|
.expect("handshake")
|
||||||
.and_then(|(mut client, h2)| {
|
.and_then(|(mut client, h2)| {
|
||||||
// we send a simple req here just to drive the connection so we can
|
// HTTP_11 request with just :path is allowed
|
||||||
// receive the server settings.
|
|
||||||
let request = Request::builder()
|
let request = Request::builder()
|
||||||
.method(Method::GET)
|
.method(Method::GET)
|
||||||
.uri("/")
|
.uri("/")
|
||||||
.body(())
|
.body(())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// first request is allowed
|
|
||||||
let (response, _) = client.send_request(request, true).unwrap();
|
let (response, _) = client.send_request(request, true).unwrap();
|
||||||
h2.drive(response)
|
h2.drive(response)
|
||||||
.map(move |(h2, _)| (client, h2))
|
.map(move |(h2, _)| (client, h2))
|
||||||
@@ -474,8 +472,8 @@ fn http_2_request_without_scheme_or_authority() {
|
|||||||
let h2 = client::handshake(io)
|
let h2 = client::handshake(io)
|
||||||
.expect("handshake")
|
.expect("handshake")
|
||||||
.and_then(|(mut client, h2)| {
|
.and_then(|(mut client, h2)| {
|
||||||
// we send a simple req here just to drive the connection so we can
|
// HTTP_2 with only a :path is illegal, so this request should
|
||||||
// receive the server settings.
|
// be rejected as a user error.
|
||||||
let request = Request::builder()
|
let request = Request::builder()
|
||||||
.version(Version::HTTP_2)
|
.version(Version::HTTP_2)
|
||||||
.method(Method::GET)
|
.method(Method::GET)
|
||||||
@@ -483,8 +481,10 @@ fn http_2_request_without_scheme_or_authority() {
|
|||||||
.body(())
|
.body(())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// first request is allowed
|
client
|
||||||
assert!(client.send_request(request, true).is_err());
|
.send_request(request, true)
|
||||||
|
.expect_err("should be UserError");
|
||||||
|
|
||||||
h2.expect("h2").map(|ret| {
|
h2.expect("h2").map(|ret| {
|
||||||
// Hold on to the `client` handle to avoid sending a GO_AWAY frame.
|
// Hold on to the `client` handle to avoid sending a GO_AWAY frame.
|
||||||
drop(client);
|
drop(client);
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ fn server_builder_set_max_concurrent_streams() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
stream.send_response(rsp, true).unwrap();
|
stream.send_response(rsp, true).unwrap();
|
||||||
|
|
||||||
srv.into_future().unwrap()
|
srv.into_future().unwrap().map(|_| ())
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -101,7 +101,7 @@ fn serve_request() {
|
|||||||
let rsp = http::Response::builder().status(200).body(()).unwrap();
|
let rsp = http::Response::builder().status(200).body(()).unwrap();
|
||||||
stream.send_response(rsp, true).unwrap();
|
stream.send_response(rsp, true).unwrap();
|
||||||
|
|
||||||
srv.into_future().unwrap()
|
srv.into_future().unwrap().map(|_| ())
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -134,7 +134,7 @@ fn recv_invalid_authority() {
|
|||||||
|
|
||||||
let srv = server::handshake(io)
|
let srv = server::handshake(io)
|
||||||
.expect("handshake")
|
.expect("handshake")
|
||||||
.and_then(|srv| srv.into_future().unwrap());
|
.and_then(|srv| srv.into_future().unwrap().map(|_| ()));
|
||||||
|
|
||||||
srv.join(client).wait().expect("wait");
|
srv.join(client).wait().expect("wait");
|
||||||
}
|
}
|
||||||
@@ -169,7 +169,7 @@ fn recv_connection_header() {
|
|||||||
|
|
||||||
let srv = server::handshake(io)
|
let srv = server::handshake(io)
|
||||||
.expect("handshake")
|
.expect("handshake")
|
||||||
.and_then(|srv| srv.into_future().unwrap());
|
.and_then(|srv| srv.into_future().unwrap()).map(|_| ());
|
||||||
|
|
||||||
srv.join(client).wait().expect("wait");
|
srv.join(client).wait().expect("wait");
|
||||||
}
|
}
|
||||||
@@ -200,7 +200,7 @@ fn sends_reset_cancel_when_req_body_is_dropped() {
|
|||||||
let rsp = http::Response::builder().status(200).body(()).unwrap();
|
let rsp = http::Response::builder().status(200).body(()).unwrap();
|
||||||
stream.send_response(rsp, true).unwrap();
|
stream.send_response(rsp, true).unwrap();
|
||||||
|
|
||||||
srv.into_future().unwrap()
|
srv.into_future().unwrap().map(|_| ())
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -390,7 +390,7 @@ fn sends_reset_cancel_when_res_body_is_dropped() {
|
|||||||
tx.send_data(vec![0; 10].into(), false).unwrap();
|
tx.send_data(vec![0; 10].into(), false).unwrap();
|
||||||
// no send_data with eos
|
// no send_data with eos
|
||||||
|
|
||||||
srv.into_future().unwrap()
|
srv.into_future().unwrap().map(|_| ())
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -625,3 +625,37 @@ fn server_error_on_unclean_shutdown() {
|
|||||||
|
|
||||||
srv.wait().expect_err("should error");
|
srv.wait().expect_err("should error");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn request_without_authority() {
|
||||||
|
let _ = ::env_logger::try_init();
|
||||||
|
let (io, client) = mock::new();
|
||||||
|
|
||||||
|
let client = client
|
||||||
|
.assert_server_handshake()
|
||||||
|
.unwrap()
|
||||||
|
.recv_settings()
|
||||||
|
.send_frame(
|
||||||
|
frames::headers(1)
|
||||||
|
.request("GET", "/just-a-path")
|
||||||
|
.scheme("http")
|
||||||
|
.eos()
|
||||||
|
)
|
||||||
|
.recv_frame(frames::headers(1).response(200).eos())
|
||||||
|
.close();
|
||||||
|
|
||||||
|
let srv = server::handshake(io).expect("handshake").and_then(|srv| {
|
||||||
|
srv.into_future().unwrap().and_then(|(reqstream, srv)| {
|
||||||
|
let (req, mut stream) = reqstream.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(req.uri().path(), "/just-a-path");
|
||||||
|
|
||||||
|
let rsp = Response::new(());
|
||||||
|
stream.send_response(rsp, true).unwrap();
|
||||||
|
|
||||||
|
srv.into_future().unwrap().map(|_| ())
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
srv.join(client).wait().expect("wait");
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user