1- use http_body_util:: { BodyExt , Full } ;
1+ use http_body_util:: { BodyExt , Full , Limited } ;
22use hyper:: body:: { Bytes , Incoming } ;
33use hyper:: service:: Service ;
44use hyper:: { Request , Response , StatusCode } ;
@@ -22,15 +22,44 @@ use log::{debug, trace};
2222
2323use crate :: util:: KeyValueVecKeyPrinter ;
2424
25+ const MAXIMUM_REQUEST_BODY_SIZE : usize = 1024 * 1024 * 1024 ;
26+
27+ #[ derive( Clone , Copy ) ]
28+ pub ( crate ) struct VssServiceConfig {
29+ maximum_request_body_size : usize ,
30+ }
31+
32+ impl VssServiceConfig {
33+ pub fn new ( maximum_request_body_size : usize ) -> Result < Self , String > {
34+ if maximum_request_body_size > MAXIMUM_REQUEST_BODY_SIZE {
35+ return Err ( format ! (
36+ "Maximum request body size {} exceeds maximum {}" ,
37+ maximum_request_body_size, MAXIMUM_REQUEST_BODY_SIZE
38+ ) ) ;
39+ }
40+
41+ Ok ( Self { maximum_request_body_size } )
42+ }
43+ }
44+
45+ impl Default for VssServiceConfig {
46+ fn default ( ) -> Self {
47+ Self { maximum_request_body_size : MAXIMUM_REQUEST_BODY_SIZE }
48+ }
49+ }
50+
2551#[ derive( Clone ) ]
2652pub struct VssService {
2753 store : Arc < dyn KvStore > ,
2854 authorizer : Arc < dyn Authorizer > ,
55+ config : VssServiceConfig ,
2956}
3057
3158impl VssService {
32- pub ( crate ) fn new ( store : Arc < dyn KvStore > , authorizer : Arc < dyn Authorizer > ) -> Self {
33- Self { store, authorizer }
59+ pub ( crate ) fn new (
60+ store : Arc < dyn KvStore > , authorizer : Arc < dyn Authorizer > , config : VssServiceConfig ,
61+ ) -> Self {
62+ Self { store, authorizer, config }
3463 }
3564}
3665
@@ -45,22 +74,51 @@ impl Service<Request<Incoming>> for VssService {
4574 let store = Arc :: clone ( & self . store ) ;
4675 let authorizer = Arc :: clone ( & self . authorizer ) ;
4776 let path = req. uri ( ) . path ( ) . to_owned ( ) ;
77+ let maximum_request_body_size = self . config . maximum_request_body_size ;
4878
4979 Box :: pin ( async move {
5080 let prefix_stripped_path = path. strip_prefix ( BASE_PATH_PREFIX ) . unwrap_or_default ( ) ;
5181
5282 match prefix_stripped_path {
5383 "/getObject" => {
54- handle_request ( store, authorizer, req, handle_get_object_request) . await
84+ handle_request (
85+ store,
86+ authorizer,
87+ req,
88+ maximum_request_body_size,
89+ handle_get_object_request,
90+ )
91+ . await
5592 } ,
5693 "/putObjects" => {
57- handle_request ( store, authorizer, req, handle_put_object_request) . await
94+ handle_request (
95+ store,
96+ authorizer,
97+ req,
98+ maximum_request_body_size,
99+ handle_put_object_request,
100+ )
101+ . await
58102 } ,
59103 "/deleteObject" => {
60- handle_request ( store, authorizer, req, handle_delete_object_request) . await
104+ handle_request (
105+ store,
106+ authorizer,
107+ req,
108+ maximum_request_body_size,
109+ handle_delete_object_request,
110+ )
111+ . await
61112 } ,
62113 "/listKeyVersions" => {
63- handle_request ( store, authorizer, req, handle_list_object_request) . await
114+ handle_request (
115+ store,
116+ authorizer,
117+ req,
118+ maximum_request_body_size,
119+ handle_list_object_request,
120+ )
121+ . await
64122 } ,
65123 _ => {
66124 let error_msg = "Invalid request path." . as_bytes ( ) ;
@@ -140,7 +198,7 @@ async fn handle_request<
140198 Fut : Future < Output = Result < R , VssError > > + Send ,
141199> (
142200 store : Arc < dyn KvStore > , authorizer : Arc < dyn Authorizer > , request : Request < Incoming > ,
143- handler : F ,
201+ maximum_request_body_size : usize , handler : F ,
144202) -> Result < <VssService as Service < Request < Incoming > > >:: Response , hyper:: Error > {
145203 let ( parts, body) = request. into_parts ( ) ;
146204 let headers_map = parts
@@ -155,8 +213,18 @@ async fn handle_request<
155213 Ok ( auth_response) => auth_response. user_token ,
156214 Err ( e) => return Ok ( build_error_response ( e) ) ,
157215 } ;
158- // TODO: we should bound the amount of data we read to avoid allocating too much memory.
159- let bytes = body. collect ( ) . await ?. to_bytes ( ) ;
216+
217+ let limited_body = Limited :: new ( body, maximum_request_body_size) ;
218+ let bytes = match limited_body. collect ( ) . await {
219+ Ok ( body) => body. to_bytes ( ) ,
220+ Err ( _) => {
221+ return Ok ( Response :: builder ( )
222+ . status ( StatusCode :: PAYLOAD_TOO_LARGE )
223+ . body ( Full :: new ( Bytes :: from ( "Request body too large" ) ) )
224+ // unwrap safety: body only errors when previous chained calls failed.
225+ . unwrap ( ) ) ;
226+ } ,
227+ } ;
160228 match T :: decode ( bytes) {
161229 Ok ( request) => match handler ( store. clone ( ) , user_token, request) . await {
162230 Ok ( response) => Ok ( Response :: builder ( )
0 commit comments