This is an automated email from the ASF dual-hosted git repository.
pjfanning pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/pekko-connectors.git
The following commit(s) were added to refs/heads/main by this push:
new 26d689382 AWS SPI: preserve content-type parameters and drop
unreachable map entry (#1905)
26d689382 is described below
commit 26d689382dd0cdca85db47fa710b04b310b5e446
Author: PJ Fanning <[email protected]>
AuthorDate: Thu Oct 1 15:29:18 2026 +0100
AWS SPI: preserve content-type parameters and drop unreachable map entry
(#1905)
Motivation:
tryCreateCustomContentType split content-type values only on '/', so a
value with parameters (e.g. "text/plain; charset=UTF-8") produced a
custom binary media type whose subtype embedded the parameters
("plain; charset=UTF-8") instead of a properly modeled ContentType.
The contentTypeMap also carried an entry keyed
"application/x-www-form-urlencoded; charset-UTF-8" (typo: '-' instead
of '='); the key is unreachable either way because the lookup value is
the re-rendered parsed Content-Type header, and pekko-http renders the
fixed-charset form-urlencoded media type without a charset parameter.
Modification:
tryCreateCustomContentType now tries ContentType.parse first and only
falls back to the legacy '/'-split custom binary media type when proper
parsing fails. Remove the unreachable typo'd map entry with a comment
explaining why no charset-suffixed key is needed.
Result:
Content-type values with parameters keep their parameters in the
request entity's ContentType; unparseable values retain the previous
fallback behavior.
Tests:
- sbt "aws-spi-pekko-http/Test/testOnly
org.apache.pekko.stream.connectors.awsspi.PekkoHttpClientSpec" - 14 passed (3
new tests); the parameters-preservation test fails without the fix (verified)
- sbt "aws-spi-pekko-http/mimaReportBinaryIssues" - no issues
- scalafmt --mode diff-ref=origin/main - clean
References:
None - found during a review of the aws-spi-pekko-http client
---
.../stream/connectors/awsspi/PekkoHttpClient.scala | 17 ++++++++++-----
.../connectors/awsspi/PekkoHttpClientSpec.scala | 25 +++++++++++++++++++++-
2 files changed, 36 insertions(+), 6 deletions(-)
diff --git
a/aws-spi-pekko-http/src/main/scala/org/apache/pekko/stream/connectors/awsspi/PekkoHttpClient.scala
b/aws-spi-pekko-http/src/main/scala/org/apache/pekko/stream/connectors/awsspi/PekkoHttpClient.scala
index 528d724a7..1c6b1aa41 100644
---
a/aws-spi-pekko-http/src/main/scala/org/apache/pekko/stream/connectors/awsspi/PekkoHttpClient.scala
+++
b/aws-spi-pekko-http/src/main/scala/org/apache/pekko/stream/connectors/awsspi/PekkoHttpClient.scala
@@ -167,10 +167,16 @@ object PekkoHttpClient {
private[awsspi] def tryCreateCustomContentType(contentTypeStr: String):
ContentType = {
logger.debug("Try to parse content type from {}", contentTypeStr)
- val mainAndsubType = contentTypeStr.split('/')
- if (mainAndsubType.length == 2)
- ContentType(MediaType.customBinary(mainAndsubType(0), mainAndsubType(1),
Compressible))
- else throw new RuntimeException(s"Could not parse custom content type
'$contentTypeStr'.")
+ // Prefer a proper parse so that values with parameters (e.g. "text/plain;
charset=UTF-8")
+ // keep their parameters instead of ending up embedded in the subtype.
+ ContentType.parse(contentTypeStr) match {
+ case Right(contentType) => contentType
+ case Left(_) =>
+ val mainAndsubType = contentTypeStr.split('/')
+ if (mainAndsubType.length == 2)
+ ContentType(MediaType.customBinary(mainAndsubType(0),
mainAndsubType(1), Compressible))
+ else throw new RuntimeException(s"Could not parse custom content type
'$contentTypeStr'.")
+ }
}
private[awsspi] def buildConnectionPoolSettings(
@@ -247,7 +253,8 @@ object PekkoHttpClient {
"application/x-amz-json-1.0" -> xAmzJson,
"application/x-amz-json-1.1" -> xAmzJson11,
"application/x-amz-cbor-1.1" -> xAmzCbor11, // used by Kinesis
- "application/x-www-form-urlencoded; charset-UTF-8" -> formUrlEncoded,
+ // No charset-suffixed key is needed: `application/x-www-form-urlencoded`
is a fixed-charset
+ // media type, so a parsed Content-Type header always renders without a
charset parameter.
"application/x-www-form-urlencoded" -> formUrlEncoded,
"application/xml" -> applicationXml)
diff --git
a/aws-spi-pekko-http/src/test/scala/org/apache/pekko/stream/connectors/awsspi/PekkoHttpClientSpec.scala
b/aws-spi-pekko-http/src/test/scala/org/apache/pekko/stream/connectors/awsspi/PekkoHttpClientSpec.scala
index d07b892c3..efab9223c 100644
---
a/aws-spi-pekko-http/src/test/scala/org/apache/pekko/stream/connectors/awsspi/PekkoHttpClientSpec.scala
+++
b/aws-spi-pekko-http/src/test/scala/org/apache/pekko/stream/connectors/awsspi/PekkoHttpClientSpec.scala
@@ -26,7 +26,7 @@ import com.typesafe.config.ConfigFactory
import org.apache.pekko
import pekko.http.scaladsl.model.headers.`Content-Type`
-import pekko.http.scaladsl.model.{ ContentTypes, HttpMethods, MediaTypes }
+import pekko.http.scaladsl.model.{ ContentTypes, HttpHeader, HttpMethods,
MediaTypes }
import pekko.http.scaladsl.settings.{ ClientConnectionSettings,
ConnectionPoolSettings }
import org.reactivestreams.Subscriber
import org.scalatest.OptionValues
@@ -70,6 +70,29 @@ class PekkoHttpClientSpec extends AnyWordSpec with Matchers
with OptionValues {
messages should contain(s"Try to parse content type from
$contentTypeStr")
}
+ "parse custom content type with parameters preserving the parameters" in {
+ val contentType =
PekkoHttpClient.tryCreateCustomContentType("text/plain; charset=UTF-8")
+ contentType.mediaType.mainType shouldBe "text"
+ contentType.mediaType.subType shouldBe "plain"
+ contentType.charsetOption.map(_.value) shouldBe Some("UTF-8")
+ }
+
+ "fall back to a custom binary content type when proper parsing fails" in {
+ val contentType = PekkoHttpClient.tryCreateCustomContentType("foo/bar
baz")
+ contentType.mediaType.mainType shouldBe "foo"
+ contentType.mediaType.subType shouldBe "bar baz"
+ }
+
+ "map form-urlencoded content type with charset to the predefined content
type" in {
+ val header = HttpHeader.parse("Content-Type",
"application/x-www-form-urlencoded; charset=UTF-8") match {
+ case HttpHeader.ParsingResult.Ok(h, _) => h
+ case error => fail(s"could not parse
header: $error")
+ }
+ val contentType =
PekkoHttpClient.contentTypeHeaderToContentType(Some(header))
+ contentType.mediaType.subType shouldBe "x-www-form-urlencoded"
+ contentType shouldBe PekkoHttpClient.formUrlEncoded
+ }
+
"remove 'ContentType' return 'ContentLength' separate from sdk headers" in
{
val headers = new java.util.HashMap[String, java.util.List[String]]
headers.put("Content-Type", Collections.singletonList("application/xml"))
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]