Skip to main content

openmoat_proxy/server/
limits.rs

1//! Bounds on what one client can make the proxy hold.
2
3use std::io::{self, ErrorKind};
4use std::time::{Duration, Instant};
5
6/// Bounds on what one client can make the proxy hold.
7#[derive(Debug, Clone)]
8pub struct Limits {
9    /// Largest request head, in bytes.
10    pub max_head_bytes: usize,
11    /// Time allowed for the request head, and for the `ClientHello` after it.
12    pub handshake_timeout: Duration,
13    /// A relayed connection with no bytes either way for this long is closed.
14    pub idle_timeout: Duration,
15    /// Time allowed to connect to the destination.
16    pub connect_timeout: Duration,
17    /// Connections served at once; more are answered 503 and closed. With
18    /// sessions, one session (or the connections not yet authenticated) may
19    /// hold at most half of them.
20    pub max_connections: usize,
21    /// In session mode, how often an open connection is checked against its
22    /// session's taint again: one that the session's taint would now refuse
23    /// (it read secret material since) is closed.
24    pub taint_recheck: Duration,
25}
26
27impl Limits {
28    /// Refuse limits under which no connection could be served: a zero limit,
29    /// or a timeout too large to set a deadline with.
30    pub(super) fn check(&self) -> io::Result<()> {
31        let now = Instant::now();
32        let sizes = [
33            ("max_head_bytes", self.max_head_bytes),
34            ("max_connections", self.max_connections),
35        ];
36        let timeouts = [
37            ("handshake_timeout", self.handshake_timeout),
38            ("idle_timeout", self.idle_timeout),
39            ("connect_timeout", self.connect_timeout),
40            ("taint_recheck", self.taint_recheck),
41        ];
42        let bad = sizes
43            .iter()
44            .find(|(_, n)| *n == 0)
45            .map(|(name, _)| name)
46            .or_else(|| {
47                timeouts
48                    .iter()
49                    .find(|(_, d)| d.is_zero() || now.checked_add(*d).is_none())
50                    .map(|(name, _)| name)
51            });
52        match bad {
53            Some(name) => Err(io::Error::new(
54                ErrorKind::InvalidInput,
55                format!("proxy limit `{name}` is zero or too large"),
56            )),
57            None => Ok(()),
58        }
59    }
60}
61
62impl Default for Limits {
63    fn default() -> Self {
64        Self {
65            max_head_bytes: 16 * 1024,
66            handshake_timeout: Duration::from_secs(10),
67            idle_timeout: Duration::from_mins(2),
68            connect_timeout: Duration::from_secs(10),
69            max_connections: 256,
70            taint_recheck: Duration::from_secs(1),
71        }
72    }
73}