diff --git a/packages/smithy-http/src/smithy_http/deserializers.py b/packages/smithy-http/src/smithy_http/deserializers.py index f48136db..778137c0 100644 --- a/packages/smithy-http/src/smithy_http/deserializers.py +++ b/packages/smithy-http/src/smithy_http/deserializers.py @@ -24,6 +24,7 @@ from .aio.interfaces import HTTPResponse from .interfaces import Field, Fields +from .utils import split_header if TYPE_CHECKING: from smithy_core.aio.interfaces import StreamingBlob as AsyncStreamingBlob @@ -177,7 +178,17 @@ def __init__(self, field: Field) -> None: def read_list( self, schema: Schema, consumer: Callable[["ShapeDeserializer"], None] ) -> None: - for value in self._field.values: + values = self._field.values + if len(values) == 1: + is_http_date_list = False + value_schema = schema.members["member"] + if value_schema.shape_type is ShapeType.TIMESTAMP: + trait = value_schema.get_trait(TimestampFormatTrait) + is_http_date_list = ( + trait is None or trait.format is TimestampFormat.HTTP_DATE + ) + values = split_header(values[0], is_http_date_list) + for value in values: consumer(HTTPHeaderDeserializer(value)) diff --git a/packages/smithy-http/tests/unit/test_serializers.py b/packages/smithy-http/tests/unit/test_serializers.py index 199193bf..2385de2d 100644 --- a/packages/smithy-http/tests/unit/test_serializers.py +++ b/packages/smithy-http/tests/unit/test_serializers.py @@ -1290,6 +1290,90 @@ def header_cases() -> list[HTTPMessageTestCase]: ] +def header_deser_cases() -> list[HTTPMessageTestCase]: + return [ + HTTPMessageTestCase( + HTTPHeaders(string_list_member=["foo", "bar", "baz"]), + HTTPMessage(fields=tuples_to_fields([("stringList", "foo, bar, baz")])), + ), + HTTPMessageTestCase( + HTTPHeaders(string_list_member=["foo, bar", "spam", "eggs"]), + HTTPMessage( + fields=tuples_to_fields([("stringList", '"foo, bar", spam, eggs')]) + ), + ), + HTTPMessageTestCase( + HTTPHeaders( + http_date_list_timestamp_member=[ + datetime.datetime(2025, 1, 1, tzinfo=UTC), + datetime.datetime(2024, 1, 1, tzinfo=UTC), + ] + ), + HTTPMessage( + fields=tuples_to_fields( + [ + ( + "httpDateListTimestamp", + "Wed, 01 Jan 2025 00:00:00 GMT, Mon, 01 Jan 2024 00:00:00 GMT", + ), + ] + ), + ), + ), + HTTPMessageTestCase( + HTTPHeaders( + http_date_list_timestamp_member=[ + datetime.datetime(2025, 1, 1, tzinfo=UTC), + datetime.datetime(2024, 1, 1, tzinfo=UTC), + ] + ), + HTTPMessage( + fields=tuples_to_fields( + [ + ( + "httpDateListTimestamp", + '"Wed, 01 Jan 2025 00:00:00 GMT", "Mon, 01 Jan 2024 00:00:00 GMT"', + ), + ] + ), + ), + ), + HTTPMessageTestCase( + HTTPHeaders( + date_time_list_timestamp_member=[ + datetime.datetime(2025, 1, 1, tzinfo=UTC), + datetime.datetime(2024, 1, 1, tzinfo=UTC), + ] + ), + HTTPMessage( + fields=tuples_to_fields( + [ + ( + "dateTimeListTimestamp", + "2025-01-01T00:00:00Z, 2024-01-01T00:00:00Z", + ), + ] + ), + ), + ), + HTTPMessageTestCase( + HTTPHeaders( + epoch_list_timestamp_member=[ + datetime.datetime(2025, 1, 1, tzinfo=UTC), + datetime.datetime(2024, 1, 1, tzinfo=UTC), + ] + ), + HTTPMessage( + fields=tuples_to_fields( + [ + ("epochListTimestamp", "1735689600, 1704067200"), + ] + ), + ), + ), + ] + + def empty_prefix_header_ser_cases() -> list[HTTPMessageTestCase]: return [ HTTPMessageTestCase( @@ -1678,7 +1762,10 @@ async def test_serialize_http_response(case: HTTPMessageTestCase) -> None: RESPONSE_DESER_CASES: list[HTTPMessageTestCase] = ( - header_cases() + empty_prefix_header_deser_cases() + payload_cases() + header_cases() + + header_deser_cases() + + empty_prefix_header_deser_cases() + + payload_cases() )