httpio 0.2.4

A transport-agnostic, async HTTP/1.1 client library for any runtime.
Documentation
use futures_rustls::{TlsAcceptor, rustls};
use futures::io::AsyncReadExt;
use futures::{AsyncBufRead, AsyncWrite};
use httpio::enums::http_body::HttpBody;
use httpio::enums::http_status_code::HttpStatusCode;
use httpio::structures::connection::http_server_connection::HttpServerConnection;
use httpio::structures::http_response::HttpResponse;
use rcgen::generate_simple_self_signed;
use rustls::pki_types::{CertificateDer, PrivateKeyDer};
use smol::io::BufReader;
use smol::net::TcpListener;
use smol::stream::StreamExt;
use std::sync::Arc;

const HTTP_ADDR: &str = "127.0.0.1:8081";
const HTTPS_ADDR: &str = "127.0.0.1:8443";

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let subject_alt_names = vec!["localhost".to_string(), "127.0.0.1".to_string()];
    let cert = generate_simple_self_signed(subject_alt_names).unwrap();
    
    let cert_der = cert.cert.der().to_vec();
    let priv_key_der = cert.key_pair.serialize_der();
    
    let certs = vec![CertificateDer::from(cert_der)];
    let private_key = PrivateKeyDer::try_from(priv_key_der).unwrap();

    let config = rustls::ServerConfig::builder()
        .with_no_client_auth()
        .with_single_cert(certs, private_key)
        .map_err(|e| format!("TLS config error: {}", e))?;
    
    let acceptor = TlsAcceptor::from(Arc::new(config));

    smol::block_on(async {
        let http_task = smol::spawn(run_http_server());
        let https_task = smol::spawn(run_https_server(acceptor));

        let _ = futures::future::join(http_task, https_task).await;
        Ok(())
    })
}

async fn run_http_server() -> Result<(), std::io::Error> {
    let http_listener = TcpListener::bind(HTTP_ADDR).await?;
    println!("HTTP Listening on {}", HTTP_ADDR);
    
    let mut incoming = http_listener.incoming();
    while let Some(stream) = incoming.next().await {
        match stream {
            Ok(stream) => {
                smol::spawn(async move {
                    let reader = BufReader::new(stream.clone());
                    let writer = stream;
                    handle_connection(reader, writer).await;
                }).detach();
            }
            Err(e) => eprintln!("Error accepting HTTP connection: {}", e),
        }
    }
    Ok(())
}

async fn run_https_server(acceptor: TlsAcceptor) -> Result<(), std::io::Error> {
    let https_listener = TcpListener::bind(HTTPS_ADDR).await?;
    println!("HTTPS Listening on {}", HTTPS_ADDR);
    
    let mut incoming = https_listener.incoming();
    while let Some(stream) = incoming.next().await {
        match stream {
            Ok(stream) => {
                let acceptor = acceptor.clone();
                smol::spawn(async move {
                    match acceptor.accept(stream).await {
                        Ok(tls_stream) => {
                            let (reader, writer) = tls_stream.split();
                            let reader = BufReader::new(reader);
                            handle_connection(reader, writer).await;
                        }
                        Err(e) => eprintln!("TLS handshake error: {}", e),
                    }
                }).detach();
            }
            Err(e) => eprintln!("Error accepting HTTPS connection: {}", e),
        }
    }
    Ok(())
}

async fn handle_connection<R, W>(reader: R, writer: W)
where
    R: AsyncBufRead + Unpin + Send + 'static,
    W: AsyncWrite + Unpin + Send + 'static,
{
    let mut connection = HttpServerConnection::new(reader, writer);

    match connection.read_request().await {
        Ok(request) => {
            println!("Received request: {} {}", request.method.to_string(), request.path);
            
            let body_content = format!("Hello, World! You requested {}", request.path);
            let body = HttpBody::Content(body_content.into_bytes());
            
            let response = HttpResponse::new(HttpStatusCode::Ok, body);
            
            if let Err(e) = connection.send_response(response).await {
                eprintln!("Failed to send response: {}", e);
            }
        }
        Err(e) => eprintln!("Failed to read request: {}", e),
    }
}