-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Support CONNECT over h2 #2508
Comments
AFAICT for the client part we mostly want to patch this match arm: Lines 217 to 290 in 117cc49
Specifically, ultimately we want to patch this snippet so that it inserts an Lines 270 to 280 in 117cc49
The first issue I'm experiencing is that the |
I guess I can change the struct enum SendBuf<B> {
Buf(B),
Cursor(Cursor<Box<[u8]>>),
None,
} where |
To implement |
I'm also not exactly sure what |
AFAIK |
So, I implemented To implement struct H2Upgraded<B>
where
B: Buf,
{
ping: Recorder,
send_stream: SendStream<SendBuf<B>>,
recv_stream: RecvStream,
buf: Bytes,
}
impl<B> AsyncRead for H2Upgraded<B>
where
B: Buf,
{
fn poll_read(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
read_buf: &mut ReadBuf<'_>,
) -> Poll<Result<(), io::Error>> {
let mut polled_stream = false;
Poll::Ready(loop {
if !self.buf.is_empty() {
let cnt = std::cmp::min(self.buf.len(), read_buf.remaining());
read_buf.put_slice(&self.buf[..cnt]);
self.buf.advance(cnt);
let _ = self.recv_stream.flow_control().release_capacity(cnt);
}
if polled_stream || read_buf.remaining() == 0 {
break Ok(());
}
debug_assert!(!self.buf.is_empty());
self.buf = match ready!(self.recv_stream.poll_data(cx)) {
None => break Ok(()),
Some(Ok(buf)) => {
self.ping.record_data(buf.len());
buf
}
Some(Err(e)) => {
return Poll::Ready(Err(h2_to_io_error(e)));
}
};
polled_stream = true;
})
}
}
impl<B> AsyncWrite for H2Upgraded<B>
where
B: Buf,
{
fn poll_write(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<Result<usize, io::Error>> {
if buf.is_empty() {
return Poll::Ready(Ok(0));
}
self.send_stream.reserve_capacity(buf.len());
Poll::Ready(match ready!(self.send_stream.poll_capacity(cx)) {
None => Ok(0),
Some(Ok(cnt)) => self.write(&buf[..cnt], false).map(|()| cnt),
Some(Err(e)) => Err(h2_to_io_error(e)),
})
}
fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
Poll::Ready(Ok(()))
}
fn poll_shutdown(
mut self: Pin<&mut Self>,
_cx: &mut Context<'_>,
) -> Poll<Result<(), io::Error>> {
Poll::Ready(self.write(&[], true))
}
} So far so good, right? Then in the server code, I pass an
|
Ah right, it also wants |
@nox Thanks for implementing this -- is it complete so I can give it a try? I kind of worked around this by issuing a lower-case "connect" request and passing around a streaming body for the "connect" request. The streaming body is basically one end of the pipe (I used tokio's DuplexStream, but I just need a HalfDuplexStream). The other end of this pipe, and the response's streaming body become a custom H2Upgraded struct that satisfies the trait bound |
This PR only includes support for CONNECT over h2 on the server side, not the client, but yeah it works! |
There is a h2 issue but even if support for CONNECT was perfect in h2, there are still details to sort out on hyper itself too. I'm filing this issue because I started working on that today and will probably need some help.
The text was updated successfully, but these errors were encountered: