forked from loafle/openapi-generator-original
[Rust Server] Support multiple identical MIME types (#5562)
* Support multiple identical MIME types in a multipart request * Add test for multiple identical MIME types * Update samples
This commit is contained in:
committed by
GitHub
parent
058d1d2aa0
commit
b0520a346d
@@ -368,7 +368,7 @@
|
||||
match content_type.as_ref().map(|x| x.as_str()) {
|
||||
{{#formParams}}
|
||||
{{^isBinary}}
|
||||
Some("{{{contentType}}}") => {
|
||||
Some("{{{contentType}}}") if param_{{{paramName}}}.is_none() => {
|
||||
// Extract JSON part.
|
||||
let deserializer = &mut serde_json::Deserializer::from_slice(part.body.as_slice());
|
||||
let json_data: {{dataType}} = match serde_ignored::deserialize(deserializer, |path| {
|
||||
@@ -386,13 +386,13 @@
|
||||
},
|
||||
{{/isBinary}}
|
||||
{{#isBinary}}
|
||||
Some("{{{contentType}}}") => {
|
||||
Some("{{{contentType}}}") if param_{{{paramName}}}.is_none() => {
|
||||
param_{{{paramName}}}.get_or_insert(swagger::ByteArray(part.body));
|
||||
},
|
||||
{{/isBinary}}
|
||||
{{/formParams}}
|
||||
Some(content_type) => {
|
||||
warn!("Ignoring unknown content type: {}", content_type);
|
||||
warn!("Ignoring unexpected content type: {}", content_type);
|
||||
unused_elements.push(content_type.to_string());
|
||||
},
|
||||
None => {
|
||||
|
||||
@@ -50,6 +50,29 @@ paths:
|
||||
responses:
|
||||
'201':
|
||||
description: 'OK'
|
||||
/multiple-identical-mime-types:
|
||||
post:
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
multipart/related:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
binary1:
|
||||
type: string
|
||||
format: binary
|
||||
binary2:
|
||||
type: string
|
||||
format: binary
|
||||
encoding:
|
||||
binary1:
|
||||
contentType: application/octet-stream
|
||||
binary2:
|
||||
contentType: application/octet-stream
|
||||
responses:
|
||||
200:
|
||||
description: OK
|
||||
components:
|
||||
schemas:
|
||||
multipart_request:
|
||||
|
||||
@@ -63,6 +63,7 @@ To run a client, follow one of the following simple steps:
|
||||
```
|
||||
cargo run --example client MultipartRelatedRequestPost
|
||||
cargo run --example client MultipartRequestPost
|
||||
cargo run --example client MultipleIdenticalMimeTypesPost
|
||||
```
|
||||
|
||||
### HTTPS
|
||||
@@ -98,10 +99,12 @@ Method | HTTP request | Description
|
||||
------------- | ------------- | -------------
|
||||
[****](docs/default_api.md#) | **POST** /multipart_related_request |
|
||||
[****](docs/default_api.md#) | **POST** /multipart_request |
|
||||
[****](docs/default_api.md#) | **POST** /multiple-identical-mime-types |
|
||||
|
||||
|
||||
## Documentation For Models
|
||||
|
||||
- [InlineObject](docs/InlineObject.md)
|
||||
- [MultipartRelatedRequest](docs/MultipartRelatedRequest.md)
|
||||
- [MultipartRequest](docs/MultipartRequest.md)
|
||||
- [MultipartRequestObjectField](docs/MultipartRequestObjectField.md)
|
||||
|
||||
@@ -50,7 +50,40 @@ paths:
|
||||
responses:
|
||||
"201":
|
||||
description: OK
|
||||
/multiple-identical-mime-types:
|
||||
post:
|
||||
requestBody:
|
||||
$ref: '#/components/requestBodies/inline_object'
|
||||
content:
|
||||
multipart/related:
|
||||
encoding:
|
||||
binary1:
|
||||
contentType: application/octet-stream
|
||||
style: form
|
||||
binary2:
|
||||
contentType: application/octet-stream
|
||||
style: form
|
||||
schema:
|
||||
properties:
|
||||
binary1:
|
||||
format: binary
|
||||
type: string
|
||||
binary2:
|
||||
format: binary
|
||||
type: string
|
||||
type: object
|
||||
required: true
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
components:
|
||||
requestBodies:
|
||||
inline_object:
|
||||
content:
|
||||
multipart/related:
|
||||
schema:
|
||||
$ref: '#/components/schemas/inline_object'
|
||||
required: true
|
||||
schemas:
|
||||
multipart_request:
|
||||
properties:
|
||||
@@ -80,6 +113,15 @@ components:
|
||||
required:
|
||||
- required_binary_field
|
||||
type: object
|
||||
inline_object:
|
||||
properties:
|
||||
binary1:
|
||||
format: binary
|
||||
type: string
|
||||
binary2:
|
||||
format: binary
|
||||
type: string
|
||||
type: object
|
||||
multipart_request_object_field:
|
||||
properties:
|
||||
field_a:
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
# InlineObject
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**binary1** | [***swagger::ByteArray**](file.md) | | [optional] [default to None]
|
||||
**binary2** | [***swagger::ByteArray**](file.md) | | [optional] [default to None]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ Method | HTTP request | Description
|
||||
------------- | ------------- | -------------
|
||||
****](default_api.md#) | **POST** /multipart_related_request |
|
||||
****](default_api.md#) | **POST** /multipart_request |
|
||||
****](default_api.md#) | **POST** /multiple-identical-mime-types |
|
||||
|
||||
|
||||
# ****
|
||||
@@ -80,3 +81,36 @@ No authorization required
|
||||
|
||||
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
|
||||
|
||||
# ****
|
||||
> (optional)
|
||||
|
||||
|
||||
### Required Parameters
|
||||
|
||||
Name | Type | Description | Notes
|
||||
------------- | ------------- | ------------- | -------------
|
||||
**optional** | **map[string]interface{}** | optional parameters | nil if no parameters
|
||||
|
||||
### Optional Parameters
|
||||
Optional parameters are passed through a map[string]interface{}.
|
||||
|
||||
Name | Type | Description | Notes
|
||||
------------- | ------------- | ------------- | -------------
|
||||
**binary1** | **swagger::ByteArray**| |
|
||||
**binary2** | **swagger::ByteArray**| |
|
||||
|
||||
### Return type
|
||||
|
||||
(empty response body)
|
||||
|
||||
### Authorization
|
||||
|
||||
No authorization required
|
||||
|
||||
### HTTP request headers
|
||||
|
||||
- **Content-Type**: multipart/related
|
||||
- **Accept**: Not defined
|
||||
|
||||
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -15,7 +15,8 @@ use futures::{Future, future, Stream, stream};
|
||||
use multipart_v3::{Api, ApiNoContext, Client, ContextWrapperExt,
|
||||
ApiError,
|
||||
MultipartRelatedRequestPostResponse,
|
||||
MultipartRequestPostResponse
|
||||
MultipartRequestPostResponse,
|
||||
MultipleIdenticalMimeTypesPostResponse
|
||||
};
|
||||
use clap::{App, Arg};
|
||||
use swagger::{ContextBuilder, EmptyContext, XSpanIdString, Has, Push, AuthData};
|
||||
@@ -29,6 +30,7 @@ fn main() {
|
||||
.possible_values(&[
|
||||
"MultipartRelatedRequestPost",
|
||||
"MultipartRequestPost",
|
||||
"MultipleIdenticalMimeTypesPost",
|
||||
])
|
||||
.required(true)
|
||||
.index(1))
|
||||
@@ -89,6 +91,13 @@ fn main() {
|
||||
));
|
||||
info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &Has<XSpanIdString>).get().clone());
|
||||
},
|
||||
Some("MultipleIdenticalMimeTypesPost") => {
|
||||
let result = rt.block_on(client.multiple_identical_mime_types_post(
|
||||
Some(swagger::ByteArray(Vec::from("BINARY_DATA_HERE"))),
|
||||
Some(swagger::ByteArray(Vec::from("BINARY_DATA_HERE")))
|
||||
));
|
||||
info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &Has<XSpanIdString>).get().clone());
|
||||
},
|
||||
_ => {
|
||||
panic!("Invalid operation provided")
|
||||
}
|
||||
|
||||
@@ -108,6 +108,7 @@ use multipart_v3::{
|
||||
ApiError,
|
||||
MultipartRelatedRequestPostResponse,
|
||||
MultipartRequestPostResponse,
|
||||
MultipleIdenticalMimeTypesPostResponse,
|
||||
};
|
||||
use multipart_v3::server::MakeService;
|
||||
|
||||
@@ -137,4 +138,15 @@ impl<C> Api<C> for Server<C> where C: Has<XSpanIdString>{
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
}
|
||||
|
||||
fn multiple_identical_mime_types_post(
|
||||
&self,
|
||||
binary1: Option<swagger::ByteArray>,
|
||||
binary2: Option<swagger::ByteArray>,
|
||||
context: &C) -> Box<Future<Item=MultipleIdenticalMimeTypesPostResponse, Error=ApiError> + Send>
|
||||
{
|
||||
let context = context.clone();
|
||||
info!("multiple_identical_mime_types_post({:?}, {:?}) - X-Span-ID: {:?}", binary1, binary2, context.get().0.clone());
|
||||
Box::new(future::err("Generic failure".into()))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -43,7 +43,8 @@ define_encode_set! {
|
||||
|
||||
use {Api,
|
||||
MultipartRelatedRequestPostResponse,
|
||||
MultipartRequestPostResponse
|
||||
MultipartRequestPostResponse,
|
||||
MultipleIdenticalMimeTypesPostResponse
|
||||
};
|
||||
|
||||
/// Convert input into a base path, e.g. "http://example:123". Also checks the scheme as it goes.
|
||||
@@ -554,4 +555,133 @@ impl<C, F> Api<C> for Client<F> where
|
||||
}))
|
||||
}
|
||||
|
||||
fn multiple_identical_mime_types_post(
|
||||
&self,
|
||||
param_binary1: Option<swagger::ByteArray>,
|
||||
param_binary2: Option<swagger::ByteArray>,
|
||||
context: &C) -> Box<dyn Future<Item=MultipleIdenticalMimeTypesPostResponse, Error=ApiError> + Send>
|
||||
{
|
||||
let mut uri = format!(
|
||||
"{}/multiple-identical-mime-types",
|
||||
self.base_path
|
||||
);
|
||||
|
||||
// Query parameters
|
||||
let mut query_string = url::form_urlencoded::Serializer::new("".to_owned());
|
||||
let query_string_str = query_string.finish();
|
||||
if !query_string_str.is_empty() {
|
||||
uri += "?";
|
||||
uri += &query_string_str;
|
||||
}
|
||||
|
||||
let uri = match Uri::from_str(&uri) {
|
||||
Ok(uri) => uri,
|
||||
Err(err) => return Box::new(future::err(ApiError(format!("Unable to build URI: {}", err)))),
|
||||
};
|
||||
|
||||
let mut request = match hyper::Request::builder()
|
||||
.method("POST")
|
||||
.uri(uri)
|
||||
.body(Body::empty()) {
|
||||
Ok(req) => req,
|
||||
Err(e) => return Box::new(future::err(ApiError(format!("Unable to create request: {}", e))))
|
||||
};
|
||||
|
||||
// Construct the Body for a multipart/related request. The mime 0.2.6 library
|
||||
// does not parse quoted-string parameters correctly. The boundary doesn't
|
||||
// need to be a quoted string if it does not contain a '/', hence ensure
|
||||
// no such boundary is used.
|
||||
let mut boundary = generate_boundary();
|
||||
for b in boundary.iter_mut() {
|
||||
if b == &('/' as u8) {
|
||||
*b = '=' as u8;
|
||||
}
|
||||
}
|
||||
|
||||
let mut body_parts = vec![];
|
||||
|
||||
if let Some(binary1) = param_binary1 {
|
||||
let part = Node::Part(Part {
|
||||
headers: {
|
||||
let mut h = Headers::new();
|
||||
h.set(ContentType("application/octet-stream".parse().unwrap()));
|
||||
h.set(ContentId("binary1".parse().unwrap()));
|
||||
h
|
||||
},
|
||||
body: binary1.0,
|
||||
});
|
||||
body_parts.push(part);
|
||||
}
|
||||
|
||||
if let Some(binary2) = param_binary2 {
|
||||
let part = Node::Part(Part {
|
||||
headers: {
|
||||
let mut h = Headers::new();
|
||||
h.set(ContentType("application/octet-stream".parse().unwrap()));
|
||||
h.set(ContentId("binary2".parse().unwrap()));
|
||||
h
|
||||
},
|
||||
body: binary2.0,
|
||||
});
|
||||
body_parts.push(part);
|
||||
}
|
||||
|
||||
// Write the body into a vec.
|
||||
let mut body: Vec<u8> = vec![];
|
||||
write_multipart(&mut body, &boundary, &body_parts)
|
||||
.expect("Failed to write multipart body");
|
||||
|
||||
// Add the message body to the request object.
|
||||
*request.body_mut() = Body::from(body);
|
||||
|
||||
let header = &mimetypes::requests::MULTIPLE_IDENTICAL_MIME_TYPES_POST;
|
||||
request.headers_mut().insert(CONTENT_TYPE,
|
||||
match HeaderValue::from_bytes(
|
||||
&[header.as_bytes(), "; boundary=".as_bytes(), &boundary, "; type=\"application/json\"".as_bytes()].concat()
|
||||
) {
|
||||
Ok(h) => h,
|
||||
Err(e) => return Box::new(future::err(ApiError(format!("Unable to create header: {} - {}", header, e))))
|
||||
});
|
||||
|
||||
let header = HeaderValue::from_str((context as &dyn Has<XSpanIdString>).get().0.clone().to_string().as_str());
|
||||
request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header {
|
||||
Ok(h) => h,
|
||||
Err(e) => return Box::new(future::err(ApiError(format!("Unable to create X-Span ID header value: {}", e))))
|
||||
});
|
||||
|
||||
Box::new(self.client_service.request(request)
|
||||
.map_err(|e| ApiError(format!("No response received: {}", e)))
|
||||
.and_then(|mut response| {
|
||||
match response.status().as_u16() {
|
||||
200 => {
|
||||
let body = response.into_body();
|
||||
Box::new(
|
||||
future::ok(
|
||||
MultipleIdenticalMimeTypesPostResponse::OK
|
||||
)
|
||||
) as Box<dyn Future<Item=_, Error=_> + Send>
|
||||
},
|
||||
code => {
|
||||
let headers = response.headers().clone();
|
||||
Box::new(response.into_body()
|
||||
.take(100)
|
||||
.concat2()
|
||||
.then(move |body|
|
||||
future::err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}",
|
||||
code,
|
||||
headers,
|
||||
match body {
|
||||
Ok(ref body) => match str::from_utf8(body) {
|
||||
Ok(body) => Cow::from(body),
|
||||
Err(e) => Cow::from(format!("<Body was not UTF8: {:?}>", e)),
|
||||
},
|
||||
Err(e) => Cow::from(format!("<Failed to read body: {}>", e)),
|
||||
})))
|
||||
)
|
||||
) as Box<dyn Future<Item=_, Error=_> + Send>
|
||||
}
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -91,6 +91,12 @@ pub enum MultipartRequestPostResponse {
|
||||
OK
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum MultipleIdenticalMimeTypesPostResponse {
|
||||
/// OK
|
||||
OK
|
||||
}
|
||||
|
||||
/// API
|
||||
pub trait Api<C> {
|
||||
fn multipart_related_request_post(
|
||||
@@ -108,6 +114,12 @@ pub trait Api<C> {
|
||||
object_field: Option<models::MultipartRequestObjectField>,
|
||||
context: &C) -> Box<dyn Future<Item=MultipartRequestPostResponse, Error=ApiError> + Send>;
|
||||
|
||||
fn multiple_identical_mime_types_post(
|
||||
&self,
|
||||
binary1: Option<swagger::ByteArray>,
|
||||
binary2: Option<swagger::ByteArray>,
|
||||
context: &C) -> Box<dyn Future<Item=MultipleIdenticalMimeTypesPostResponse, Error=ApiError> + Send>;
|
||||
|
||||
}
|
||||
|
||||
/// API without a `Context`
|
||||
@@ -127,6 +139,12 @@ pub trait ApiNoContext {
|
||||
object_field: Option<models::MultipartRequestObjectField>,
|
||||
) -> Box<dyn Future<Item=MultipartRequestPostResponse, Error=ApiError> + Send>;
|
||||
|
||||
fn multiple_identical_mime_types_post(
|
||||
&self,
|
||||
binary1: Option<swagger::ByteArray>,
|
||||
binary2: Option<swagger::ByteArray>,
|
||||
) -> Box<dyn Future<Item=MultipleIdenticalMimeTypesPostResponse, Error=ApiError> + Send>;
|
||||
|
||||
}
|
||||
|
||||
/// Trait to extend an API to make it easy to bind it to a context.
|
||||
@@ -163,6 +181,15 @@ impl<'a, T: Api<C>, C> ApiNoContext for ContextWrapper<'a, T, C> {
|
||||
self.api().multipart_request_post(string_field, binary_field, optional_string_field, object_field, &self.context())
|
||||
}
|
||||
|
||||
fn multiple_identical_mime_types_post(
|
||||
&self,
|
||||
binary1: Option<swagger::ByteArray>,
|
||||
binary2: Option<swagger::ByteArray>,
|
||||
) -> Box<dyn Future<Item=MultipleIdenticalMimeTypesPostResponse, Error=ApiError> + Send>
|
||||
{
|
||||
self.api().multiple_identical_mime_types_post(binary1, binary2, &self.context())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[cfg(feature = "client")]
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
pub mod responses {
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
pub mod requests {
|
||||
@@ -10,4 +11,7 @@ pub mod requests {
|
||||
pub static MULTIPART_RELATED_REQUEST_POST: &str = "multipart/related";
|
||||
|
||||
|
||||
/// Create &str objects for the request content types for MultipleIdenticalMimeTypesPost
|
||||
pub static MULTIPLE_IDENTICAL_MIME_TYPES_POST: &str = "multipart/related";
|
||||
|
||||
}
|
||||
|
||||
@@ -11,6 +11,107 @@ use std::str::FromStr;
|
||||
use header::IntoHeaderValue;
|
||||
|
||||
|
||||
// Methods for converting between IntoHeaderValue<InlineObject> and HeaderValue
|
||||
|
||||
impl From<IntoHeaderValue<InlineObject>> for HeaderValue {
|
||||
fn from(hdr_value: IntoHeaderValue<InlineObject>) -> Self {
|
||||
HeaderValue::from_str(&hdr_value.to_string()).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<HeaderValue> for IntoHeaderValue<InlineObject> {
|
||||
fn from(hdr_value: HeaderValue) -> Self {
|
||||
IntoHeaderValue(InlineObject::from_str(hdr_value.to_str().unwrap()).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "conversion", derive(LabelledGeneric))]
|
||||
pub struct InlineObject {
|
||||
#[serde(rename = "binary1")]
|
||||
#[serde(skip_serializing_if="Option::is_none")]
|
||||
pub binary1: Option<swagger::ByteArray>,
|
||||
|
||||
#[serde(rename = "binary2")]
|
||||
#[serde(skip_serializing_if="Option::is_none")]
|
||||
pub binary2: Option<swagger::ByteArray>,
|
||||
|
||||
}
|
||||
|
||||
impl InlineObject {
|
||||
pub fn new() -> InlineObject {
|
||||
InlineObject {
|
||||
binary1: None,
|
||||
binary2: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts the InlineObject value to the Query Parameters representation (style=form, explode=false)
|
||||
/// specified in https://swagger.io/docs/specification/serialization/
|
||||
/// Should be implemented in a serde serializer
|
||||
impl ::std::string::ToString for InlineObject {
|
||||
fn to_string(&self) -> String {
|
||||
let mut params: Vec<String> = vec![];
|
||||
// Skipping binary1 in query parameter serialization
|
||||
// Skipping binary1 in query parameter serialization
|
||||
|
||||
// Skipping binary2 in query parameter serialization
|
||||
// Skipping binary2 in query parameter serialization
|
||||
|
||||
params.join(",").to_string()
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts Query Parameters representation (style=form, explode=false) to a InlineObject value
|
||||
/// as specified in https://swagger.io/docs/specification/serialization/
|
||||
/// Should be implemented in a serde deserializer
|
||||
impl ::std::str::FromStr for InlineObject {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
#[derive(Default)]
|
||||
// An intermediate representation of the struct to use for parsing.
|
||||
struct IntermediateRep {
|
||||
pub binary1: Vec<swagger::ByteArray>,
|
||||
pub binary2: Vec<swagger::ByteArray>,
|
||||
}
|
||||
|
||||
let mut intermediate_rep = IntermediateRep::default();
|
||||
|
||||
// Parse into intermediate representation
|
||||
let mut string_iter = s.split(',').into_iter();
|
||||
let mut key_result = string_iter.next();
|
||||
|
||||
while key_result.is_some() {
|
||||
let val = match string_iter.next() {
|
||||
Some(x) => x,
|
||||
None => return Err("Missing value while parsing InlineObject".to_string())
|
||||
};
|
||||
|
||||
if let Some(key) = key_result {
|
||||
match key {
|
||||
"binary1" => return Err("Parsing binary data in this style is not supported in InlineObject".to_string()),
|
||||
"binary2" => return Err("Parsing binary data in this style is not supported in InlineObject".to_string()),
|
||||
_ => return Err("Unexpected key while parsing InlineObject".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
// Get the next key
|
||||
key_result = string_iter.next();
|
||||
}
|
||||
|
||||
// Use the intermediate representation to return the struct
|
||||
Ok(InlineObject {
|
||||
binary1: intermediate_rep.binary1.into_iter().next(),
|
||||
binary2: intermediate_rep.binary2.into_iter().next(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Methods for converting between IntoHeaderValue<MultipartRelatedRequest> and HeaderValue
|
||||
|
||||
impl From<IntoHeaderValue<MultipartRelatedRequest>> for HeaderValue {
|
||||
|
||||
@@ -30,7 +30,8 @@ pub use crate::context;
|
||||
|
||||
use {Api,
|
||||
MultipartRelatedRequestPostResponse,
|
||||
MultipartRequestPostResponse
|
||||
MultipartRequestPostResponse,
|
||||
MultipleIdenticalMimeTypesPostResponse
|
||||
};
|
||||
|
||||
mod paths {
|
||||
@@ -39,12 +40,14 @@ mod paths {
|
||||
lazy_static! {
|
||||
pub static ref GLOBAL_REGEX_SET: regex::RegexSet = regex::RegexSet::new(vec![
|
||||
r"^/multipart_related_request$",
|
||||
r"^/multipart_request$"
|
||||
r"^/multipart_request$",
|
||||
r"^/multiple-identical-mime-types$"
|
||||
])
|
||||
.expect("Unable to create global regex set");
|
||||
}
|
||||
pub static ID_MULTIPART_RELATED_REQUEST: usize = 0;
|
||||
pub static ID_MULTIPART_REQUEST: usize = 1;
|
||||
pub static ID_MULTIPLE_IDENTICAL_MIME_TYPES: usize = 2;
|
||||
}
|
||||
|
||||
pub struct MakeService<T, RC> {
|
||||
@@ -185,7 +188,7 @@ where
|
||||
if let Node::Part(part) = node {
|
||||
let content_type = part.content_type().map(|x| format!("{}",x));
|
||||
match content_type.as_ref().map(|x| x.as_str()) {
|
||||
Some("application/json") => {
|
||||
Some("application/json") if param_object_field.is_none() => {
|
||||
// Extract JSON part.
|
||||
let deserializer = &mut serde_json::Deserializer::from_slice(part.body.as_slice());
|
||||
let json_data: models::MultipartRequestObjectField = match serde_ignored::deserialize(deserializer, |path| {
|
||||
@@ -201,14 +204,14 @@ where
|
||||
// Push JSON part to return object.
|
||||
param_object_field.get_or_insert(json_data);
|
||||
},
|
||||
Some("application/zip") => {
|
||||
Some("application/zip") if param_optional_binary_field.is_none() => {
|
||||
param_optional_binary_field.get_or_insert(swagger::ByteArray(part.body));
|
||||
},
|
||||
Some("image/png") => {
|
||||
Some("image/png") if param_required_binary_field.is_none() => {
|
||||
param_required_binary_field.get_or_insert(swagger::ByteArray(part.body));
|
||||
},
|
||||
Some(content_type) => {
|
||||
warn!("Ignoring unknown content type: {}", content_type);
|
||||
warn!("Ignoring unexpected content type: {}", content_type);
|
||||
unused_elements.push(content_type.to_string());
|
||||
},
|
||||
None => {
|
||||
@@ -435,8 +438,124 @@ where
|
||||
)
|
||||
},
|
||||
|
||||
// MultipleIdenticalMimeTypesPost - POST /multiple-identical-mime-types
|
||||
&hyper::Method::POST if path.matched(paths::ID_MULTIPLE_IDENTICAL_MIME_TYPES) => {
|
||||
// Body parameters (note that non-required body parameters will ignore garbage
|
||||
// values, rather than causing a 400 response). Produce warning header and logs for
|
||||
// any unused fields.
|
||||
Box::new(body.concat2()
|
||||
.then(move |result| -> Self::Future {
|
||||
match result {
|
||||
Ok(body) => {
|
||||
let mut unused_elements: Vec<String> = vec![];
|
||||
|
||||
// Get multipart chunks.
|
||||
|
||||
// Extract the top-level content type header.
|
||||
let content_type_mime = headers
|
||||
.get(CONTENT_TYPE)
|
||||
.ok_or("Missing content-type header".to_string())
|
||||
.and_then(|v| v.to_str().map_err(|e| format!("Couldn't read content-type header value for MultipleIdenticalMimeTypesPost: {}", e)))
|
||||
.and_then(|v| v.parse::<Mime2>().map_err(|_e| format!("Couldn't parse content-type header value for MultipleIdenticalMimeTypesPost")));
|
||||
|
||||
// Insert top-level content type header into a Headers object.
|
||||
let mut multi_part_headers = Headers::new();
|
||||
match content_type_mime {
|
||||
Ok(content_type_mime) => {
|
||||
multi_part_headers.set(ContentType(content_type_mime));
|
||||
},
|
||||
Err(e) => {
|
||||
return Box::new(future::ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(e))
|
||||
.expect("Unable to create Bad Request response due to unable to read content-type header for MultipleIdenticalMimeTypesPost")));
|
||||
}
|
||||
}
|
||||
|
||||
// &*body expresses the body as a byteslice, &mut provides a
|
||||
// mutable reference to that byteslice.
|
||||
let nodes = match read_multipart_body(&mut&*body, &multi_part_headers, false) {
|
||||
Ok(nodes) => nodes,
|
||||
Err(e) => {
|
||||
return Box::new(future::ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(format!("Could not read multipart body for MultipleIdenticalMimeTypesPost: {}", e)))
|
||||
.expect("Unable to create Bad Request response due to unable to read multipart body for MultipleIdenticalMimeTypesPost")));
|
||||
}
|
||||
};
|
||||
|
||||
let mut param_binary1 = None;
|
||||
let mut param_binary2 = None;
|
||||
|
||||
for node in nodes {
|
||||
if let Node::Part(part) = node {
|
||||
let content_type = part.content_type().map(|x| format!("{}",x));
|
||||
match content_type.as_ref().map(|x| x.as_str()) {
|
||||
Some("application/octet-stream") if param_binary1.is_none() => {
|
||||
param_binary1.get_or_insert(swagger::ByteArray(part.body));
|
||||
},
|
||||
Some("application/octet-stream") if param_binary2.is_none() => {
|
||||
param_binary2.get_or_insert(swagger::ByteArray(part.body));
|
||||
},
|
||||
Some(content_type) => {
|
||||
warn!("Ignoring unexpected content type: {}", content_type);
|
||||
unused_elements.push(content_type.to_string());
|
||||
},
|
||||
None => {
|
||||
warn!("Missing content type");
|
||||
},
|
||||
}
|
||||
} else {
|
||||
unimplemented!("No support for handling unexpected parts");
|
||||
// unused_elements.push();
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the required multipart chunks are present.
|
||||
|
||||
Box::new(
|
||||
api_impl.multiple_identical_mime_types_post(
|
||||
param_binary1,
|
||||
param_binary2,
|
||||
&context
|
||||
).then(move |result| {
|
||||
let mut response = Response::new(Body::empty());
|
||||
response.headers_mut().insert(
|
||||
HeaderName::from_static("x-span-id"),
|
||||
HeaderValue::from_str((&context as &dyn Has<XSpanIdString>).get().0.clone().to_string().as_str())
|
||||
.expect("Unable to create X-Span-ID header value"));
|
||||
|
||||
match result {
|
||||
Ok(rsp) => match rsp {
|
||||
MultipleIdenticalMimeTypesPostResponse::OK
|
||||
=> {
|
||||
*response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode");
|
||||
},
|
||||
},
|
||||
Err(_) => {
|
||||
// Application code returned an error. This should not happen, as the implementation should
|
||||
// return a valid response.
|
||||
*response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
|
||||
*response.body_mut() = Body::from("An internal error occurred");
|
||||
},
|
||||
}
|
||||
|
||||
future::ok(response)
|
||||
}
|
||||
))
|
||||
},
|
||||
Err(e) => Box::new(future::ok(Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Body::from(format!("Couldn't read body parameter Default: {}", e)))
|
||||
.expect("Unable to create Bad Request response due to unable to read body parameter Default"))),
|
||||
}
|
||||
})
|
||||
) as Self::Future
|
||||
},
|
||||
|
||||
_ if path.matched(paths::ID_MULTIPART_RELATED_REQUEST) => method_not_allowed(),
|
||||
_ if path.matched(paths::ID_MULTIPART_REQUEST) => method_not_allowed(),
|
||||
_ if path.matched(paths::ID_MULTIPLE_IDENTICAL_MIME_TYPES) => method_not_allowed(),
|
||||
_ => Box::new(future::ok(
|
||||
Response::builder().status(StatusCode::NOT_FOUND)
|
||||
.body(Body::empty())
|
||||
@@ -466,6 +585,8 @@ impl<T> RequestParser<T> for ApiRequestParser {
|
||||
&hyper::Method::POST if path.matched(paths::ID_MULTIPART_RELATED_REQUEST) => Ok("MultipartRelatedRequestPost"),
|
||||
// MultipartRequestPost - POST /multipart_request
|
||||
&hyper::Method::POST if path.matched(paths::ID_MULTIPART_REQUEST) => Ok("MultipartRequestPost"),
|
||||
// MultipleIdenticalMimeTypesPost - POST /multiple-identical-mime-types
|
||||
&hyper::Method::POST if path.matched(paths::ID_MULTIPLE_IDENTICAL_MIME_TYPES) => Ok("MultipleIdenticalMimeTypesPost"),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user