diff --git a/CHANGELOG.next.toml b/CHANGELOG.next.toml
index 3f5cea1331..6fd2ee4a8c 100644
--- a/CHANGELOG.next.toml
+++ b/CHANGELOG.next.toml
@@ -15,3 +15,11 @@ message = "A feature, `aws-lambda`, has been added to generated SDKs to re-expor
references = ["smithy-rs#3643"]
meta = { "breaking" = false, "bug" = true, "tada" = false, "target" = "server" }
author = "drganjoo"
+
+[[smithy-rs]]
+message = """
+Content-Type header validation now ignores parameter portion of media types.
+"""
+references = ["smithy-rs#3471","smithy-rs#3724"]
+meta = { "breaking" = false, "tada" = false, "bug" = true, target = "server" }
+authors = ["djedward"]
diff --git a/codegen-core/common-test-models/rest-xml-extras.smithy b/codegen-core/common-test-models/rest-xml-extras.smithy
new file mode 100644
index 0000000000..5a47976009
--- /dev/null
+++ b/codegen-core/common-test-models/rest-xml-extras.smithy
@@ -0,0 +1,53 @@
+$version: "2.0"
+
+namespace aws.protocoltests.restxml
+
+use aws.api#service
+use aws.protocols#restXml
+use smithy.test#httpRequestTests
+
+/// A REST XML service that sends XML requests and responses.
+@service(sdkId: "Rest Xml Protocol")
+@restXml
+@title("Sample Rest Xml Protocol Service")
+service RestXmlExtras {
+ version: "2024-04-15",
+ operations: [
+ ContentTypeParameters
+ ]
+}
+
+/// The example tests how servers must support requests
+/// containing a `Content-Type` header with parameters.
+@http(uri: "/ContentTypeParameters", method: "PUT")
+operation ContentTypeParameters {
+ input: ContentTypeParametersInput,
+ output: ContentTypeParametersOutput
+}
+
+apply ContentTypeParameters @httpRequestTests([
+ {
+ id: "RestXmlMustSupportParametersInContentType",
+ documentation: "A server should ignore parameters added to the content type",
+ protocol: restXml,
+ method: "PUT",
+ headers: {
+ "Content-Type": "application/xml; charset=utf-8"
+ },
+ uri: "/ContentTypeParameters",
+ body: "5",
+ bodyMediaType: "application/xml",
+ params: {
+ value: 5,
+ },
+ appliesTo: "server"
+ }
+])
+
+@input
+structure ContentTypeParametersInput {
+ value: Integer,
+}
+
+@output
+structure ContentTypeParametersOutput {}
diff --git a/codegen-server-test/build.gradle.kts b/codegen-server-test/build.gradle.kts
index 509b921877..36d942c840 100644
--- a/codegen-server-test/build.gradle.kts
+++ b/codegen-server-test/build.gradle.kts
@@ -100,6 +100,11 @@ val allCodegenTests = "../codegen-core/common-test-models".let { commonModels ->
"pokemon-service-awsjson-server-sdk",
imports = listOf("$commonModels/pokemon-awsjson.smithy", "$commonModels/pokemon-common.smithy"),
),
+ CodegenTest(
+ "aws.protocoltests.restxml#RestXmlExtras",
+ "rest_xml_extras",
+ imports = listOf("$commonModels/rest-xml-extras.smithy"),
+ ),
)
}
diff --git a/rust-runtime/Cargo.lock b/rust-runtime/Cargo.lock
index 77ff2b31d0..b808989551 100644
--- a/rust-runtime/Cargo.lock
+++ b/rust-runtime/Cargo.lock
@@ -465,7 +465,7 @@ version = "0.60.3"
[[package]]
name = "aws-smithy-http-server"
-version = "0.62.0"
+version = "0.62.1"
dependencies = [
"aws-smithy-http 0.60.9",
"aws-smithy-json 0.60.7",
diff --git a/rust-runtime/aws-smithy-http-server/Cargo.toml b/rust-runtime/aws-smithy-http-server/Cargo.toml
index c1b40cad68..3fefabbe9a 100644
--- a/rust-runtime/aws-smithy-http-server/Cargo.toml
+++ b/rust-runtime/aws-smithy-http-server/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "aws-smithy-http-server"
-version = "0.62.0"
+version = "0.62.1"
authors = ["Smithy Rust Server "]
edition = "2021"
license = "Apache-2.0"
@@ -29,7 +29,7 @@ http = "0.2"
http-body = "0.4"
hyper = { version = "0.14.26", features = ["server", "http1", "http2", "tcp", "stream"] }
lambda_http = { version = "0.8.0", optional = true }
-mime = "0.3.4"
+mime = "0.3.17"
nom = "7"
once_cell = "1.13"
pin-project-lite = "0.2"
diff --git a/rust-runtime/aws-smithy-http-server/src/protocol/mod.rs b/rust-runtime/aws-smithy-http-server/src/protocol/mod.rs
index e7eb963e98..27a16d9f18 100644
--- a/rust-runtime/aws-smithy-http-server/src/protocol/mod.rs
+++ b/rust-runtime/aws-smithy-http-server/src/protocol/mod.rs
@@ -93,7 +93,7 @@ fn content_type_header_classifier(
(Some(actual_content_type), Some(expected_content_type)) => {
let expected_mime = parse_expected_mime(expected_content_type);
let found_mime = parse_mime(actual_content_type)?;
- if expected_mime != found_mime {
+ if expected_mime != found_mime.essence_str() {
Err(MissingContentTypeReason::UnexpectedMimeType {
expected_mime: Some(expected_mime),
found_mime: Some(found_mime),
@@ -241,6 +241,13 @@ mod tests {
));
}
+ #[test]
+ fn valid_content_type_header_classifier_http_params() {
+ let request = req_content_type_smithy("application/json; charset=utf-8");
+ let result = content_type_header_classifier_smithy(&request, APPLICATION_JSON);
+ assert!(result.is_ok());
+ }
+
#[test]
fn valid_accept_header_classifier_multiple_values() {
let valid_request = req_accept("text/strings, application/json, invalid");