Streamed read for binary HTTP#74
Conversation
|
@martinthomson Hi Martin, I've been looking at this PR and have a few questions that I hope you don't mind me asking.
diff --git a/bhttp/src/lib.rs b/bhttp/src/lib.rs
index 2082b0f..9063e7e 100644
--- a/bhttp/src/lib.rs
+++ b/bhttp/src/lib.rs
@@ -188,7 +188,10 @@ impl FieldSection {
}
/// Gets all of the values of the named field.
- pub fn get_all<'a, 'b>(&'a self, n: &'b [u8]) -> impl Iterator<Item = &'a [u8]> + use<'a, 'b> {
+ pub fn get_all<'a, 'b>(&'a self, n: &'b [u8]) -> impl Iterator<Item = &'a [u8]> + 'b
+ where
+ 'a: 'b,
+ {
self.0.iter().filter_map(move |f| {
if &f.name[..] == n {
Some(&f.value[..])Thanks again for your work on this — it's really helpful! |
|
|
I've taken your suggested change, though I can't see a way to avoid the 1.82 change, even though it is in a dependency that you might not need. There doesn't seem to be a way to make the MSRV conditional on the feature set chosen. And until we get rust 2024 edition (1.85) we are stuck with a dependency resolver that consistently finds dependencies that can't be compiled. |
|
@martinthomson Thank you for your detailed explanation and the work you've done on this project. Regarding the first point about writing BHTTP messages: I'm working on a scenario where I need to receive HTTP messages (e.g. a server-sent event http response), convert them to BHTTP format on-the-fly, and stream them out. This led me to think about implementing an async conversion between bhttp encoded request/response binary stream and I'm happy to draft a PR for this if you think it aligns with the crate's goals. Looking forward to your thoughts! |
|
@martinthomson Hi, I have created an early implementation of http-compat #82. Looking forward to your valuable feedback. |
|
Oh, this is great. I'll take a look tomorrow. |
|
Found a panic when decapsulating a long request: #[test]
fn long_request() {
init();
// A long request.
const LONG_REQUEST: &[u8] = &[0u8; 1024];
let server_config = make_config();
let server = Server::new(server_config).unwrap();
let encoded_config = server.config().encode().unwrap();
trace!("Config: {}", hex::encode(&encoded_config));
// The client sends a request.
let client = ClientRequest::from_encoded_config(&encoded_config).unwrap();
let (mut request_read, request_write) = Pipe::new();
let mut client_request = client.encapsulate_stream(request_write).unwrap();
client_request
.write_all(LONG_REQUEST)
.sync_resolve()
.unwrap();
client_request.close().sync_resolve().unwrap();
trace!("Request: {}", hex::encode(LONG_REQUEST));
let enc_request = request_read.sync_read_to_end();
trace!("Encapsulated Request: {}", hex::encode(&enc_request));
// The server receives a request.
let mut server_request = server.decapsulate_stream(&enc_request[..]); // <---- panic here
assert_eq!(server_request.sync_read_to_end(), LONG_REQUEST);
}panic message The out of range access happens here: Line 490 in 8628e6c |
|
Well, that embarrassing. That's a pretty big omission on my part. Thanks for finding it, and for the easy test case. The fix is non-trivial, but I'm on it. |
|
Hey @martinthomson, no worries at all. I'm glad we found the issue! |
The original code assumed that the output would always be large enough for an entire chunk. Thankfully, it didn't take much of a buffer for that assumption to be proven false.
|
I've put a fix in place. It should be a little more complete than yours (you lost the value of |
This is far from ready.
It also requires an MSRV update to 1.82, which is brand new, so I don't want to say that this is ready to land.
Missing:
Bodyimplementation), but this is still likely to be non-trivial.