2023-05-25 00:20:44 +00:00
|
|
|
use std::io::BufReader;
|
|
|
|
use std::net::SocketAddr;
|
|
|
|
use std::{fs::File, sync::Arc};
|
|
|
|
|
|
|
|
use moq::{session, transport};
|
2023-04-14 20:32:02 +00:00
|
|
|
|
|
|
|
use clap::Parser;
|
2023-05-25 00:20:44 +00:00
|
|
|
use ring::digest::{digest, SHA256};
|
|
|
|
use warp::Filter;
|
2023-04-14 20:32:02 +00:00
|
|
|
|
|
|
|
/// Search for a pattern in a file and display the lines that contain it.
|
2023-05-25 00:20:44 +00:00
|
|
|
#[derive(Parser, Clone)]
|
2023-04-14 20:32:02 +00:00
|
|
|
struct Cli {
|
2023-05-23 19:04:27 +00:00
|
|
|
/// Listen on this address
|
|
|
|
#[arg(short, long, default_value = "[::]:4443")]
|
|
|
|
addr: String,
|
2023-04-14 20:32:02 +00:00
|
|
|
|
2023-05-23 19:04:27 +00:00
|
|
|
/// Use the certificate file at this path
|
2023-05-25 00:20:44 +00:00
|
|
|
#[arg(short, long, default_value = "cert/localhost.crt")]
|
2023-05-23 19:04:27 +00:00
|
|
|
cert: String,
|
2023-04-14 20:32:02 +00:00
|
|
|
|
2023-05-23 19:04:27 +00:00
|
|
|
/// Use the private key at this path
|
2023-05-25 00:20:44 +00:00
|
|
|
#[arg(short, long, default_value = "cert/localhost.key")]
|
2023-05-23 19:04:27 +00:00
|
|
|
key: String,
|
2023-04-24 17:18:55 +00:00
|
|
|
|
2023-05-23 19:04:27 +00:00
|
|
|
/// Use the media file at this path
|
2023-05-25 00:20:44 +00:00
|
|
|
#[arg(short, long, default_value = "media/fragmented.mp4")]
|
2023-05-23 19:04:27 +00:00
|
|
|
media: String,
|
2023-04-24 17:18:55 +00:00
|
|
|
}
|
|
|
|
|
2023-05-25 00:20:44 +00:00
|
|
|
#[tokio::main]
|
|
|
|
async fn main() -> anyhow::Result<()> {
|
2023-05-23 19:04:27 +00:00
|
|
|
env_logger::init();
|
2023-04-24 17:18:55 +00:00
|
|
|
|
2023-05-25 00:20:44 +00:00
|
|
|
let moq_args = Cli::parse();
|
|
|
|
let http_args = moq_args.clone();
|
|
|
|
|
|
|
|
// TODO return result instead of panicing
|
|
|
|
tokio::task::spawn(async move { run_transport(moq_args).unwrap() });
|
|
|
|
|
|
|
|
run_http(http_args).await
|
|
|
|
}
|
2023-04-14 20:32:02 +00:00
|
|
|
|
2023-05-25 00:20:44 +00:00
|
|
|
// Run the WebTransport server using quiche.
|
|
|
|
fn run_transport(args: Cli) -> anyhow::Result<()> {
|
2023-05-23 19:04:27 +00:00
|
|
|
let server_config = transport::Config {
|
|
|
|
addr: args.addr,
|
|
|
|
cert: args.cert,
|
|
|
|
key: args.key,
|
|
|
|
};
|
2023-04-14 20:32:02 +00:00
|
|
|
|
2023-05-23 19:04:27 +00:00
|
|
|
let mut server = transport::Server::<session::Session>::new(server_config).unwrap();
|
|
|
|
server.run()
|
2023-05-02 18:05:21 +00:00
|
|
|
}
|
2023-05-25 00:20:44 +00:00
|
|
|
|
|
|
|
// Run a HTTP server using Warp
|
|
|
|
// TODO remove this when Chrome adds support for self-signed certificates using WebTransport
|
|
|
|
async fn run_http(args: Cli) -> anyhow::Result<()> {
|
|
|
|
let addr: SocketAddr = args.addr.parse()?;
|
|
|
|
|
|
|
|
// Read the PEM certificate file
|
|
|
|
let crt = File::open(&args.cert)?;
|
|
|
|
let mut crt = BufReader::new(crt);
|
|
|
|
|
|
|
|
// Parse the DER certificate
|
|
|
|
let certs = rustls_pemfile::certs(&mut crt)?;
|
|
|
|
let cert = certs.first().expect("no certificate found");
|
|
|
|
|
|
|
|
// Compute the SHA-256 digest
|
|
|
|
let fingerprint = digest(&SHA256, cert.as_ref());
|
|
|
|
let fingerprint = hex::encode(fingerprint.as_ref());
|
|
|
|
let fingerprint = Arc::new(fingerprint);
|
|
|
|
|
|
|
|
let cors = warp::cors().allow_any_origin();
|
|
|
|
|
|
|
|
// What an annoyingly complicated way to serve a static String
|
|
|
|
// I spent a long time trying to find the exact way of cloning and dereferencing the Arc.
|
|
|
|
let routes = warp::path!("fingerprint")
|
|
|
|
.map(move || (*(fingerprint.clone())).clone())
|
|
|
|
.with(cors);
|
|
|
|
|
|
|
|
warp::serve(routes)
|
|
|
|
.tls()
|
|
|
|
.cert_path(args.cert)
|
|
|
|
.key_path(args.key)
|
|
|
|
.run(addr)
|
|
|
|
.await;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|