chiark / gitweb /
server: wip
[hippotat.git] / src / bin / server.rs
1 // Copyright 2021 Ian Jackson and contributors to Hippotat
2 // SPDX-License-Identifier: GPL-3.0-or-later
3 // There is NO WARRANTY.
4
5 use hippotat::prelude::*;
6
7 #[derive(StructOpt,Debug)]
8 pub struct Opts {
9   #[structopt(flatten)]
10   log: LogOpts,
11
12   #[structopt(flatten)]
13   config: config::Opts,
14 }
15
16 const METADATA_MAX_LEN: usize = MAX_OVERHEAD;
17
18 async fn handle(
19 //    context: (),
20 //    addr: SocketAddr,
21     req: hyper::Request<hyper::Body>
22 ) -> Result<hyper::Response<hyper::Body>, Infallible> {
23
24   let mkboundary = |b: &'_ _| format!("\n--{}", b).into_bytes();
25   let (boundary, warning) = (||{
26     let mut ctypes = req.headers().get_all("Content-Type").iter();
27     let t = ctypes.next().ok_or_else(|| anyhow!("missing Content-Type"))?;
28     if ctypes.next().is_some() { throw!(anyhow!("several Content-Type")) }
29     let t = t.to_str().context("interpret Content-Type as utf-8")?;
30     let t: mime::Mime = t.parse().context("parse Content-Type")?;
31     if t.type_() != "multipart" { throw!(anyhow!("not multipart/")) }
32     let b = mime::BOUNDARY;
33     let b = t.get_param(b).ok_or_else(|| anyhow!("missing boundary=..."))?;
34     let warning = (||{
35       if t.subtype() != "form-data" { throw!(anyhow!("not /form-data"))}
36       Ok::<_,AE>(())
37     })();
38     let b = mkboundary(b.as_str());
39     Ok::<_,AE>((b, warning))
40   })().unwrap_or_else(|e| {
41     (mkboundary("b"), Err(e.wrap_err("guessing boundary")))
42   });
43
44   if let Err(w) = &warning { eprintln!("warning={}", w); }
45
46   match async {
47     let mut body = req.into_body();
48     let initial = match read_limited_bytes(METADATA_MAX_LEN, &mut body).await {
49       Ok(all) => all,
50       Err(ReadLimitedError::Truncated { sofar,.. }) => sofar,
51       Err(ReadLimitedError::Hyper(e)) => throw!(e),
52     };
53
54     eprintln!("boundary={:?} initial={:?}", boundary, initial);
55
56     Ok::<_,AE>(())
57   }.await {
58     Ok(()) => {
59     },
60     Err(e) => {
61       eprintln!("error={}", e);
62     }
63   }
64
65   Ok(hyper::Response::new(hyper::Body::from("Hello World")))
66 }
67
68
69 #[tokio::main]
70 async fn main() {
71   let opts = Opts::from_args();
72   let mut hservers = vec![];
73   let (ics,(global,ipif)) = config::startup(
74     "hippotatd", LinkEnd::Server,
75     &opts.config, &opts.log, |ics|
76   {
77     let global = config::InstanceConfigGlobal::from(&ics);
78     let ipif = Ipif::start(&global.ipif, None)?;
79
80     let make_service = hyper::service::make_service_fn(|_conn| async {
81       Ok::<_, Infallible>(hyper::service::service_fn(handle))
82     });
83
84     for addr in &global.addrs {
85       let addr = SocketAddr::new(*addr, global.port);
86       let server = hyper::Server::try_bind(&addr)
87         .context("bind")?
88         .http1_preserve_header_case(true)
89         .serve(make_service);
90       info!("listening on {}", &addr);
91       let task = tokio::task::spawn(server);
92       hservers.push(task);
93     }
94
95     Ok((global, ipif))
96   });
97
98   let x = future::select_all(&mut hservers).await;
99   error!("xxx hserver {:?}", &x);
100
101   ipif.quitting(None).await;
102
103   dbg!(ics, global);
104 }