@@ -21,6 +21,8 @@ static SERVER_FULL_ERROR_MESSAGE: &[u8] = b"HTTP/1.1 503\r\n\
2121 Connection: close\r \n \
2222 Content-Length: 40\r \n \r \n { \" error\" : \" Too many open connections\" }";
2323const MAX_CONNECTIONS : usize = 10 ;
24+ /// Payload max size
25+ pub ( crate ) const MAX_PAYLOAD_SIZE : usize = 51200 ;
2426
2527type Result < T > = std:: result:: Result < T , ServerError > ;
2628
@@ -259,6 +261,8 @@ pub struct HttpServer {
259261 /// We use the file descriptor of the stream as the key for mapping
260262 /// connections because the 1-to-1 relation is guaranteed by the OS.
261263 connections : HashMap < RawFd , ClientConnection < UnixStream > > ,
264+ /// Payload max size
265+ payload_max_size : usize ,
262266}
263267
264268impl HttpServer {
@@ -275,6 +279,7 @@ impl HttpServer {
275279 socket,
276280 epoll,
277281 connections : HashMap :: new ( ) ,
282+ payload_max_size : MAX_PAYLOAD_SIZE ,
278283 } )
279284 }
280285
@@ -295,9 +300,16 @@ impl HttpServer {
295300 socket,
296301 epoll,
297302 connections : HashMap :: new ( ) ,
303+ payload_max_size : MAX_PAYLOAD_SIZE ,
298304 } )
299305 }
300306
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+
301313 /// Starts the HTTP Server.
302314 pub fn start_server ( & mut self ) -> Result < ( ) > {
303315 // Add the socket on which we listen for new connections to the
@@ -573,12 +585,12 @@ impl HttpServer {
573585 } )
574586 . and_then ( |stream| {
575587 // 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 ) ;
577592 // 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) ) ;
582594 Ok ( ( ) )
583595 } )
584596 }
@@ -676,6 +688,73 @@ mod tests {
676688 assert ! ( socket. read( & mut buf[ ..] ) . unwrap( ) > 0 ) ;
677689 }
678690
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+
679758 #[ test]
680759 fn test_wait_one_fd_connection ( ) {
681760 use std:: os:: unix:: io:: IntoRawFd ;
0 commit comments