Upgrade to env_logger 0.5 and log 0.4 so that projects that use those versions don't have to build both those versions and the older ones that h2 is currently using. Don't enable the regex support in env_logger. Applications that want the regex support can enable it themselves; this will happen automatically when they add their env_logger dependency. Disable the env_logger dependency in quickcheck. The result of this is that there are fewer dependencies. For example, regex and its dependencies are no longer required at all, as can be seen by observing the changes to the Cargo.lock. That said, env_logger 0.5 does add more dependencies itself; however it seems applications are going to use env_logger 0.5 anyway so this is still a net gain. Submitted on behalf of Buoyant, Inc. Signed-off-by: Brian Smith <brian@briansmith.org>
409 lines
12 KiB
Rust
409 lines
12 KiB
Rust
pub mod support;
|
|
use support::prelude::*;
|
|
|
|
const SETTINGS: &'static [u8] = &[0, 0, 0, 4, 0, 0, 0, 0, 0];
|
|
const SETTINGS_ACK: &'static [u8] = &[0, 0, 0, 4, 1, 0, 0, 0, 0];
|
|
|
|
#[test]
|
|
fn read_preface_in_multiple_frames() {
|
|
let _ = ::env_logger::try_init();
|
|
|
|
let mock = mock_io::Builder::new()
|
|
.read(b"PRI * HTTP/2.0")
|
|
.read(b"\r\n\r\nSM\r\n\r\n")
|
|
.write(SETTINGS)
|
|
.read(SETTINGS)
|
|
.write(SETTINGS_ACK)
|
|
.read(SETTINGS_ACK)
|
|
.build();
|
|
|
|
let h2 = server::handshake(mock).wait().unwrap();
|
|
|
|
assert!(Stream::wait(h2).next().is_none());
|
|
}
|
|
|
|
#[test]
|
|
fn server_builder_set_max_concurrent_streams() {
|
|
let _ = ::env_logger::try_init();
|
|
let (io, client) = mock::new();
|
|
|
|
let mut settings = frame::Settings::default();
|
|
settings.set_max_concurrent_streams(Some(1));
|
|
|
|
let client = client
|
|
.assert_server_handshake()
|
|
.unwrap()
|
|
.recv_custom_settings(settings)
|
|
.send_frame(
|
|
frames::headers(1)
|
|
.request("GET", "https://example.com/"),
|
|
)
|
|
.send_frame(
|
|
frames::headers(3)
|
|
.request("GET", "https://example.com/"),
|
|
)
|
|
.send_frame(frames::data(1, &b"hello"[..]).eos(),)
|
|
.recv_frame(frames::reset(3).refused())
|
|
.recv_frame(frames::headers(1).response(200).eos())
|
|
.close();
|
|
|
|
let mut builder = server::Builder::new();
|
|
builder.max_concurrent_streams(1);
|
|
|
|
let h2 = builder
|
|
.handshake::<_, Bytes>(io)
|
|
.expect("handshake")
|
|
.and_then(|srv| {
|
|
srv.into_future().unwrap().and_then(|(reqstream, srv)| {
|
|
let (req, mut stream) = reqstream.unwrap();
|
|
|
|
assert_eq!(req.method(), &http::Method::GET);
|
|
|
|
let rsp =
|
|
http::Response::builder()
|
|
.status(200).body(())
|
|
.unwrap();
|
|
stream.send_response(rsp, true).unwrap();
|
|
|
|
srv.into_future().unwrap()
|
|
})
|
|
});
|
|
|
|
h2.join(client).wait().expect("wait");
|
|
}
|
|
|
|
#[test]
|
|
fn serve_request() {
|
|
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", "https://example.com/")
|
|
.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.method(), &http::Method::GET);
|
|
|
|
let rsp = http::Response::builder().status(200).body(()).unwrap();
|
|
stream.send_response(rsp, true).unwrap();
|
|
|
|
srv.into_future().unwrap()
|
|
})
|
|
});
|
|
|
|
srv.join(client).wait().expect("wait");
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn accept_with_pending_connections_after_socket_close() {}
|
|
|
|
#[test]
|
|
fn recv_invalid_authority() {
|
|
let _ = ::env_logger::try_init();
|
|
let (io, client) = mock::new();
|
|
|
|
let bad_auth = util::byte_str("not:a/good authority");
|
|
let mut bad_headers: frame::Headers = frames::headers(1)
|
|
.request("GET", "https://example.com/")
|
|
.eos()
|
|
.into();
|
|
bad_headers.pseudo_mut().authority = Some(bad_auth);
|
|
|
|
let client = client
|
|
.assert_server_handshake()
|
|
.unwrap()
|
|
.recv_settings()
|
|
.send_frame(bad_headers)
|
|
.recv_frame(frames::reset(1).protocol_error())
|
|
.close();
|
|
|
|
let srv = server::handshake(io)
|
|
.expect("handshake")
|
|
.and_then(|srv| srv.into_future().unwrap());
|
|
|
|
srv.join(client).wait().expect("wait");
|
|
}
|
|
|
|
#[test]
|
|
fn recv_connection_header() {
|
|
let _ = ::env_logger::try_init();
|
|
let (io, client) = mock::new();
|
|
|
|
let req = |id, name, val| {
|
|
frames::headers(id)
|
|
.request("GET", "https://example.com/")
|
|
.field(name, val)
|
|
.eos()
|
|
};
|
|
|
|
let client = client
|
|
.assert_server_handshake()
|
|
.unwrap()
|
|
.recv_settings()
|
|
.send_frame(req(1, "connection", "foo"))
|
|
.send_frame(req(3, "keep-alive", "5"))
|
|
.send_frame(req(5, "proxy-connection", "bar"))
|
|
.send_frame(req(7, "transfer-encoding", "chunked"))
|
|
.send_frame(req(9, "upgrade", "HTTP/2.0"))
|
|
.recv_frame(frames::reset(1).protocol_error())
|
|
.recv_frame(frames::reset(3).protocol_error())
|
|
.recv_frame(frames::reset(5).protocol_error())
|
|
.recv_frame(frames::reset(7).protocol_error())
|
|
.recv_frame(frames::reset(9).protocol_error())
|
|
.close();
|
|
|
|
let srv = server::handshake(io)
|
|
.expect("handshake")
|
|
.and_then(|srv| srv.into_future().unwrap());
|
|
|
|
srv.join(client).wait().expect("wait");
|
|
}
|
|
|
|
#[test]
|
|
fn sends_reset_cancel_when_req_body_is_dropped() {
|
|
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("POST", "https://example.com/")
|
|
)
|
|
.recv_frame(frames::headers(1).response(200).eos())
|
|
.recv_frame(frames::reset(1).cancel())
|
|
.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.method(), &http::Method::POST);
|
|
|
|
let rsp = http::Response::builder().status(200).body(()).unwrap();
|
|
stream.send_response(rsp, true).unwrap();
|
|
|
|
srv.into_future().unwrap()
|
|
})
|
|
});
|
|
|
|
srv.join(client).wait().expect("wait");
|
|
}
|
|
|
|
#[test]
|
|
fn sends_goaway_when_serv_closes_connection() {
|
|
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("POST", "https://example.com/")
|
|
)
|
|
.recv_frame(frames::go_away(1))
|
|
.close();
|
|
|
|
let srv = server::handshake(io).expect("handshake").and_then(|srv| {
|
|
srv.into_future().unwrap().and_then(|(_, mut srv)| {
|
|
srv.close_connection();
|
|
srv.into_future().unwrap()
|
|
})
|
|
});
|
|
|
|
srv.join(client).wait().expect("wait");
|
|
}
|
|
|
|
#[test]
|
|
fn serve_request_then_serv_closes_connection() {
|
|
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", "https://example.com/"),
|
|
)
|
|
.recv_frame(frames::headers(1).response(200).eos())
|
|
.recv_frame(frames::reset(1).cancel())
|
|
.send_frame(
|
|
frames::headers(3)
|
|
.request("GET", "https://example.com/"),
|
|
)
|
|
.recv_frame(frames::go_away(3))
|
|
// streams sent after GOAWAY receive no response
|
|
.send_frame(
|
|
frames::headers(5)
|
|
.request("GET", "https://example.com/"),
|
|
)
|
|
.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.method(), &http::Method::GET);
|
|
|
|
let rsp = http::Response::builder().status(200).body(()).unwrap();
|
|
stream.send_response(rsp, true).unwrap();
|
|
|
|
srv.into_future().unwrap().and_then(|(_reqstream, mut srv)| {
|
|
srv.close_connection();
|
|
srv.into_future().unwrap()
|
|
})
|
|
})
|
|
});
|
|
|
|
srv.join(client).wait().expect("wait");
|
|
}
|
|
|
|
#[test]
|
|
fn sends_reset_cancel_when_res_body_is_dropped() {
|
|
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", "https://example.com/")
|
|
.eos()
|
|
)
|
|
.recv_frame(frames::headers(1).response(200))
|
|
.recv_frame(frames::reset(1).cancel())
|
|
.send_frame(
|
|
frames::headers(3)
|
|
.request("GET", "https://example.com/")
|
|
.eos()
|
|
)
|
|
.recv_frame(frames::headers(3).response(200))
|
|
.recv_frame(frames::data(3, vec![0; 10]))
|
|
.recv_frame(frames::reset(3).cancel())
|
|
.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.method(), &http::Method::GET);
|
|
|
|
let rsp = http::Response::builder()
|
|
.status(200)
|
|
.body(())
|
|
.unwrap();
|
|
stream.send_response(rsp, false).unwrap();
|
|
// SendStream dropped
|
|
|
|
srv.into_future().unwrap()
|
|
}).and_then(|(reqstream, srv)| {
|
|
let (_req, mut stream) = reqstream.unwrap();
|
|
|
|
let rsp = http::Response::builder()
|
|
.status(200)
|
|
.body(())
|
|
.unwrap();
|
|
let mut tx = stream.send_response(rsp, false).unwrap();
|
|
tx.send_data(vec![0; 10].into(), false).unwrap();
|
|
// no send_data with eos
|
|
|
|
srv.into_future().unwrap()
|
|
})
|
|
});
|
|
|
|
srv.join(client).wait().expect("wait");
|
|
}
|
|
|
|
#[test]
|
|
fn too_big_headers_sends_431() {
|
|
let _ = ::env_logger::try_init();
|
|
let (io, client) = mock::new();
|
|
|
|
let client = client
|
|
.assert_server_handshake()
|
|
.unwrap()
|
|
.recv_custom_settings(
|
|
frames::settings()
|
|
.max_header_list_size(10)
|
|
)
|
|
.send_frame(
|
|
frames::headers(1)
|
|
.request("GET", "https://example.com/")
|
|
.field("some-header", "some-value")
|
|
.eos()
|
|
)
|
|
.recv_frame(frames::headers(1).response(431).eos())
|
|
.idle_ms(10)
|
|
.close();
|
|
|
|
let srv = server::Builder::new()
|
|
.max_header_list_size(10)
|
|
.handshake::<_, Bytes>(io)
|
|
.expect("handshake")
|
|
.and_then(|srv| {
|
|
srv.into_future()
|
|
.expect("server")
|
|
.map(|(req, _)| {
|
|
assert!(req.is_none(), "req is {:?}", req);
|
|
})
|
|
});
|
|
|
|
srv.join(client).wait().expect("wait");
|
|
}
|
|
|
|
#[test]
|
|
fn too_big_headers_sends_reset_after_431_if_not_eos() {
|
|
let _ = ::env_logger::try_init();
|
|
let (io, client) = mock::new();
|
|
|
|
let client = client
|
|
.assert_server_handshake()
|
|
.unwrap()
|
|
.recv_custom_settings(
|
|
frames::settings()
|
|
.max_header_list_size(10)
|
|
)
|
|
.send_frame(
|
|
frames::headers(1)
|
|
.request("GET", "https://example.com/")
|
|
.field("some-header", "some-value")
|
|
)
|
|
.recv_frame(frames::headers(1).response(431).eos())
|
|
.recv_frame(frames::reset(1).refused())
|
|
.close();
|
|
|
|
let srv = server::Builder::new()
|
|
.max_header_list_size(10)
|
|
.handshake::<_, Bytes>(io)
|
|
.expect("handshake")
|
|
.and_then(|srv| {
|
|
srv.into_future()
|
|
.expect("server")
|
|
.map(|(req, _)| {
|
|
assert!(req.is_none(), "req is {:?}", req);
|
|
})
|
|
});
|
|
|
|
srv.join(client).wait().expect("wait");
|
|
}
|