mgen-web.rs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. // An extremely minimal http server.
  2. // Accepts https GET requests with a "size" parameter, and responds with that many bytes.
  3. // Accepts all other https requests, and ignores whatever was given.
  4. use hyper::server::conn::AddrIncoming;
  5. use hyper::service::{make_service_fn, service_fn};
  6. use hyper::{Body, Method, Request, Response, Server, StatusCode};
  7. use hyper_rustls::TlsAcceptor;
  8. use mgen::log;
  9. use std::collections::HashMap;
  10. use std::io::BufReader;
  11. use std::str::FromStr;
  12. use tokio_rustls::rustls::PrivateKey;
  13. static MISSING: &[u8] = b"Missing field";
  14. static NOTNUMERIC: &[u8] = b"Number field is not numeric";
  15. async fn process(req: Request<Body>) -> Result<Response<Body>, hyper::Error> {
  16. let Some(query) = req.uri().query()
  17. else {
  18. return Ok(Response::builder()
  19. .status(StatusCode::UNPROCESSABLE_ENTITY)
  20. .body(Body::from(MISSING))
  21. .unwrap());
  22. };
  23. let params = url::form_urlencoded::parse(query.as_bytes())
  24. .into_owned()
  25. .collect::<HashMap<String, String>>();
  26. let Some(from) = params.get("user")
  27. else {
  28. return Ok(Response::builder()
  29. .status(StatusCode::UNPROCESSABLE_ENTITY)
  30. .body(Body::from(MISSING))
  31. .unwrap());
  32. };
  33. match req.method() {
  34. &Method::GET => {
  35. let Ok(size) = params
  36. .get("size")
  37. .map_or(Ok(0), |s| usize::from_str(s.as_str()))
  38. else {
  39. return Ok(Response::builder()
  40. .status(StatusCode::UNPROCESSABLE_ENTITY)
  41. .body(Body::from(NOTNUMERIC))
  42. .unwrap());
  43. };
  44. log!("sending,{},{}", from, size);
  45. let body = Body::from(vec![0; size]);
  46. Ok(Response::new(body))
  47. }
  48. _ => {
  49. log!("receiving,{}", from);
  50. Ok(Response::new(Body::empty()))
  51. }
  52. }
  53. }
  54. // FIXME: move this out into module to share with server (along with other shared functionality)
  55. fn load_private_key(filename: &str) -> PrivateKey {
  56. let keyfile = std::fs::File::open(filename).expect("cannot open private key file");
  57. let mut reader = BufReader::new(keyfile);
  58. loop {
  59. match rustls_pemfile::read_one(&mut reader).expect("cannot parse private key .pem file") {
  60. Some(rustls_pemfile::Item::RSAKey(key)) => return PrivateKey(key),
  61. Some(rustls_pemfile::Item::PKCS8Key(key)) => return PrivateKey(key),
  62. Some(rustls_pemfile::Item::ECKey(key)) => return PrivateKey(key),
  63. None => break,
  64. _ => {}
  65. }
  66. }
  67. panic!(
  68. "no keys found in {:?} (encrypted keys not supported)",
  69. filename
  70. );
  71. }
  72. #[tokio::main]
  73. async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
  74. let mut args = std::env::args();
  75. let _arg0 = args.next().unwrap();
  76. let cert_filename = args
  77. .next()
  78. .unwrap_or_else(|| panic!("no cert file provided"));
  79. let key_filename = args
  80. .next()
  81. .unwrap_or_else(|| panic!("no key file provided"));
  82. let listen_addr = args.next().unwrap_or("127.0.0.1:6398".to_string());
  83. let certfile = std::fs::File::open(cert_filename).expect("cannot open certificate file");
  84. let mut reader = BufReader::new(certfile);
  85. let certs: Vec<tokio_rustls::rustls::Certificate> = rustls_pemfile::certs(&mut reader)
  86. .unwrap()
  87. .iter()
  88. .map(|v| tokio_rustls::rustls::Certificate(v.clone()))
  89. .collect();
  90. let key = load_private_key(&key_filename);
  91. let config = tokio_rustls::rustls::ServerConfig::builder()
  92. .with_safe_default_cipher_suites()
  93. .with_safe_default_kx_groups()
  94. .with_safe_default_protocol_versions()
  95. .unwrap()
  96. .with_no_client_auth()
  97. .with_single_cert(certs, key)?;
  98. let incoming = AddrIncoming::bind(&listen_addr.parse()?)?;
  99. let acceptor = TlsAcceptor::builder()
  100. .with_tls_config(config)
  101. .with_http11_alpn()
  102. .with_incoming(incoming);
  103. let service = make_service_fn(|_| async { Ok::<_, std::io::Error>(service_fn(process)) });
  104. let server = Server::builder(acceptor).serve(service);
  105. log!("listening,{}", &listen_addr);
  106. server.await?;
  107. Ok(())
  108. }