Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use mime_multipart::{read_multipart_body, Node, Part};
{{/apiUsesMultipartRelated}}
{{#apiUsesMultipartFormData}}
use multipart::server::Multipart;
use multipart::server::save::SaveResult;
use multipart::server::save::{PartialReason, SaveResult};
{{/apiUsesMultipartFormData}}

#[allow(unused_imports)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ pub struct MakeService<T, C> where
C: Has<XSpanIdString> {{#hasAuthMethods}}+ Has<Option<Authorization>>{{/hasAuthMethods}} + Send + Sync + 'static
{
api_impl: T,
{{#apiUsesMultipartFormData}}
multipart_form_size_limit: Option<u64>,
{{/apiUsesMultipartFormData}}
marker: PhantomData<C>,
}

Expand All @@ -14,11 +17,25 @@ impl<T, C> MakeService<T, C> where
pub fn new(api_impl: T) -> Self {
MakeService {
api_impl,
{{#apiUsesMultipartFormData}}
multipart_form_size_limit: Some(8 * 1024 * 1024),
{{/apiUsesMultipartFormData}}
marker: PhantomData
}
}
}
{{#apiUsesMultipartFormData}}

/// Configure size limit when inspecting a multipart/form body.
///
/// Default is 8 MiB.
///
/// Set to None for no size limit, which presents a Denial of Service attack risk.
pub fn multipart_form_size_limit(mut self, multipart_form_size_limit: Option<u64>) -> Self {
self.multipart_form_size_limit = multipart_form_size_limit;
self
}
{{/apiUsesMultipartFormData}}
}

impl<T, C, Target> hyper::service::Service<Target> for MakeService<T, C> where
T: Api<C> + Clone + Send + 'static,
Expand All @@ -33,8 +50,11 @@ impl<T, C, Target> hyper::service::Service<Target> for MakeService<T, C> where
}

fn call(&mut self, target: Target) -> Self::Future {
future::ok(Service::new(
self.api_impl.clone(),
))
let service = Service::new(self.api_impl.clone()){{^apiUsesMultipartFormData}};{{/apiUsesMultipartFormData}}
{{#apiUsesMultipartFormData}}
.multipart_form_size_limit(self.multipart_form_size_limit);
{{/apiUsesMultipartFormData}}

future::ok(service)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,43 @@
use std::io::Read;

// Read Form Parameters from body
let mut entries = match Multipart::with_body(&body.to_vec()[..], boundary).save().temp() {
let mut entries = match Multipart::with_body(&body.to_vec()[..], boundary)
.save()
.size_limit(multipart_form_size_limit)
.temp()
{
SaveResult::Full(entries) => {
entries
},
_ => {
SaveResult::Partial(_, PartialReason::CountLimit) => {
return Ok(Response::builder()
.status(StatusCode::BAD_REQUEST)
.body(Body::from("Unable to process all message parts".to_string()))
.expect("Unable to create Bad Request response due to failure to process all message"))
.body(Body::from("Unable to process message part due to excessive parts".to_string()))
.expect("Unable to create Bad Request response due to excessive parts"))
},
SaveResult::Partial(_, PartialReason::SizeLimit) => {
return Ok(Response::builder()
.status(StatusCode::BAD_REQUEST)
.body(Body::from("Unable to process message part due to excessive data".to_string()))
.expect("Unable to create Bad Request response due to excessive data"))
},
SaveResult::Partial(_, PartialReason::Utf8Error(_)) => {
return Ok(Response::builder()
.status(StatusCode::BAD_REQUEST)
.body(Body::from("Unable to process message part due to invalid data".to_string()))
.expect("Unable to create Bad Request response due to invalid data"))
},
SaveResult::Partial(_, PartialReason::IoError(_)) => {
return Ok(Response::builder()
.status(StatusCode::INTERNAL_SERVER_ERROR)
.body(Body::from("Failed to process message part due an internal error".to_string()))
.expect("Unable to create Internal Server Error response due to an internal errror"))
},
SaveResult::Error(e) => {
return Ok(Response::builder()
.status(StatusCode::INTERNAL_SERVER_ERROR)
.body(Body::from("Failed to process all message parts due to an internal error".to_string()))
.expect("Unable to create Internal Server Error response due to an internal error"))
},
};
{{#formParams}}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
_ => Ok(Response::builder().status(StatusCode::NOT_FOUND)
.body(Body::empty())
.expect("Unable to create Not Found response"))
_ => Ok(Response::builder().status(StatusCode::NOT_FOUND)
.body(Body::empty())
.expect("Unable to create Not Found response"))
}
}
} Box::pin(run(self.api_impl.clone(), req)) }
Box::pin(run(
self.api_impl.clone(),
req,
{{#apiUsesMultipartFormData}}
self.multipart_form_size_limit,
{{/apiUsesMultipartFormData}}
))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ pub struct Service<T, C> where
C: Has<XSpanIdString> {{#hasAuthMethods}}+ Has<Option<Authorization>>{{/hasAuthMethods}} + Send + Sync + 'static
{
api_impl: T,
{{#apiUsesMultipart}}
multipart_form_size_limit: Option<u64>,
{{/apiUsesMultipart}}
marker: PhantomData<C>,
}

Expand All @@ -21,9 +24,24 @@ impl<T, C> Service<T, C> where
pub fn new(api_impl: T) -> Self {
Service {
api_impl,
{{#apiUsesMultipart}}
multipart_form_size_limit: Some(8 * 1024 * 1024),
{{/apiUsesMultipart}}
marker: PhantomData
}
}
{{#apiUsesMultipart}}

/// Configure size limit when extracting a multipart/form body.
///
/// Default is 8 MiB.
///
/// Set to None for no size limit, which presents a Denial of Service attack risk.
pub fn multipart_form_size_limit(mut self, multipart_form_size_limit: Option<u64>) -> Self {
self.multipart_form_size_limit = multipart_form_size_limit;
self
}
{{/apiUsesMultipart}}
}

impl<T, C> Clone for Service<T, C> where
Expand All @@ -33,6 +51,9 @@ impl<T, C> Clone for Service<T, C> where
fn clone(&self) -> Self {
Service {
api_impl: self.api_impl.clone(),
{{#apiUsesMultipart}}
multipart_form_size_limit: Some(8 * 1024 * 1024),
{{/apiUsesMultipart}}
marker: self.marker,
}
}
Expand All @@ -50,17 +71,24 @@ impl<T, C> hyper::service::Service<(Request<Body>, C)> for Service<T, C> where
self.api_impl.poll_ready(cx)
}

fn call(&mut self, req: (Request<Body>, C)) -> Self::Future { async fn run<T, C>(mut api_impl: T, req: (Request<Body>, C)) -> Result<Response<Body>, crate::ServiceError> where
T: Api<C> + Clone + Send + 'static,
C: Has<XSpanIdString> {{#hasAuthMethods}}+ Has<Option<Authorization>>{{/hasAuthMethods}} + Send + Sync + 'static
{
let (request, context) = req;
let (parts, body) = request.into_parts();
let (method, uri, headers) = (parts.method, parts.uri, parts.headers);
let path = paths::GLOBAL_REGEX_SET.matches(uri.path());
fn call(&mut self, req: (Request<Body>, C)) -> Self::Future {
async fn run<T, C>(
mut api_impl: T,
req: (Request<Body>, C),
{{#apiUsesMultipartFormData}}
multipart_form_size_limit: Option<u64>,
{{/apiUsesMultipartFormData}}
) -> Result<Response<Body>, crate::ServiceError> where
T: Api<C> + Clone + Send + 'static,
C: Has<XSpanIdString> {{#hasAuthMethods}}+ Has<Option<Authorization>>{{/hasAuthMethods}} + Send + Sync + 'static
{
let (request, context) = req;
let (parts, body) = request.into_parts();
let (method, uri, headers) = (parts.method, parts.uri, parts.headers);
let path = paths::GLOBAL_REGEX_SET.matches(uri.path());

{{!
This match statement is duplicated below in `parse_operation_id()`.
Please update both places if changing how this code is autogenerated.
}}
match method {
{{!
This match statement is duplicated below in `parse_operation_id()`.
Please update both places if changing how this code is autogenerated.
}}
match method {
Loading