Working implementation

This commit is contained in:
Antun Krasic
2024-04-11 08:29:55 +01:00
parent 2af2ad132a
commit a6d17d61ae
3 changed files with 658 additions and 121 deletions

View File

@@ -1,96 +1,31 @@
use hyper::body::{Body as HttpBody, Bytes, Frame};
use hyper::{Error, Request, Response};
use hyper::body::Bytes;
use http_body_util::{combinators::BoxBody, BodyExt, Empty};
use hyper::Request;
use hyper_util::rt::TokioIo;
use std::marker::PhantomData;
use std::pin::Pin;
use std::task::{Context, Poll};
use tokio::net::TcpStream;
use tracing::{debug, Value};
use log::debug;
use tokio_rustls::{rustls, TlsConnector};
use std::sync::Arc;
#[derive(Clone, Copy, Debug)]
struct LocalExec;
pub fn empty_body() -> BoxBody<Bytes, hyper::Error> {
Empty::<Bytes>::new()
.map_err(|never| match never {})
.boxed()
}
impl<F> hyper::rt::Executor<F> for LocalExec
where
F: std::future::Future + Send + 'static,
//
// With using the HTTP2 we need to take the executre
// https://docs.rs/hyper/latest/hyper/rt/trait.Executor.html
#[derive(Clone, Debug)]
struct MyExecutor;
impl<F> hyper::rt::Executor<F> for MyExecutor
where
F: std::future::Future + Send + 'static,
F::Output: Send + 'static,
{
fn execute(&self, fut: F) {
tokio::task::spawn(fut);
}
}
struct IOTypeNotSend {
_marker: PhantomData<()>,
stream: hyper_util::rt::TokioIo<tokio::net::TcpStream>,
}
impl IOTypeNotSend {
fn new(stream: TokioIo<TcpStream>) -> Self {
Self {
_marker: PhantomData,
stream,
}
}
}
impl hyper::rt::Write for IOTypeNotSend {
fn poll_write(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<Result<usize, std::io::Error>> {
Pin::new(&mut self.stream).poll_write(cx, buf)
}
fn poll_flush(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Result<(), std::io::Error>> {
Pin::new(&mut self.stream).poll_flush(cx)
}
fn poll_shutdown(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> std::task::Poll<Result<(), std::io::Error>> {
Pin::new(&mut self.stream).poll_shutdown(cx)
}
}
impl hyper::rt::Read for IOTypeNotSend {
fn poll_read(
mut self: std::pin::Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
buf: hyper::rt::ReadBufCursor<'_>,
) -> std::task::Poll<Result<(), std::io::Error>> {
Pin::new(&mut self.stream).poll_read(cx, buf)
}
}
#[derive(Debug)]
struct Body {
_marker: PhantomData<()>,
data: Option<Bytes>,
}
impl From<String> for Body {
fn from(a: String) -> Self {
Body {
_marker: PhantomData,
data: Some(a.into()),
}
}
}
impl HttpBody for Body {
type Data = Bytes;
type Error = Error;
fn poll_frame(
self: Pin<&mut Self>,
_: &mut Context<'_>,
) -> Poll<Option<Result<Frame<Self::Data>, Error>>> {
Poll::Ready(self.get_mut().data.take().map(|d| Ok(Frame::data(d))))
fn execute(&self, future: F) {
tokio::spawn(future);
}
}
@@ -100,13 +35,46 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
.with_max_level(tracing::Level::TRACE)
.init();
let target_host = "167.235.156.145:443";
let domain = "g.s0c.in";
let tcp_stream = tokio::net::TcpStream::connect(target_host).await?;
let io = IOTypeNotSend::new(hyper_util::rt::TokioIo::new(tcp_stream));
let (mut sender, conn) =
hyper::client::conn::http2::handshake::<LocalExec, IOTypeNotSend, Body>(LocalExec, io)
.await?;
let mut root_cert_store = rustls::RootCertStore::empty();
root_cert_store.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());
let mut config = rustls::ClientConfig::builder().with_root_certificates(root_cert_store).with_no_client_auth();
// Available protocols: http/1.0, http/1.1, h2
config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec(), b"http/1.0".to_vec()];
let connector = TlsConnector::from(Arc::new(config));
// Look into adding tokiotls there working with setting up a client TLS connection
//
// Connection established with the remote host
// Establish valid Client TLS negotiation process
// Craft the request - HTTP/1.1 or HTTP/2 needs to be looked at
// Send the request.
//
// From the intiial look, it might seem that the needed action here is to do the
// actual TLS negtiation based on the `TcpStream` that was opened.
// Established a valid TLS connection.
//
// Once a TLS connection is estasblished either a HTTP/1.1 request should be sent
// over the line.
// Or establish a HTTP/2 type connection to stream over the TLS connection.
//
let tcp_stream = TcpStream::connect(target_host).await?;
let tls_domain = rustls_pki_types::ServerName::try_from(domain).map_err(|_| std::io::Error::new(std::io::ErrorKind::InvalidInput, "invalid dnsname"))?.to_owned();
// let io = IOTypeNotSend::new(hyper_util::rt::TokioIo::new(tcp_stream));
let stream = connector.connect(tls_domain, tcp_stream).await?;
let io = TokioIo::new(stream);
// let (mut sender, conn) = hyper::client::conn::http1::handshake(io).await.unwrap();
let (mut sender, conn) = hyper::client::conn::http2::handshake(MyExecutor, io).await?;
tokio::task::spawn(async move {
if let Err(e) = conn.await {
@@ -114,19 +82,19 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
}
});
let upstream = Request::builder()
.uri("/")
.header("host", "g.s0c.in")
// .version(hyper::Version::HTTP_2)
.body(Body::from("".to_string()))?;
let upstream_request = Request::builder()
.uri("https://g.s0c.in/")
// .header("host", domain)
.header("user-agent", "lolza-0.2")
.version(hyper::Version::HTTP_2)
.body(empty_body())?;
debug!("Sending out the request -----");
println!("{:#?}", upstream);
let res = sender.send_request(upstream).await?;
debug!("---------- REQUEST SENT");
debug!("Request: {:#?}", upstream_request);
let res = sender.send_request(upstream_request).await?;
debug!("Response: {:#?}", res);
println!("{:#?}", res);
Ok(())
}