Skip to content

Commit b04f043

Browse files
committed
Make the capacity, max payload size and eviction interval configurable
This does not add the config bits, but does add the plumbing to set it from the Python size
1 parent bc5d2d0 commit b04f043

File tree

2 files changed

+52
-33
lines changed

2 files changed

+52
-33
lines changed

rust/src/rendezvous/mod.rs

Lines changed: 44 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,6 @@ use crate::{
3939

4040
mod session;
4141

42-
const MAX_CONTENT_LENGTH: u64 = 1024 * 100;
43-
const CAPACITY: usize = 100;
44-
4542
// n.b. Because OPTIONS requests are handled by the Python code, we don't need to set Access-Control-Allow-Headers.
4643
fn prepare_headers(headers: &mut HeaderMap, session: &Session) {
4744
headers.typed_insert(AccessControlAllowOrigin::ANY);
@@ -53,38 +50,42 @@ fn prepare_headers(headers: &mut HeaderMap, session: &Session) {
5350
headers.typed_insert(session.last_modified());
5451
}
5552

56-
fn check_input_headers(headers: &HeaderMap) -> PyResult<Mime> {
57-
let ContentLength(content_length) = headers.typed_get_required()?;
58-
59-
if content_length > MAX_CONTENT_LENGTH {
60-
return Err(SynapseError::new(
61-
StatusCode::PAYLOAD_TOO_LARGE,
62-
"Payload too large".to_owned(),
63-
"M_TOO_LARGE",
64-
None,
65-
None,
66-
));
67-
}
68-
69-
let content_type: ContentType = headers.typed_get_required()?;
70-
71-
Ok(content_type.into())
72-
}
73-
7453
#[pyclass]
7554
struct RendezvousHandler {
7655
base: Uri,
7756
clock: PyObject,
7857
sessions: BTreeMap<Ulid, Session>,
58+
capacity: usize,
59+
max_content_length: u64,
7960
}
8061

8162
impl RendezvousHandler {
82-
fn evict(&mut self, now: SystemTime, max_entries: usize) {
63+
/// Check the input headers of a request which sets data for a session, and return the content type.
64+
fn check_input_headers(&self, headers: &HeaderMap) -> PyResult<Mime> {
65+
let ContentLength(content_length) = headers.typed_get_required()?;
66+
67+
if content_length > self.max_content_length {
68+
return Err(SynapseError::new(
69+
StatusCode::PAYLOAD_TOO_LARGE,
70+
"Payload too large".to_owned(),
71+
"M_TOO_LARGE",
72+
None,
73+
None,
74+
));
75+
}
76+
77+
let content_type: ContentType = headers.typed_get_required()?;
78+
79+
Ok(content_type.into())
80+
}
81+
82+
/// Evict expired sessions and remove the oldest sessions until we're under the capacity.
83+
fn evict(&mut self, now: SystemTime) {
8384
// First remove all the entries which expired
8485
self.sessions.retain(|_, session| !session.expired(now));
8586

8687
// Then we remove the oldest entires until we're under the limit
87-
while self.sessions.len() > max_entries {
88+
while self.sessions.len() > self.capacity {
8889
self.sessions.pop_first();
8990
}
9091
}
@@ -93,7 +94,14 @@ impl RendezvousHandler {
9394
#[pymethods]
9495
impl RendezvousHandler {
9596
#[new]
96-
fn new(py: Python<'_>, homeserver: &PyAny) -> PyResult<Py<Self>> {
97+
#[pyo3(signature = (homeserver, /, capacity=100, max_content_length=1024*1024, eviction_interval=60*1000))]
98+
fn new(
99+
py: Python<'_>,
100+
homeserver: &PyAny,
101+
capacity: usize,
102+
max_content_length: u64,
103+
eviction_interval: u64,
104+
) -> PyResult<Py<Self>> {
97105
let base: String = homeserver
98106
.getattr("config")?
99107
.getattr("server")?
@@ -112,13 +120,17 @@ impl RendezvousHandler {
112120
base,
113121
clock,
114122
sessions: BTreeMap::new(),
123+
capacity,
124+
max_content_length,
115125
},
116126
)?;
117127

118128
let evict = self_.getattr(py, "_evict")?;
119-
homeserver
120-
.call_method0("get_clock")?
121-
.call_method("looping_call", (evict, 500), None)?;
129+
homeserver.call_method0("get_clock")?.call_method(
130+
"looping_call",
131+
(evict, eviction_interval),
132+
None,
133+
)?;
122134

123135
Ok(self_)
124136
}
@@ -127,23 +139,23 @@ impl RendezvousHandler {
127139
let clock = self.clock.as_ref(py);
128140
let now: u64 = clock.call_method0("time_msec")?.extract()?;
129141
let now = SystemTime::UNIX_EPOCH + Duration::from_millis(now);
130-
self.evict(now, CAPACITY);
142+
self.evict(now);
131143

132144
Ok(())
133145
}
134146

135147
fn handle_post(&mut self, py: Python<'_>, twisted_request: &PyAny) -> PyResult<()> {
136148
let request = http_request_from_twisted(twisted_request)?;
137149

138-
let content_type = check_input_headers(request.headers())?;
150+
let content_type = self.check_input_headers(request.headers())?;
139151

140152
let clock = self.clock.as_ref(py);
141153
let now: u64 = clock.call_method0("time_msec")?.extract()?;
142154
let now = SystemTime::UNIX_EPOCH + Duration::from_millis(now);
143155

144156
// We trigger an immediate eviction if we're at 2x the capacity
145-
if self.sessions.len() >= CAPACITY * 2 {
146-
self.evict(now, CAPACITY);
157+
if self.sessions.len() >= self.capacity * 2 {
158+
self.evict(now);
147159
}
148160

149161
// Generate a new ULID for the session from the current time.
@@ -210,7 +222,7 @@ impl RendezvousHandler {
210222
fn handle_put(&mut self, py: Python<'_>, twisted_request: &PyAny, id: &str) -> PyResult<()> {
211223
let request = http_request_from_twisted(twisted_request)?;
212224

213-
let content_type = check_input_headers(request.headers())?;
225+
let content_type = self.check_input_headers(request.headers())?;
214226

215227
let if_match: IfMatch = request.headers().typed_get_required()?;
216228

synapse/synapse_rust/rendezvous.pyi

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,14 @@ from twisted.web.iweb import IRequest
1515
from synapse.server import HomeServer
1616

1717
class RendezvousHandler:
18-
def __init__(self, homeserver: HomeServer) -> None: ...
18+
def __init__(
19+
self,
20+
homeserver: HomeServer,
21+
/,
22+
capacity: int = 100,
23+
max_content_length: int = 1024 * 1024,
24+
eviction_interval: int = 60 * 1000,
25+
) -> None: ...
1926
def handle_post(self, request: IRequest) -> None: ...
2027
def handle_get(self, request: IRequest, session_id: str) -> None: ...
2128
def handle_put(self, request: IRequest, session_id: str) -> None: ...

0 commit comments

Comments
 (0)