@@ -21,6 +21,8 @@ static SERVER_FULL_ERROR_MESSAGE: &[u8] = b"HTTP/1.1 503\r\n\
21
21
Connection: close\r \n \
22
22
Content-Length: 40\r \n \r \n { \" error\" : \" Too many open connections\" }";
23
23
const MAX_CONNECTIONS : usize = 10 ;
24
+ /// Payload max size
25
+ pub ( crate ) const MAX_PAYLOAD_SIZE : usize = 51200 ;
24
26
25
27
type Result < T > = std:: result:: Result < T , ServerError > ;
26
28
@@ -259,6 +261,8 @@ pub struct HttpServer {
259
261
/// We use the file descriptor of the stream as the key for mapping
260
262
/// connections because the 1-to-1 relation is guaranteed by the OS.
261
263
connections : HashMap < RawFd , ClientConnection < UnixStream > > ,
264
+ /// Payload max size
265
+ payload_max_size : usize ,
262
266
}
263
267
264
268
impl HttpServer {
@@ -275,6 +279,7 @@ impl HttpServer {
275
279
socket,
276
280
epoll,
277
281
connections : HashMap :: new ( ) ,
282
+ payload_max_size : MAX_PAYLOAD_SIZE ,
278
283
} )
279
284
}
280
285
@@ -295,9 +300,16 @@ impl HttpServer {
295
300
socket,
296
301
epoll,
297
302
connections : HashMap :: new ( ) ,
303
+ payload_max_size : MAX_PAYLOAD_SIZE ,
298
304
} )
299
305
}
300
306
307
+ /// This function sets the limit for PUT/PATCH requests. It overwrites the
308
+ /// default limit of 0.05MiB with the one allowed by server.
309
+ pub fn set_payload_max_size ( & mut self , request_payload_max_size : usize ) {
310
+ self . payload_max_size = request_payload_max_size;
311
+ }
312
+
301
313
/// Starts the HTTP Server.
302
314
pub fn start_server ( & mut self ) -> Result < ( ) > {
303
315
// Add the socket on which we listen for new connections to the
@@ -573,12 +585,12 @@ impl HttpServer {
573
585
} )
574
586
. and_then ( |stream| {
575
587
// Add the stream to the `epoll` structure and listen for bytes to be read.
576
- Self :: epoll_add ( & self . epoll , stream. as_raw_fd ( ) ) ?;
588
+ let raw_fd = stream. as_raw_fd ( ) ;
589
+ Self :: epoll_add ( & self . epoll , raw_fd) ?;
590
+ let mut conn = HttpConnection :: new ( stream) ;
591
+ conn. set_payload_max_size ( self . payload_max_size ) ;
577
592
// Then add it to our open connections.
578
- self . connections . insert (
579
- stream. as_raw_fd ( ) ,
580
- ClientConnection :: new ( HttpConnection :: new ( stream) ) ,
581
- ) ;
593
+ self . connections . insert ( raw_fd, ClientConnection :: new ( conn) ) ;
582
594
Ok ( ( ) )
583
595
} )
584
596
}
@@ -676,6 +688,73 @@ mod tests {
676
688
assert ! ( socket. read( & mut buf[ ..] ) . unwrap( ) > 0 ) ;
677
689
}
678
690
691
+ #[ test]
692
+ fn test_connection_size_limit_exceeded ( ) {
693
+ let path_to_socket = get_temp_socket_file ( ) ;
694
+
695
+ let mut server = HttpServer :: new ( path_to_socket. as_path ( ) ) . unwrap ( ) ;
696
+ server. start_server ( ) . unwrap ( ) ;
697
+
698
+ // Test one incoming connection.
699
+ let mut socket = UnixStream :: connect ( path_to_socket. as_path ( ) ) . unwrap ( ) ;
700
+ assert ! ( server. requests( ) . unwrap( ) . is_empty( ) ) ;
701
+
702
+ socket
703
+ . write_all (
704
+ b"PATCH /machine-config HTTP/1.1\r \n \
705
+ Content-Length: 51201\r \n \
706
+ Content-Type: application/json\r \n \r \n aaaaa",
707
+ )
708
+ . unwrap ( ) ;
709
+ assert ! ( server. requests( ) . unwrap( ) . is_empty( ) ) ;
710
+ assert ! ( server. requests( ) . unwrap( ) . is_empty( ) ) ;
711
+ let mut buf: [ u8 ; 265 ] = [ 0 ; 265 ] ;
712
+ assert ! ( socket. read( & mut buf[ ..] ) . unwrap( ) > 0 ) ;
713
+ let error_message = b"HTTP/1.1 400 \r \n \
714
+ Server: Firecracker API\r \n \
715
+ Connection: keep-alive\r \n \
716
+ Content-Type: application/json\r \n \
717
+ Content-Length: 149\r \n \r \n { \" error\" : \" \
718
+ Request payload with size 51201 is larger than \
719
+ the limit of 51200 allowed by server.\n All \
720
+ previous unanswered requests will be dropped.";
721
+ assert_eq ! ( & buf[ ..] , & error_message[ ..] ) ;
722
+ }
723
+
724
+ #[ test]
725
+ fn test_set_payload_size ( ) {
726
+ let path_to_socket = get_temp_socket_file ( ) ;
727
+
728
+ let mut server = HttpServer :: new ( path_to_socket. as_path ( ) ) . unwrap ( ) ;
729
+ server. start_server ( ) . unwrap ( ) ;
730
+ server. set_payload_max_size ( 4 ) ;
731
+
732
+ // Test one incoming connection.
733
+ let mut socket = UnixStream :: connect ( path_to_socket. as_path ( ) ) . unwrap ( ) ;
734
+ assert ! ( server. requests( ) . unwrap( ) . is_empty( ) ) ;
735
+
736
+ socket
737
+ . write_all (
738
+ b"PATCH /machine-config HTTP/1.1\r \n \
739
+ Content-Length: 5\r \n \
740
+ Content-Type: application/json\r \n \r \n aaaaa",
741
+ )
742
+ . unwrap ( ) ;
743
+ assert ! ( server. requests( ) . unwrap( ) . is_empty( ) ) ;
744
+ assert ! ( server. requests( ) . unwrap( ) . is_empty( ) ) ;
745
+ let mut buf: [ u8 ; 260 ] = [ 0 ; 260 ] ;
746
+ assert ! ( socket. read( & mut buf[ ..] ) . unwrap( ) > 0 ) ;
747
+ let error_message = b"HTTP/1.1 400 \r \n \
748
+ Server: Firecracker API\r \n \
749
+ Connection: keep-alive\r \n \
750
+ Content-Type: application/json\r \n \
751
+ Content-Length: 141\r \n \r \n { \" error\" : \" \
752
+ Request payload with size 5 is larger than the \
753
+ limit of 4 allowed by server.\n All previous \
754
+ unanswered requests will be dropped.\" }";
755
+ assert_eq ! ( & buf[ ..] , & error_message[ ..] ) ;
756
+ }
757
+
679
758
#[ test]
680
759
fn test_wait_one_fd_connection ( ) {
681
760
use std:: os:: unix:: io:: IntoRawFd ;
0 commit comments