@@ -121,15 +121,16 @@ impl ExclusiveExtractor for MultipartBody {
121121
122122/// Given an HTTP request, attempt to read the body, parse it according
123123/// to the content type, and deserialize it to an instance of `BodyType`.
124- async fn http_request_load_body < Context : ServerContext , BodyType > (
125- rqctx : & RequestContext < Context > ,
124+ async fn http_request_load_body < BodyType > (
126125 request : hyper:: Request < crate :: Body > ,
126+ request_body_max_bytes : usize ,
127+ expected_body_content_type : & ApiEndpointBodyContentType ,
127128) -> Result < TypedBody < BodyType > , HttpError >
128129where
129130 BodyType : JsonSchema + DeserializeOwned + Send + Sync ,
130131{
131132 let ( parts, body) = request. into_parts ( ) ;
132- let body = StreamingBody :: new ( body, rqctx . request_body_max_bytes ( ) )
133+ let body = StreamingBody :: new ( body, request_body_max_bytes)
133134 . into_bytes_mut ( )
134135 . await ?;
135136
@@ -150,14 +151,19 @@ where
150151 . unwrap_or ( Ok ( CONTENT_TYPE_JSON ) ) ?;
151152 let end = content_type. find ( ';' ) . unwrap_or_else ( || content_type. len ( ) ) ;
152153 let mime_type = content_type[ ..end] . trim_end ( ) . to_lowercase ( ) ;
153- let body_content_type =
154- ApiEndpointBodyContentType :: from_mime_type ( & mime_type)
155- . map_err ( |e| HttpError :: for_bad_request ( None , e) ) ?;
156- let expected_content_type = rqctx. endpoint . body_content_type . clone ( ) ;
154+ let body_content_type = ApiEndpointBodyContentType :: from_mime_type (
155+ & mime_type,
156+ )
157+ . map_err ( |e| {
158+ HttpError :: for_bad_request (
159+ None ,
160+ format ! ( "unsupported content-type: {}" , e) ,
161+ )
162+ } ) ?;
157163
158164 use ApiEndpointBodyContentType :: * ;
159165
160- let content = match ( expected_content_type , body_content_type) {
166+ let content = match ( expected_body_content_type , body_content_type) {
161167 ( Json , Json ) => {
162168 let jd = & mut serde_json:: Deserializer :: from_slice ( & body) ;
163169 serde_path_to_error:: deserialize ( jd) . map_err ( |e| {
@@ -186,7 +192,7 @@ where
186192 expected. mime_type( ) ,
187193 requested. mime_type( )
188194 ) ,
189- ) )
195+ ) ) ;
190196 }
191197 } ;
192198 Ok ( TypedBody { inner : content } )
@@ -207,7 +213,12 @@ where
207213 rqctx : & RequestContext < Context > ,
208214 request : hyper:: Request < crate :: Body > ,
209215 ) -> Result < TypedBody < BodyType > , HttpError > {
210- http_request_load_body ( rqctx, request) . await
216+ http_request_load_body (
217+ request,
218+ rqctx. request_body_max_bytes ( ) ,
219+ & rqctx. endpoint . body_content_type ,
220+ )
221+ . await
211222 }
212223
213224 fn metadata ( content_type : ApiEndpointBodyContentType ) -> ExtractorMetadata {
@@ -457,3 +468,32 @@ fn untyped_metadata() -> ExtractorMetadata {
457468 extension_mode : ExtensionMode :: None ,
458469 }
459470}
471+
472+ #[ cfg( test) ]
473+ mod tests {
474+ use schemars:: JsonSchema ;
475+ use serde:: Deserialize ;
476+
477+ use crate :: extractor:: body:: http_request_load_body;
478+
479+ #[ tokio:: test]
480+ async fn test_content_plus_json ( ) {
481+ #[ derive( Deserialize , JsonSchema ) ]
482+ struct TheRealScimShady { }
483+
484+ let body = "{}" ;
485+ let request = hyper:: Request :: builder ( )
486+ . header ( http:: header:: CONTENT_TYPE , "application/scim+json" )
487+ . body ( crate :: Body :: with_content ( body) )
488+ . unwrap ( ) ;
489+
490+ let r = http_request_load_body :: < TheRealScimShady > (
491+ request,
492+ 9000 ,
493+ & crate :: ApiEndpointBodyContentType :: Json ,
494+ )
495+ . await ;
496+
497+ assert ! ( r. is_ok( ) )
498+ }
499+ }
0 commit comments