Repository: rusoto/rusoto (language: rust)

Issue:
Content-Type of rusoto_sagemaker_runtime::InvokeEndpointInput
First of all, thanks for the great job!

I started using rusoto recently and everything is going smooth so far.
However, I'm a bit confused of how `InvokeEndpointInput.content_type` field influences an invocation.

That's how I build the input instance:
```rust
InvokeEndpointInput {
    accept: Some("application/json".to_owned()),
    body: json.to_string().as_bytes().to_owned(),
    content_type: Some("application/json".to_owned()), // <-- That's it
    endpoint_name: self.endpoint.clone(),
}
```
That's what I see in logs:
```
-- ship --
 2019-01-04 18:54:51 DEBUG rusoto_core::request              > content-type:"application/x-amz-json-1.1"
 2019-01-04 18:54:51 DEBUG rusoto_core::request              > content-type:"application/json"
-- snip --
```

According to [this RFC](https://tools.ietf.org/html/rfc7230#section-3.2.2): 
> A sender MUST NOT generate multiple header fields with the same field
   name in a message unless either the entire field value for that
   header field is defined as a comma-separated list [i.e., #(values)]
   or the header field is a well-known exception (as noted below).
>
> A recipient MAY combine multiple header fields with the same field
   name into one "field-name: field-value" pair, without changing the
   semantics of the message, by appending each subsequent field value to
   the combined field value in order, separated by a comma.

So, the actual behavior looks like a bug.


Discussion / hints:

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0ca71c41c8f..d60ae11b1a9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,8 +1,8 @@
 # Rusoto changes
 
 ## [Unreleased]
+- Fix duplicated Content-Type header in SageMaker Runtime
 - Switch from `try!` to `?` operator
-
 - Remove unneeded muts in Glacier codegen
 - Add Eu-North-1 Region
 - Fix bug in SNS publish message action
diff --git a/rusoto/services/sagemaker-runtime/src/generated.rs b/rusoto/services/sagemaker-runtime/src/generated.rs
index a5d81a2eb68..9bf289621a4 100644
--- a/rusoto/services/sagemaker-runtime/src/generated.rs
+++ b/rusoto/services/sagemaker-runtime/src/generated.rs
@@ -226,7 +226,9 @@ impl SageMakerRuntime for SageMakerRuntimeClient {
         );
 
         let mut request = SignedRequest::new("POST", "sagemaker", &self.region, &request_uri);
-        request.set_content_type("application/x-amz-json-1.1".to_owned());
+        if input.content_type.is_none() {
+            request.set_content_type("application/x-amz-json-1.1".to_owned());
+        }
 
         request.set_endpoint_prefix("runtime.sagemaker".to_string());
         let encoded = Some(input.body.to_owned());
diff --git a/service_crategen/src/commands/generate/codegen/rest_json.rs b/service_crategen/src/commands/generate/codegen/rest_json.rs
index 3ce5fc489cc..18de5e00a43 100644
--- a/service_crategen/src/commands/generate/codegen/rest_json.rs
+++ b/service_crategen/src/commands/generate/codegen/rest_json.rs
@@ -49,7 +49,7 @@ impl GenerateProtocol for RestJsonGenerator {
                     {request_uri_formatter}
 
                     let mut request = SignedRequest::new(\"{http_method}\", \"{endpoint_prefix}\", &self.region, &request_uri);
-                    request.set_content_type(\"application/x-amz-json-1.1\".to_owned());
+                    {default_headers}
                     {set_headers}
                     {modify_endpoint_prefix}
                     {load_payload}
@@ -92,6 +92,7 @@ impl GenerateProtocol for RestJsonGenerator {
                 ).unwrap_or_else(|| "".to_string()),
                 load_payload = generate_payload(service, input_shape).unwrap_or_else(|| "".to_string()),
                 load_params = rest_request_generator::generate_params_loading_string(service, operation).unwrap_or_else(|| "".to_string()),
+                default_headers = generate_default_headers(service),
                 set_headers = generate_headers(service).unwrap_or_else(|| "".to_string()),
             )?
         }
@@ -144,6 +145,17 @@ fn generate_headers(service: &Service) -> Option<String> {
     None
 }
 
+// SageMaker Runtime allows to overwrite content-type
+fn generate_default_headers(service: &Service) -> String {
+    if service.full_name() == "Amazon SageMaker Runtime" {
+        return "if input.content_type.is_none() {
+                    request.set_content_type(\"application/x-amz-json-1.1\".to_owned());
+                }"
+                .to_string();
+    }
+    "request.set_content_type(\"application/x-amz-json-1.1\".to_owned());".to_string()
+}
+
 // IoT has an endpoint_prefix and a signing_name that differ
 fn generate_endpoint_modification(service: &Service) -> Option<String> {
     if service.signing_name() == service.endpoint_prefix() {


Test patch: