@@ -39,9 +39,6 @@ use crate::{
3939
4040mod 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.
4643fn 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]
7554struct RendezvousHandler {
7655 base : Uri ,
7756 clock : PyObject ,
7857 sessions : BTreeMap < Ulid , Session > ,
58+ capacity : usize ,
59+ max_content_length : u64 ,
7960}
8061
8162impl 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]
9495impl 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
0 commit comments