Repository: smithy-lang/smithy
Pull request #2280 (2024-05-08 19:58:42)

Add defaults tests for restJson1
#### Background
Add defaults tests for restJson1 similar to AwsJson1_0 and CBOR

#### Testing
In smithy-ruby, not sure how to test here.

#### Links
n/a

---
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.



Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2778a445c..b95d0290f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,28 @@
 # Smithy Changelog
 
+## 1.49.0 (2024-05-08)
+
+### Features
+
+* Added list and map shapes to directed codegen. ([#2273](https://github.com/smithy-lang/smithy/pull/2273))
+* Added support for defaults on trait member values in trait-codegen. ([#2267](https://github.com/smithy-lang/smithy/pull/2267))
+* Added support for string-arrays for as parameters in rules-engine. ([#2266](https://github.com/smithy-lang/smithy/pull/2266))
+* Added new trait (`@operationContextParams`) for binding array parameters to nested operation inputs in the rules-engine. ([#2264](https://github.com/smithy-lang/smithy/pull/2264))
+
+### Bug Fixes
+
+* Fixed bug in the formatter where comments in operation errors were not being handled correctly. ([#2283](https://github.com/smithy-lang/smithy/pull/2283))
+* Fixed bug in the formatter where certain documentation comments were being converted to line-comments. ([#2277](https://github.com/smithy-lang/smithy/pull/2277))
+* Fixed incorrect status code in restXml response protocol test. ([#2272](https://github.com/smithy-lang/smithy/pull/2272))
+* Fixed ec2query protocol test for empty list serialization. ([#2269](https://github.com/smithy-lang/smithy/pull/2269))
+* Fixed Javadoc integration for documentation in members and enum variants in trait-codegen. ([#2265](https://github.com/smithy-lang/smithy/pull/2265)) 
+* Fixed timing issue in the delay calculation for waiter retries. ([#2259](https://github.com/smithy-lang/smithy/pull/2259))
+
+### Documentation
+
+* Corrected a typo in RPCv2 CBOR specificaiton. ([#2278](https://github.com/smithy-lang/smithy/pull/2278))
+* Updated casing of aggregate shape names in shape type table. ([#2271](https://github.com/smithy-lang/smithy/pull/2271))
+
 ## 1.48.0 (2024-04-24)
 
 ### Features
diff --git a/VERSION b/VERSION
index 9db5ea12f..7f3a46a84 100644
--- a/VERSION
+++ b/VERSION
@@ -1,1 +1,1 @@
-1.48.0
+1.49.0
diff --git a/docs/source-1.0/spec/aws/aws-json.rst.template b/docs/source-1.0/spec/aws/aws-json.rst.template
index ed8744312..641970472 100644
--- a/docs/source-1.0/spec/aws/aws-json.rst.template
+++ b/docs/source-1.0/spec/aws/aws-json.rst.template
@@ -50,7 +50,7 @@ The |quoted shape name| protocol uses the following headers:
     * - ``Content-Length``
       - true
       - The standard ``Content-Length`` header defined by
-        `RFC 7230 Section 3.3.2`_.
+        :rfc:`9110#section-8.6`.
     * - ``X-Amz-Target``
       - true for requests
       - The value of this header is the :token:`shape name <smithy:Identifier>` of the
@@ -207,5 +207,3 @@ These compliance tests define a model that is used to define test cases and
 the expected serialized HTTP requests and responses for each case.
 
 *TODO: Add event stream handling specifications.*
-
-.. _`RFC 7230 Section 3.3.2`: https://tools.ietf.org/html/rfc7230#section-3.3.2
diff --git a/docs/source-1.0/spec/aws/aws-query-serialization.rst.template b/docs/source-1.0/spec/aws/aws-query-serialization.rst.template
index 4b11f1fbb..fac8711b5 100644
--- a/docs/source-1.0/spec/aws/aws-query-serialization.rst.template
+++ b/docs/source-1.0/spec/aws/aws-query-serialization.rst.template
@@ -97,5 +97,3 @@ to the input's key.
     * - ``union``
       - A union is serialized identically to a ``structure`` shape, but only a
         single member can be set to a non-null value.
-
-.. _`RFC 7230 Section 3.3.2`: https://tools.ietf.org/html/rfc7230#section-3.3.2
diff --git a/docs/source-1.0/spec/core/http-traits.rst b/docs/source-1.0/spec/core/http-traits.rst
index 61d2368e9..2ae3190bf 100644
--- a/docs/source-1.0/spec/core/http-traits.rst
+++ b/docs/source-1.0/spec/core/http-traits.rst
@@ -14,8 +14,8 @@ and error structures are considered when serializing HTTP messages.
 
 .. important::
 
-    Violating `HTTP specifications`_ or relying on poorly-supported HTTP
-    functionality when defining HTTP bindings will limit interoperability
+    Violating :rfc:`HTTP specifications <9110>` or relying on poorly-supported
+    HTTP functionality when defining HTTP bindings will limit interoperability
     and likely lead to undefined behavior across Smithy implementations. For
     example, avoid defining GET/DELETE requests with payloads, defining
     response payloads for operations with a 204/205 status, etc.
@@ -106,9 +106,8 @@ method
 The ``method`` property defines the HTTP method of the operation (e.g., "GET",
 "PUT", "POST", "DELETE", "PATCH", etc). Smithy will use this value literally
 and will perform no validation on the method. The ``method`` value SHOULD
-match the ``operation`` production rule of :rfc:`7230#appendix-B`. This
-property does not influence the safety or idempotency characteristics of an
-operation.
+match one of the definitions found in :rfc:`9110#section-9.3`. This property
+does not influence the safety or idempotency characteristics of an operation.
 
 
 .. _http-uri:
@@ -117,7 +116,7 @@ uri
 ---
 
 The ``uri`` property defines the *request-target* of the operation in
-*origin-form* as defined in :rfc:`7230#section-5.3.1`. The URI is a simple
+*origin-form* as defined in :rfc:`9112#section-3.2.1`. The URI is a simple
 pattern that Smithy uses to match HTTP requests to operations and to bind
 components of the request URI to fields in the operations's input structure.
 :dfn:`Patterns` consist of literal characters that MUST be matched in the
@@ -525,9 +524,8 @@ Trait selector
     ``structure`` member that targets a list of these types.
 Value type
     ``string`` value defining a valid HTTP header field name according to
-    :rfc:`section 3.2 of RFC7230 <7230#section-3.2>`. The value MUST NOT be
-    empty and MUST be case-insensitively unique across all other members of
-    the structure.
+    :rfc:`9110#section-5.1`. The value MUST NOT be empty and MUST be
+    case-insensitively unique across all other members of the structure.
 Conflicts with
    :ref:`httpLabel-trait`,
    :ref:`httpQuery-trait`,
@@ -546,7 +544,7 @@ Conflicts with
 * ``string`` values with a :ref:`mediaType-trait` are always base64 encoded.
 * ``timestamp`` values are serialized using the ``http-date``
   format by default, as defined in the ``IMF-fixdate`` production of
-  :rfc:`7231#section-7.1.1.1`. The :ref:`timestampFormat-trait` MAY be used
+  :rfc:`9110#section-5.6.7`. The :ref:`timestampFormat-trait` MAY be used
   to use a custom serialization format.
 
 .. rubric:: Do not put too much data in HTTP headers
@@ -954,10 +952,10 @@ the body of the response.
 
 .. rubric:: Do not put too much data in the query string
 
-While there is no limit placed on the length of an `HTTP request line`_,
-many HTTP client and server implementations enforce limits in practice.
-Carefully consider the maximum allowed length of each member that is bound to
-an HTTP query string or path.
+While there is no limit placed on the length of an
+:rfc:`HTTP request line <9112#section-3>`, many HTTP client and server
+implementations enforce limits in practice. Carefully consider the maximum
+allowed length of each member that is bound to an HTTP query string or path.
 
 
 .. smithy-trait:: smithy.api#httpQueryParams
@@ -1335,5 +1333,3 @@ marked with the ``httpPayload`` trait:
 
 
 .. _percent-encoded: https://tools.ietf.org/html/rfc3986#section-2.1
-.. _HTTP request line: https://tools.ietf.org/html/rfc7230.html#section-3.1.1
-.. _HTTP specifications: https://datatracker.ietf.org/doc/html/rfc7230
diff --git a/docs/source-1.0/spec/core/model.rst b/docs/source-1.0/spec/core/model.rst
index bd5c4e6ae..78f1659dc 100644
--- a/docs/source-1.0/spec/core/model.rst
+++ b/docs/source-1.0/spec/core/model.rst
@@ -2020,7 +2020,7 @@ The following example defines the ``PutForecast`` operation.
 .. rubric:: Put semantics
 
 The semantics of a ``put`` lifecycle operation are similar to the semantics
-of a HTTP PUT method as described in :rfc:`section 4.3.4 of [RFC7231] <7231#section-4.3.4>`:
+of a HTTP PUT method as described in :rfc:`section 4.3.4 of [RFC9110] <9110#section-9.3.4>`:
 
   The PUT method requests that the state of the target resource be
   created or replaced ...
diff --git a/docs/source-1.0/spec/core/protocol-traits.rst b/docs/source-1.0/spec/core/protocol-traits.rst
index e420498b0..61c1af42b 100644
--- a/docs/source-1.0/spec/core/protocol-traits.rst
+++ b/docs/source-1.0/spec/core/protocol-traits.rst
@@ -309,7 +309,7 @@ Smithy defines the following built-in timestamp formats:
         values that contain offsets gracefully by normalizing them to UTC.
     * - http-date
       - An HTTP date as defined by the ``IMF-fixdate`` production in
-        :rfc:`7231#section-7.1.1.1` (for example,
+        :rfc:`9110#section-5.6.7` (for example,
         ``Tue, 29 Apr 2014 18:30:38 GMT``). A deserializer that encounters an
         ``http-date`` timestamp with fractional precision SHOULD fail to
         deserialize the value (for example, an HTTP server SHOULD return a 400
diff --git a/docs/source-2.0/additional-specs/protocols/smithy-rpc-v2.rst b/docs/source-2.0/additional-specs/protocols/smithy-rpc-v2.rst
index 40479383a..46b54ffa2 100644
--- a/docs/source-2.0/additional-specs/protocols/smithy-rpc-v2.rst
+++ b/docs/source-2.0/additional-specs/protocols/smithy-rpc-v2.rst
@@ -238,7 +238,7 @@ headers for requests:
         is ``application/vnd.amazon.eventstream``.
     * - ``Content-Length``
       - Conditional
-      - The standard ``Content-Length`` header defined by :rfc:`7230#section-3.3.2`.
+      - The standard ``Content-Length`` header defined by :rfc:`9110#section-8.6`.
         For event streaming requests, this MUST NOT be set.
     * - ``Accept``
       - Conditional
@@ -303,7 +303,7 @@ headers for responses:
         is ``application/vnd.amazon.eventstream``.
     * - ``Content-Length``
       - Conditional
-      - The standard ``Content-Length`` header defined by :rfc:`7230#section-3.3.2`.
+      - The standard ``Content-Length`` header defined by :rfc:`9110#section-8.6`.
         For event streaming requests, this SHOULD NOT be set.
 
 
diff --git a/docs/source-2.0/aws/aws-iam.rst b/docs/source-2.0/aws/aws-iam.rst
index 91377a1fe..570036b42 100644
--- a/docs/source-2.0/aws/aws-iam.rst
+++ b/docs/source-2.0/aws/aws-iam.rst
@@ -545,6 +545,10 @@ The following example defines two service-specific condition keys:
 
     namespace smithy.example
 
+    use aws.api#service
+    use aws.iam#defineConditionKeys
+    use aws.iam#serviceResolvedConditionKeys
+
     @defineConditionKeys(
         "myservice:ActionContextKey1": { type: "String" },
         "myservice:ActionContextKey2": { type: "String" }
@@ -583,6 +587,11 @@ explicitly binds ``ActionContextKey1`` to the field ``key``.
 
     namespace smithy.example
 
+    use aws.api#service
+    use aws.iam#conditionKeys
+    use aws.iam#defineConditionKeys
+    use aws.iam#conditionKeyValue
+
     @defineConditionKeys(
         "myservice:ActionContextKey1": { type: "String" }
     )
@@ -595,7 +604,7 @@ explicitly binds ``ActionContextKey1`` to the field ``key``.
     @conditionKeys(["myservice:ActionContextKey1"])
     operation OperationA {
         input := {
-            @conditionKeyValue("ActionContextKey1")
+            @conditionKeyValue("myservice:ActionContextKey1")
             key: String
         }
         output := {
diff --git a/docs/source-2.0/aws/protocols/aws-json.rst.template b/docs/source-2.0/aws/protocols/aws-json.rst.template
index e77914073..0e28b73a1 100644
--- a/docs/source-2.0/aws/protocols/aws-json.rst.template
+++ b/docs/source-2.0/aws/protocols/aws-json.rst.template
@@ -50,7 +50,7 @@ The |quoted shape name| protocol uses the following headers:
     * - ``Content-Length``
       - true
       - The standard ``Content-Length`` header defined by
-        :rfc:`7230#section-3.3.2`.
+        :rfc:`9110#section-8.6`.
     * - ``X-Amz-Target``
       - true for requests
       - The value of this header is the :token:`shape name <smithy:Identifier>` of the
diff --git a/docs/source-2.0/guides/model-translations/converting-to-openapi.rst b/docs/source-2.0/guides/model-translations/converting-to-openapi.rst
index 91746b394..bbeb9a93c 100644
--- a/docs/source-2.0/guides/model-translations/converting-to-openapi.rst
+++ b/docs/source-2.0/guides/model-translations/converting-to-openapi.rst
@@ -1550,6 +1550,29 @@ additionalAllowedCorsHeaders (``[string]``)
             }
         }
 
+
+.. _generate-openapi-apigateway-setting-syncCorsPreflightIntegration:
+
+syncCorsPreflightIntegration (``boolean``)
+    Set to true to sync CORS preflight integration request templates with all possible content-types
+    from other methods within the same path resource.
+
+    .. code-block:: json
+        :caption: smithy-build.json
+
+        {
+            "version": "1.0",
+            "plugins": {
+                "openapi": {
+                    "service": "example.weather#Weather",
+                    "syncCorsPreflightIntegration": true
+                }
+            }
+        }
+
+    With this enabled, the `integration's passthroughBehavior`_ for CORS preflight integration
+    will be set to ``never``.
+
 Binary types
 ============
 
@@ -1648,6 +1671,10 @@ additions during the OpenAPI conversion:
 * Adds static CORS response headers to API Gateway "gateway" responses.  These are added only when
   no gateway responses are defined in the OpenAPI model.
 
+.. note::
+    If :ref:`syncCorsPreflightIntegration <generate-openapi-apigateway-setting-syncCorsPreflightIntegration>` is
+    set to ``true``, the CORS preflight `integration's passthroughBehavior`_ will be set to ``never`` and the integration's
+    request templates will be synced with all possible content-types from other methods within the same path resource.
 
 .. _authorizers:
 
@@ -2037,4 +2064,5 @@ The conversion process is highly extensible through
 .. _Lambda authorizers: https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-swagger-extensions-authorizer.html
 .. _API Gateway's API key usage plans: https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-api-usage-plans.html
 .. _OpenAPI specification extension: https://spec.openapis.org/oas/v3.1.0#specification-extensions
+.. _integration's passthroughBehavior: https://docs.aws.amazon.com/apigateway/latest/developerguide/integration-passthrough-behaviors.html
 .. _gradle installed: https://gradle.org/install/
diff --git a/docs/source-2.0/spec/behavior-traits.rst b/docs/source-2.0/spec/behavior-traits.rst
index 7ada59fea..5fdfdb834 100644
--- a/docs/source-2.0/spec/behavior-traits.rst
+++ b/docs/source-2.0/spec/behavior-traits.rst
@@ -6,7 +6,7 @@ Idempotency
 ===========
 
 Operations marked with the :ref:`readonly-trait` or :ref:`idempotent-trait`
-are considered idempotent as defined in :rfc:`7231#section-4.2.2`. Operations
+are considered idempotent as defined in :rfc:`9110#section-9.2.2`. Operations
 that contain a top-level input member marked with the :ref:`idempotencytoken-trait`
 that are provided a token for the member are also considered idempotent. All
 other operations SHOULD be considered unsafe to retry unless the response to
diff --git a/docs/source-2.0/spec/http-bindings.rst b/docs/source-2.0/spec/http-bindings.rst
index fa00f8de0..b177a5454 100644
--- a/docs/source-2.0/spec/http-bindings.rst
+++ b/docs/source-2.0/spec/http-bindings.rst
@@ -14,7 +14,7 @@ and error structures are considered when serializing HTTP messages.
 
 .. important::
 
-    Violating :rfc:`HTTP specifications <7230>` or relying on poorly-supported
+    Violating :rfc:`HTTP specifications <9110>` or relying on poorly-supported
     HTTP functionality when defining HTTP bindings will limit interoperability
     and likely lead to undefined behavior across Smithy implementations. For
     example, avoid defining GET/DELETE requests with payloads, defining
@@ -107,9 +107,8 @@ method
 The ``method`` property defines the HTTP method of the operation (e.g., "GET",
 "PUT", "POST", "DELETE", "PATCH", etc). Smithy will use this value literally
 and will perform no validation on the method. The ``method`` value SHOULD
-match the ``operation`` production rule of :rfc:`7230#appendix-B`. This
-property does not influence the safety or idempotency characteristics of an
-operation.
+match one of the definitions found in :rfc:`9110#section-9.3`. This property
+does not influence the safety or idempotency characteristics of an operation.
 
 
 .. _http-uri:
@@ -118,7 +117,7 @@ uri
 ---
 
 The ``uri`` property defines the *request-target* of the operation in
-*origin-form* as defined in :rfc:`7230#section-5.3.1`. The URI is a simple
+*origin-form* as defined in :rfc:`9112#section-3.2.1`. The URI is a simple
 pattern that Smithy uses to match HTTP requests to operations and to bind
 components of the request URI to fields in the operations's input structure.
 :dfn:`Patterns` consist of literal characters that MUST be matched in the
@@ -634,9 +633,8 @@ Trait selector
     ``structure`` member that targets a list of these types.
 Value type
     ``string`` value defining a valid HTTP header field name according to
-    :rfc:`section 3.2 of RFC7230 <7230#section-3.2>`. The value MUST NOT be
-    empty and MUST be case-insensitively unique across all other members of
-    the structure.
+    :rfc:`9110#section-5.1`. The value MUST NOT be empty and MUST be
+    case-insensitively unique across all other members of the structure.
 Conflicts with
    :ref:`httpLabel-trait`,
    :ref:`httpQuery-trait`,
@@ -656,7 +654,7 @@ Conflicts with
 * ``string`` values with a :ref:`mediaType-trait` are always base64 encoded.
 * ``timestamp`` values are serialized using the ``http-date``
   format by default, as defined in the ``IMF-fixdate`` production of
-  :rfc:`7231#section-7.1.1.1`. The :ref:`timestampFormat-trait` MAY be used
+  :rfc:`9110#section-5.6.7`. The :ref:`timestampFormat-trait` MAY be used
   to use a custom serialization format.
 
 .. note::
@@ -1089,7 +1087,7 @@ is simply ignored.
 .. note::
 
     While there is no limit placed on the length of an
-    :rfc:`HTTP request line <7230#section-3.1.1>`, many HTTP client and server
+    :rfc:`HTTP request line <9112#section-3>`, many HTTP client and server
     implementations enforce limits in practice. Carefully consider the maximum
     allowed length of each member that is bound to an HTTP query string or
     path.
diff --git a/docs/source-2.0/spec/protocol-traits.rst b/docs/source-2.0/spec/protocol-traits.rst
index 9e9341043..18f9518ff 100644
--- a/docs/source-2.0/spec/protocol-traits.rst
+++ b/docs/source-2.0/spec/protocol-traits.rst
@@ -228,7 +228,7 @@ Smithy defines the following built-in timestamp formats:
         values that contain offsets gracefully by normalizing them to UTC.
     * - http-date
       - An HTTP date as defined by the ``IMF-fixdate`` production in
-        :rfc:`7231#section-7.1.1.1` (for example,
+        :rfc:`9110#section-5.6.7` (for example,
         ``Tue, 29 Apr 2014 18:30:38 GMT``). A deserializer that encounters an
         ``http-date`` timestamp with fractional precision SHOULD fail to
         deserialize the value (for example, an HTTP server SHOULD return a 400
diff --git a/docs/source-2.0/spec/service-types.rst b/docs/source-2.0/spec/service-types.rst
index 5ce6ac3d2..c5dd2bcda 100644
--- a/docs/source-2.0/spec/service-types.rst
+++ b/docs/source-2.0/spec/service-types.rst
@@ -862,7 +862,7 @@ Put semantics
 ^^^^^^^^^^^^^
 
 The semantics of a ``put`` lifecycle operation are similar to the semantics
-of a HTTP PUT method as described in :rfc:`section 4.3.4 of [RFC7231] <7231#section-4.3.4>`:
+of a HTTP PUT method as described in :rfc:`section 4.3.4 of [RFC9110] <9110#section-9.3.4>`:
 
   The PUT method requests that the state of the target resource be
   created or replaced ...
diff --git a/smithy-aws-apigateway-openapi/src/main/java/software/amazon/smithy/aws/apigateway/openapi/AddCorsPreflightIntegration.java b/smithy-aws-apigateway-openapi/src/main/java/software/amazon/smithy/aws/apigateway/openapi/AddCorsPreflightIntegration.java
index ad2eab0f1..c80458cc4 100644
--- a/smithy-aws-apigateway-openapi/src/main/java/software/amazon/smithy/aws/apigateway/openapi/AddCorsPreflightIntegration.java
+++ b/smithy-aws-apigateway-openapi/src/main/java/software/amazon/smithy/aws/apigateway/openapi/AddCorsPreflightIntegration.java
@@ -31,6 +31,7 @@ import software.amazon.smithy.aws.apigateway.traits.MockIntegrationTrait;
 import software.amazon.smithy.jsonschema.Schema;
 import software.amazon.smithy.model.Model;
 import software.amazon.smithy.model.knowledge.TopDownIndex;
+import software.amazon.smithy.model.node.Node;
 import software.amazon.smithy.model.node.ObjectNode;
 import software.amazon.smithy.model.shapes.OperationShape;
 import software.amazon.smithy.model.traits.CorsTrait;
@@ -45,6 +46,7 @@ import software.amazon.smithy.openapi.model.Ref;
 import software.amazon.smithy.openapi.model.ResponseObject;
 import software.amazon.smithy.utils.CaseUtils;
 import software.amazon.smithy.utils.ListUtils;
+import software.amazon.smithy.utils.SetUtils;
 
 /**
  * Adds CORS-preflight OPTIONS requests using mock API Gateway integrations.
@@ -70,6 +72,7 @@ final class AddCorsPreflightIntegration implements ApiGatewayMapper {
     private static final Logger LOGGER = Logger.getLogger(AddCorsPreflightIntegration.class.getName());
     private static final String API_GATEWAY_DEFAULT_ACCEPT_VALUE = "application/json";
     private static final String INTEGRATION_EXTENSION = "x-amazon-apigateway-integration";
+    private static final String REQUEST_TEMPLATES_KEY = "requestTemplates";
     private static final String PREFLIGHT_SUCCESS = "{\"statusCode\":200}";
 
     @Override
@@ -95,7 +98,7 @@ final class AddCorsPreflightIntegration implements ApiGatewayMapper {
         LOGGER.fine(() -> "Adding CORS-preflight OPTIONS request and API Gateway integration for " + path);
         Map<CorsHeader, String> headers = deduceCorsHeaders(context, path, pathItem, corsTrait);
         return pathItem.toBuilder()
-                .options(createPreflightOperation(path, pathItem, headers))
+                .options(createPreflightOperation(context, path, pathItem, headers))
                 .build();
     }
 
@@ -170,7 +173,7 @@ final class AddCorsPreflightIntegration implements ApiGatewayMapper {
     }
 
     private static OperationObject createPreflightOperation(
-            String path, PathItem pathItem, Map<CorsHeader, String> headers) {
+            Context<? extends Trait> context, String path, PathItem pathItem, Map<CorsHeader, String> headers) {
         return OperationObject.builder()
                 .tags(ListUtils.of("CORS"))
                 .security(Collections.emptyList())
@@ -178,7 +181,7 @@ final class AddCorsPreflightIntegration implements ApiGatewayMapper {
                 .operationId(createOperationId(path))
                 .putResponse("200", createPreflightResponse(headers))
                 .parameters(findPathParameters(pathItem))
-                .putExtension(INTEGRATION_EXTENSION, createPreflightIntegration(headers, pathItem))
+                .putExtension(INTEGRATION_EXTENSION, createPreflightIntegration(context, headers, pathItem))
                 .build();
     }
 
@@ -214,7 +217,8 @@ final class AddCorsPreflightIntegration implements ApiGatewayMapper {
         return builder.build();
     }
 
-    private static ObjectNode createPreflightIntegration(Map<CorsHeader, String> headers, PathItem pathItem) {
+    private static ObjectNode createPreflightIntegration(
+            Context<? extends Trait> context, Map<CorsHeader, String> headers, PathItem pathItem) {
         IntegrationResponse.Builder responseBuilder = IntegrationResponse.builder().statusCode("200");
 
         // Add each CORS header to the mock integration response.
@@ -222,13 +226,34 @@ final class AddCorsPreflightIntegration implements ApiGatewayMapper {
             responseBuilder.putResponseParameter("method.response.header." + e.getKey(), "'" + e.getValue() + "'");
         }
 
+        boolean isPreflightSynced = Boolean.TRUE.equals(context.getConfig().getSyncCorsPreflightIntegration());
         MockIntegrationTrait.Builder integration = MockIntegrationTrait.builder()
                 // See https://forums.aws.amazon.com/thread.jspa?threadID=256140
                 .contentHandling("CONVERT_TO_TEXT")
-                .passThroughBehavior("when_no_match")
+                // Passthrough behavior "never" will fail the request with unsupported content type more appropriately.
+                // https://docs.aws.amazon.com/apigateway/latest/developerguide/integration-passthrough-behaviors.html
+                .passThroughBehavior(isPreflightSynced ? "never" : "when_no_match")
                 .putResponse("default", responseBuilder.build())
                 .putRequestTemplate(API_GATEWAY_DEFAULT_ACCEPT_VALUE, PREFLIGHT_SUCCESS);
 
+        if (isPreflightSynced) {
+            // Adds request template for every unique Content-Type supported by all path operations.
+            // This ensures that for Content-Type(s) other than 'application/json', the entire request payload
+            // is not sent to APIGW mock integration as stipulated by 'when_no_match' passthroughBehavior.
+            // APIGW throws an error if the mock integration request does not follow a set contract,
+            // example {"statusCode":200}.
+            for (OperationObject operation : pathItem.getOperations().values()) {
+                ObjectNode extensionNode = operation.getExtension(INTEGRATION_EXTENSION)
+                        .flatMap(Node::asObjectNode)
+                        .orElse(Node.objectNode());
+                Set<String> mimeTypes = extensionNode.getObjectMember(REQUEST_TEMPLATES_KEY)
+                        .map(ObjectNode::getStringMap)
+                        .map(Map::keySet)
+                        .orElse(SetUtils.of());
+                mimeTypes.forEach(mimeType -> integration.putRequestTemplate(mimeType, PREFLIGHT_SUCCESS));
+            }
+        }
+
         // Add a request template for every mime-type of every response.
         for (OperationObject operation : pathItem.getOperations().values()) {
             for (ResponseObject response : operation.getResponses().values()) {
diff --git a/smithy-aws-apigateway-openapi/src/main/java/software/amazon/smithy/aws/apigateway/openapi/AddDefaultConfigSettings.java b/smithy-aws-apigateway-openapi/src/main/java/software/amazon/smithy/aws/apigateway/openapi/AddDefaultConfigSettings.java
index de5bf6117..06917e347 100644
--- a/smithy-aws-apigateway-openapi/src/main/java/software/amazon/smithy/aws/apigateway/openapi/AddDefaultConfigSettings.java
+++ b/smithy-aws-apigateway-openapi/src/main/java/software/amazon/smithy/aws/apigateway/openapi/AddDefaultConfigSettings.java
@@ -43,7 +43,7 @@ final class AddDefaultConfigSettings implements ApiGatewayMapper {
     public void updateDefaultSettings(Model model, OpenApiConfig openApiConfig) {
         ApiGatewayConfig config = openApiConfig.getExtensions(ApiGatewayConfig.class);
         if (config.getApiGatewayDefaults() == null) {
-            LOGGER.warning(String.format("`apiGatewayDefaults` configuration not set for opeanapi plugin. Assuming %s.",
+            LOGGER.warning(String.format("`apiGatewayDefaults` configuration not set for openapi plugin. Assuming %s.",
                     DEFAULT_VERSION));
             config.setApiGatewayDefaults(DEFAULT_VERSION);
         }
diff --git a/smithy-aws-iam-traits/src/main/java/software/amazon/smithy/aws/iam/traits/IamResourceTraitConflictingNameValidator.java b/smithy-aws-iam-traits/src/main/java/software/amazon/smithy/aws/iam/traits/IamResourceTraitConflictingNameValidator.java
new file mode 100644
index 000000000..9ea4fa3d9
--- /dev/null
+++ b/smithy-aws-iam-traits/src/main/java/software/amazon/smithy/aws/iam/traits/IamResourceTraitConflictingNameValidator.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package software.amazon.smithy.aws.iam.traits;
+
+import static software.amazon.smithy.model.validation.ValidationUtils.tickedList;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import software.amazon.smithy.model.Model;
+import software.amazon.smithy.model.knowledge.TopDownIndex;
+import software.amazon.smithy.model.shapes.ResourceShape;
+import software.amazon.smithy.model.shapes.ServiceShape;
+import software.amazon.smithy.model.shapes.ShapeId;
+import software.amazon.smithy.model.validation.AbstractValidator;
+import software.amazon.smithy.model.validation.ValidationEvent;
+import software.amazon.smithy.utils.SmithyInternalApi;
+
+/**
+ * Ensures that there is no resource name conflict in a service closure
+ * in IAM space after processing {@link IamResourceTrait}.
+ */
+@SmithyInternalApi
+public class IamResourceTraitConflictingNameValidator extends AbstractValidator {
+    @Override
+    public List<ValidationEvent> validate(Model model) {
+        TopDownIndex topDownIndex = TopDownIndex.of(model);
+        return model.shapes(ServiceShape.class)
+                .flatMap(shape -> validateService(topDownIndex, shape).stream())
+                .collect(Collectors.toList());
+    }
+
+    private List<ValidationEvent> validateService(TopDownIndex topDownIndex, ServiceShape service) {
+        List<ValidationEvent> events = new ArrayList<>();
+        Map<String, List<ShapeId>> resourceMap = new HashMap<>();
+        for (ResourceShape resource : topDownIndex.getContainedResources(service)) {
+            String resourceName = IamResourceTrait.resolveResourceName(resource);
+            resourceMap.computeIfAbsent(resourceName, k -> new ArrayList<>()).add(resource.getId());
+        }
+        resourceMap.entrySet().stream()
+                .filter(entry -> entry.getValue().size() > 1)
+                .map(entry -> error(service, String.format(
+                        "Multiple IAM resources defined with the same IAM resource name is not allowed in a service "
+                                + "closure, but found multiple resources named `%s` in the service `%s`: [%s]",
+                        entry.getKey(), service.getId(), tickedList(entry.getValue()))))
+                .forEach(events::add);
+        return events;
+    }
+}
diff --git a/smithy-aws-iam-traits/src/main/resources/META-INF/services/software.amazon.smithy.model.validation.Validator b/smithy-aws-iam-traits/src/main/resources/META-INF/services/software.amazon.smithy.model.validation.Validator
index 856e5dbe6..120767a57 100644
--- a/smithy-aws-iam-traits/src/main/resources/META-INF/services/software.amazon.smithy.model.validation.Validator
+++ b/smithy-aws-iam-traits/src/main/resources/META-INF/services/software.amazon.smithy.model.validation.Validator
@@ -1,3 +1,4 @@
 software.amazon.smithy.aws.iam.traits.ConditionKeysValidator
 software.amazon.smithy.aws.iam.traits.IamActionValidator
 software.amazon.smithy.aws.iam.traits.IamResourceTraitValidator
+software.amazon.smithy.aws.iam.traits.IamResourceTraitConflictingNameValidator
diff --git a/smithy-diff/src/main/java/software/amazon/smithy/diff/evaluators/ChangedEnumTrait.java b/smithy-diff/src/main/java/software/amazon/smithy/diff/evaluators/ChangedEnumTrait.java
index 72cba13cd..75a494e20 100644
--- a/smithy-diff/src/main/java/software/amazon/smithy/diff/evaluators/ChangedEnumTrait.java
+++ b/smithy-diff/src/main/java/software/amazon/smithy/diff/evaluators/ChangedEnumTrait.java
@@ -43,6 +43,7 @@ public final class ChangedEnumTrait extends AbstractDiffEvaluator {
     private static final String ORDER_CHANGED = ".OrderChanged.";
     private static final String NAME_CHANGED = ".NameChanged.";
     private static final String REMOVED = ".Removed.";
+    private static final String APPENDED = ".Appended.";
 
     @Override
     public List<ValidationEvent> evaluate(Differences differences) {
@@ -135,8 +136,14 @@ public final class ChangedEnumTrait extends AbstractDiffEvaluator {
                     if (newTrait.isSynthetic()) {
                         appendedSource = change.getNewShape().getSourceLocation();
                     }
-                    events.add(note(change.getNewShape(), appendedSource, String.format(
-                            "Enum value `%s` was appended", definition.getValue())));
+                    events.add(
+                            ValidationEvent.builder()
+                                    .severity(Severity.NOTE)
+                                    .message(String.format("Enum value `%s` was appended", definition.getValue()))
+                                    .shape(change.getNewShape())
+                                    .sourceLocation(appendedSource)
+                                    .id(getEventId() + APPENDED + newPosition)
+                                    .build());
                 }
             }
 
diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/pattern/UriPattern.java b/smithy-model/src/main/java/software/amazon/smithy/model/pattern/UriPattern.java
index e9847ed2e..7cc90857c 100644
--- a/smithy-model/src/main/java/software/amazon/smithy/model/pattern/UriPattern.java
+++ b/smithy-model/src/main/java/software/amazon/smithy/model/pattern/UriPattern.java
@@ -55,12 +55,12 @@ public final class UriPattern extends SmithyPattern {
      * Parse a URI pattern string into a UriPattern.
      *
      * <p>The provided value must match the origin-form request-target
-     * grammar production in RFC 7230, section 5.3.1.
+     * grammar production in RFC 9112, section 3.2.1.
      *
      * @param uri URI pattern to parse.
      * @return Returns the parsed URI pattern.
      * @throws InvalidUriPatternException for invalid URI patterns.
-     * @see <a href="https://tools.ietf.org/html/rfc7230#section-5.3.1">RFC 7230 Section 5.3.1</a>
+     * @see <a href="https://tools.ietf.org/html/rfc9112#section-3.2.1">RFC 9112 Section 3.2.1</a>
      */
     public static UriPattern parse(String uri) {
         if (uri.endsWith("?")) {
diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/TimestampFormatPlugin.java b/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/TimestampFormatPlugin.java
index 8518356cd..24919cf17 100644
--- a/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/TimestampFormatPlugin.java
+++ b/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/TimestampFormatPlugin.java
@@ -126,7 +126,7 @@ final class TimestampFormatPlugin implements NodeValidatorPlugin {
     private String createInvalidHttpDateMessage(String dateValue) {
         return String.format(
                 "Invalid value provided for %s formatted timestamp. Expected a string value that "
-                + "matches the IMF-fixdate production of RFC 7231 section-7.1.1.1. Found: %s",
+                + "matches the IMF-fixdate production of RFC 9110 section-5.6.7. Found: %s",
                 TimestampFormatTrait.HTTP_DATE, dateValue);
     }
 
diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HttpHeaderTraitValidator.java b/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HttpHeaderTraitValidator.java
index a438298b1..45dbff2f2 100644
--- a/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HttpHeaderTraitValidator.java
+++ b/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HttpHeaderTraitValidator.java
@@ -39,7 +39,7 @@ import software.amazon.smithy.utils.SetUtils;
  */
 public final class HttpHeaderTraitValidator extends AbstractValidator {
 
-    /** Gather the allowed characters for HTTP headers (tchar from RFC 7230). **/
+    /** Gather the allowed characters for HTTP headers (tchar from RFC 9110 section 5.6.2). **/
     private static final Set<Character> TCHAR = SetUtils.of(
             // "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
             '!', '#', '$', '%', '&', '\'', '*', '+', '-', '.', '^', '_', '`', '|', '~',
@@ -101,7 +101,7 @@ public final class HttpHeaderTraitValidator extends AbstractValidator {
         for (int i = 0; i < header.length(); i++) {
             if (!TCHAR.contains(header.charAt(i))) {
                 return Optional.of(danger(member, trait, String.format(
-                        "`%s` is not a valid HTTP header field name according to section 3.2 of RFC 7230", header)));
+                        "`%s` is not a valid HTTP header field name according to section 5.6.2 of RFC 9110", header)));
             }
         }
 
diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HttpMethodSemanticsValidator.java b/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HttpMethodSemanticsValidator.java
index 69f38b383..42f660a06 100644
--- a/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HttpMethodSemanticsValidator.java
+++ b/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HttpMethodSemanticsValidator.java
@@ -35,7 +35,7 @@ import software.amazon.smithy.utils.MapUtils;
 
 /**
  * Validates that `http` traits applied to operation shapes use the most
- * semantically appropriate HTTP method according to RFC 7231.
+ * semantically appropriate HTTP method according to RFC 9110.
  */
 public final class HttpMethodSemanticsValidator extends AbstractValidator {
     /**
diff --git a/smithy-model/src/main/resources/software/amazon/smithy/model/loader/prelude.smithy b/smithy-model/src/main/resources/software/amazon/smithy/model/loader/prelude.smithy
index abce5303e..b8a92aff7 100644
--- a/smithy-model/src/main/resources/software/amazon/smithy/model/loader/prelude.smithy
+++ b/smithy-model/src/main/resources/software/amazon/smithy/model/loader/prelude.smithy
@@ -1123,7 +1123,7 @@ enum timestampFormat {
     EPOCH_SECONDS = "epoch-seconds"
 
     /// An HTTP date as defined by the IMF-fixdate production in
-    /// RFC 7231#section-7.1.1.1 (for example, Tue, 29 Apr 2014 18:30:38 GMT).
+    /// RFC 9110#section-5.6.7 (for example, Tue, 29 Apr 2014 18:30:38 GMT).
     HTTP_DATE = "http-date"
 }
 
diff --git a/smithy-openapi/src/main/java/software/amazon/smithy/openapi/OpenApiConfig.java b/smithy-openapi/src/main/java/software/amazon/smithy/openapi/OpenApiConfig.java
index cf0db1894..90b83e14d 100644
--- a/smithy-openapi/src/main/java/software/amazon/smithy/openapi/OpenApiConfig.java
+++ b/smithy-openapi/src/main/java/software/amazon/smithy/openapi/OpenApiConfig.java
@@ -101,6 +101,7 @@ public class OpenApiConfig extends JsonSchemaConfig {
     private List<String> externalDocs = ListUtils.of(
             "Homepage", "API Reference", "User Guide", "Developer Guide", "Reference", "Guide");
     private boolean disableIntegerFormat = false;
+    private boolean syncCorsPreflightIntegration = false;
     private ErrorStatusConflictHandlingStrategy onErrorStatusConflict;
     private OpenApiVersion version = OpenApiVersion.VERSION_3_0_2;
 
@@ -355,6 +356,21 @@ public class OpenApiConfig extends JsonSchemaConfig {
     }
 
 
+    public boolean getSyncCorsPreflightIntegration() {
+        return this.syncCorsPreflightIntegration;
+    }
+
+    /**
+     * Set true to sync CORS preflight integration request templates with the other
+     * methods of the same path resource and set passthroughBehavior to "never".
+     *
+     * @param syncCorsPreflightIntegration True to match CORS preflight integration.
+     */
+    public void setSyncCorsPreflightIntegration(boolean syncCorsPreflightIntegration) {
+        this.syncCorsPreflightIntegration = syncCorsPreflightIntegration;
+    }
+
+
     public ErrorStatusConflictHandlingStrategy getOnErrorStatusConflict() {
         return onErrorStatusConflict;
     }
diff --git a/smithy-syntax/src/main/java/software/amazon/smithy/syntax/BracketFormatter.java b/smithy-syntax/src/main/java/software/amazon/smithy/syntax/BracketFormatter.java
index 68c494ff8..03899eac2 100644
--- a/smithy-syntax/src/main/java/software/amazon/smithy/syntax/BracketFormatter.java
+++ b/smithy-syntax/src/main/java/software/amazon/smithy/syntax/BracketFormatter.java
@@ -38,7 +38,37 @@ final class BracketFormatter {
             Function<TreeCursor, Doc> visitor,
             Function<TreeCursor, Stream<TreeCursor>> mapper
     ) {
-        return new Extractor(visitor, mapper);
+        return extractor(visitor, mapper, TreeCursor::children);
+    }
+
+    static Function<TreeCursor, Stream<Doc>> extractor(
+            Function<TreeCursor, Doc> visitor,
+            Function<TreeCursor, Stream<TreeCursor>> mapper,
+            Function<TreeCursor, Stream<TreeCursor>> childrenSupplier
+    ) {
+        return (cursor) -> childrenSupplier.apply(cursor)
+                .flatMap(c -> {
+                    TreeType type = c.getTree().getType();
+                    return type == TreeType.WS || type == TreeType.COMMENT ? Stream.of(c) : mapper.apply(c);
+                })
+                .flatMap(c -> {
+                    // If the child extracts WS, then filter it down to just comments.
+                    return c.getTree().getType() == TreeType.WS
+                            ? c.getChildrenByType(TreeType.COMMENT).stream()
+                            : Stream.of(c);
+                })
+                .map(visitor)
+                .filter(doc -> doc != Doc.empty());
+    }
+
+    static Function<TreeCursor, Stream<TreeCursor>> byTypeMapper(TreeType childType) {
+        return child -> child.getTree().getType() == childType
+                ? Stream.of(child)
+                : Stream.empty();
+    }
+
+    static Function<TreeCursor, Stream<TreeCursor>> siblingChildrenSupplier() {
+        return cursor -> cursor.remainingSiblings().stream();
     }
 
     // Brackets children of childType between open and closed brackets. If the children can fit together
@@ -47,9 +77,7 @@ final class BracketFormatter {
             TreeType childType,
             Function<TreeCursor, Doc> visitor
     ) {
-        return extractor(visitor, child -> child.getTree().getType() == childType
-                                           ? Stream.of(child)
-                                           : Stream.empty());
+        return extractor(visitor, byTypeMapper(childType));
     }
 
     BracketFormatter open(Doc open) {
@@ -138,36 +166,4 @@ final class BracketFormatter {
         }
         return lineDoc;
     }
-
-    private static final class Extractor implements Function<TreeCursor, Stream<Doc>> {
-        private final Function<TreeCursor, Stream<TreeCursor>> mapper;
-        private final Function<TreeCursor, Doc> visitor;
-
-        private Extractor(
-                Function<TreeCursor, Doc> visitor,
-                Function<TreeCursor, Stream<TreeCursor>> mapper
-        ) {
-            this.visitor = visitor;
-            this.mapper = mapper;
-        }
-
-        @Override
-        public Stream<Doc> apply(TreeCursor cursor) {
-            SmithyBuilder.requiredState("childExtractor", mapper);
-            SmithyBuilder.requiredState("visitor", visitor);
-            return cursor.children()
-                    .flatMap(c -> {
-                        TreeType type = c.getTree().getType();
-                        return type == TreeType.WS || type == TreeType.COMMENT ? Stream.of(c) : mapper.apply(c);
-                    })
-                    .flatMap(c -> {
-                        // If the child extracts WS, then filter it down to just comments.
-                        return c.getTree().getType() == TreeType.WS
-                               ? c.getChildrenByType(TreeType.COMMENT).stream()
-                               : Stream.of(c);
-                    })
-                    .map(visitor)
-                    .filter(doc -> doc != Doc.empty());
-        }
-    }
 }
diff --git a/smithy-syntax/src/main/java/software/amazon/smithy/syntax/FormatVisitor.java b/smithy-syntax/src/main/java/software/amazon/smithy/syntax/FormatVisitor.java
index a9b1a47f6..2f8eadfe4 100644
--- a/smithy-syntax/src/main/java/software/amazon/smithy/syntax/FormatVisitor.java
+++ b/smithy-syntax/src/main/java/software/amazon/smithy/syntax/FormatVisitor.java
@@ -263,15 +263,29 @@ final class FormatVisitor {
             }
 
             case OPERATION_ERRORS: {
-                return skippedComments(cursor, false)
-                        .append(Doc.text("errors: "))
+                // Pull out any comments that come after 'errors' but before the opening '[' so they
+                // can be placed before 'errors: ['
+                Doc comments = Doc.empty();
+                TreeCursor child = cursor.getFirstChild(); // 'errors'
+                if (child.getNextSibling().getTree().getType() == TreeType.WS) {
+                    comments = comments.append(skippedComments(child.getNextSibling(), false));
+                    child = child.getNextSibling(); // skip ws
+                }
+                child = child.getNextSibling(); // ':'
+                if (child.getNextSibling().getTree().getType() == TreeType.WS) {
+                    comments = comments.append(skippedComments(child.getNextSibling(), false));
+                    child = child.getNextSibling();
+                }
+                return comments.append(Doc.text("errors: ")
                         .append(new BracketFormatter()
                                         .open(Formatter.LBRACKET)
                                         .close(Formatter.RBRACKET)
-                                        .extractChildren(cursor, BracketFormatter.extractByType(TreeType.SHAPE_ID,
-                                                                                                this::visit))
+                                        .extractChildren(child, BracketFormatter.extractor(
+                                                this::visit,
+                                                BracketFormatter.byTypeMapper(TreeType.SHAPE_ID),
+                                                BracketFormatter.siblingChildrenSupplier()))
                                         .forceLineBreaks() // always put each error on separate lines.
-                                        .write());
+                                        .write()));
             }
 
             case MIXINS: {
diff --git a/smithy-syntax/src/main/java/software/amazon/smithy/syntax/TreeCursor.java b/smithy-syntax/src/main/java/software/amazon/smithy/syntax/TreeCursor.java
index 1e2536133..3174f64eb 100644
--- a/smithy-syntax/src/main/java/software/amazon/smithy/syntax/TreeCursor.java
+++ b/smithy-syntax/src/main/java/software/amazon/smithy/syntax/TreeCursor.java
@@ -318,6 +318,19 @@ public final class TreeCursor implements FromSourceLocation {
         }
     }
 
+    /**
+     * @return All siblings after this cursor, in order.
+     */
+    public List<TreeCursor> remainingSiblings() {
+        List<TreeCursor> remaining = new ArrayList<>();
+        TreeCursor nextSibling = getNextSibling();
+        while (nextSibling != null) {
+            remaining.add(nextSibling);
+            nextSibling = nextSibling.getNextSibling();
+        }
+        return remaining;
+    }
+
     @Override
     public boolean equals(Object o) {
         if (this == o) {
diff --git a/smithy-utils/src/main/java/software/amazon/smithy/utils/MediaType.java b/smithy-utils/src/main/java/software/amazon/smithy/utils/MediaType.java
index 96492e025..66ff16794 100644
--- a/smithy-utils/src/main/java/software/amazon/smithy/utils/MediaType.java
+++ b/smithy-utils/src/main/java/software/amazon/smithy/utils/MediaType.java
@@ -26,7 +26,7 @@ import java.util.Set;
 
 /**
  * Implements a simple media type parser based on the Content-Type grammar defined in
- * <a href="https://tools.ietf.org/html/rfc7231#section-3.1.1.1">RFC 7231</a>.
+ * <a href="https://tools.ietf.org/html/rfc9110#section-8.3">RFC 9110</a>.
  *
  * <p>The type, subtype, and parameter names are all canonicalized to
  * lowercase strings.
@@ -154,7 +154,7 @@ public final class MediaType {
     }
 
     private static final class Parser extends SimpleParser {
-        // See https://tools.ietf.org/html/rfc7230#section-3.2.6
+        // See https://tools.ietf.org/html/rfc9110#section-5.6.2
         // token          = 1*tchar
         // tchar          = "!" / "#" / "$" / "%" / "&" / "'" / "*"
         //                / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
@@ -198,7 +198,7 @@ public final class MediaType {
         }
 
         private void parse() {
-            // From: https://tools.ietf.org/html/rfc7231#section-3.1.1.1
+            // From: https://tools.ietf.org/html/rfc9110#section-8.3.1
             // The type, subtype, and parameter name tokens are case-insensitive.
             //     media-type = type "/" subtype *( OWS ";" OWS parameter )
             //     type       = token.
@@ -240,7 +240,7 @@ public final class MediaType {
             return sliceFrom(start);
         }
 
-        // See https://tools.ietf.org/html/rfc7230#section-3.2.6
+        // See https://tools.ietf.org/html/rfc9110#section-5.6.4
         // quoted-string  = DQUOTE *( qdtext / quoted-pair ) DQUOTE
         // qdtext         = HTAB / SP /%x21 / %x23-5B / %x5D-7E / obs-text
         // obs-text       = %x80-FF


Test patch:
diff --git a/smithy-aws-apigateway-openapi/src/test/java/software/amazon/smithy/aws/apigateway/openapi/CorsTest.java b/smithy-aws-apigateway-openapi/src/test/java/software/amazon/smithy/aws/apigateway/openapi/CorsTest.java
index dd4caa027..1cd507ecd 100644
--- a/smithy-aws-apigateway-openapi/src/test/java/software/amazon/smithy/aws/apigateway/openapi/CorsTest.java
+++ b/smithy-aws-apigateway-openapi/src/test/java/software/amazon/smithy/aws/apigateway/openapi/CorsTest.java
@@ -112,4 +112,37 @@ public class CorsTest {
 
         Node.assertEquals(result, expectedNode);
     }
+
+    @Test
+    public void withPreflightIntegrationSync() {
+        Model model = Model.assembler(getClass().getClassLoader())
+                .discoverModels(getClass().getClassLoader())
+                .addImport(getClass().getResource("cors-with-multi-request-templates.json"))
+                .assemble()
+                .unwrap();
+        OpenApiConfig config = new OpenApiConfig();
+        config.setService(ShapeId.from("example.smithy#MyService"));
+        config.setSyncCorsPreflightIntegration(true);
+        ObjectNode result = OpenApiConverter.create().config(config).convertToNode(model);
+        Node expectedNode = Node.parse(IoUtils.toUtf8String(
+                getClass().getResourceAsStream("cors-with-preflight-sync.openapi.json")));
+
+        Node.assertEquals(result, expectedNode);
+    }
+
+    @Test
+    public void withoutPreflightIntegrationSync() {
+        Model model = Model.assembler(getClass().getClassLoader())
+                .discoverModels(getClass().getClassLoader())
+                .addImport(getClass().getResource("cors-with-multi-request-templates.json"))
+                .assemble()
+                .unwrap();
+        OpenApiConfig config = new OpenApiConfig();
+        config.setService(ShapeId.from("example.smithy#MyService"));
+        ObjectNode result = OpenApiConverter.create().config(config).convertToNode(model);
+        Node expectedNode = Node.parse(IoUtils.toUtf8String(
+                getClass().getResourceAsStream("cors-without-preflight-sync.openapi.json")));
+
+        Node.assertEquals(result, expectedNode);
+    }
 }
diff --git a/smithy-aws-apigateway-openapi/src/test/resources/software/amazon/smithy/aws/apigateway/openapi/cors-with-multi-request-templates.json b/smithy-aws-apigateway-openapi/src/test/resources/software/amazon/smithy/aws/apigateway/openapi/cors-with-multi-request-templates.json
new file mode 100644
index 000000000..714d3df7d
--- /dev/null
+++ b/smithy-aws-apigateway-openapi/src/test/resources/software/amazon/smithy/aws/apigateway/openapi/cors-with-multi-request-templates.json
@@ -0,0 +1,102 @@
+{
+    "smithy": "2.0",
+    "shapes": {
+        "example.smithy#MyService": {
+            "type": "service",
+            "version": "2006-03-01",
+            "operations": [
+                {
+                    "target": "example.smithy#MockPut"
+                },
+                {
+                    "target": "example.smithy#MockGet"
+                }
+            ],
+            "traits": {
+                "aws.protocols#restJson1": {},
+                "aws.auth#sigv4": {
+                    "name": "myservice"
+                },
+                "smithy.api#cors": {
+                    "origin": "https://www.example.com",
+                    "maxAge": 86400,
+                    "additionalAllowedHeaders": [
+                        "X-Service-Input-Metadata"
+                    ],
+                    "additionalExposedHeaders": [
+                        "X-Service-Output-Metadata"
+                    ]
+                }
+            }
+        },
+        "example.smithy#MockGet": {
+            "type": "operation",
+            "output": {
+                "target": "example.smithy#MockOutput"
+            },
+            "traits": {
+                "aws.apigateway#mockIntegration": {
+                    "passThroughBehavior": "never",
+                    "requestTemplates": {
+                        "application/json": "{\"statusCode\": 200}",
+                        "application/x-www-form-urlencoded": "{\"statusCode\": 200}"
+                    },
+                    "responses": {
+                        "default": {
+                            "statusCode": "200",
+                            "responseTemplates": {
+                                "application/json": "{\"extendedRequestId\": \"$context.extendedRequestId\"}"
+                            }
+                        }
+                    }
+                },
+                "smithy.api#http": {
+                    "code": 200,
+                    "method": "GET",
+                    "uri": "/mock"
+                },
+                "smithy.api#readonly": {}
+            }
+        },
+        "example.smithy#MockPut": {
+            "type": "operation",
+            "output": {
+                "target": "example.smithy#MockOutput"
+            },
+            "traits": {
+                "aws.apigateway#mockIntegration": {
+                    "passThroughBehavior": "never",
+                    "requestTemplates": {
+                        "text/plain": "{\"statusCode\": 200}",
+                        "application/xml": "{\"statusCode\": 200}"
+                    },
+                    "responses": {
+                        "default": {
+                            "statusCode": "200",
+                            "responseTemplates": {
+                                "application/json": "{\"extendedRequestId\": \"$context.extendedRequestId\"}"
+                            }
+                        }
+                    }
+                },
+                "smithy.api#http": {
+                    "code": 201,
+                    "method": "PUT",
+                    "uri": "/mock"
+                },
+                "smithy.api#idempotent": {}
+            }
+        },
+        "example.smithy#MockOutput": {
+            "type": "structure",
+            "members": {
+                "extendedRequestId": {
+                    "target": "smithy.api#String",
+                    "traits": {
+                        "smithy.api#required": {}
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/smithy-aws-apigateway-openapi/src/test/resources/software/amazon/smithy/aws/apigateway/openapi/cors-with-preflight-sync.openapi.json b/smithy-aws-apigateway-openapi/src/test/resources/software/amazon/smithy/aws/apigateway/openapi/cors-with-preflight-sync.openapi.json
new file mode 100644
index 000000000..5f3b8154b
--- /dev/null
+++ b/smithy-aws-apigateway-openapi/src/test/resources/software/amazon/smithy/aws/apigateway/openapi/cors-with-preflight-sync.openapi.json
@@ -0,0 +1,222 @@
+{
+  "openapi": "3.0.2",
+  "info": {
+    "title": "MyService",
+    "version": "2006-03-01"
+  },
+  "paths": {
+    "/mock": {
+      "get": {
+        "operationId": "MockGet",
+        "responses": {
+          "200": {
+            "description": "MockGet 200 response",
+            "headers": {
+              "Access-Control-Allow-Origin": {
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Access-Control-Expose-Headers": {
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/MockGetResponseContent"
+                }
+              }
+            }
+          }
+        },
+        "x-amazon-apigateway-integration": {
+          "requestTemplates": {
+            "application/json": "{\"statusCode\": 200}",
+            "application/x-www-form-urlencoded": "{\"statusCode\": 200}"
+          },
+          "responses": {
+            "default": {
+              "statusCode": "200",
+              "responseTemplates": {
+                "application/json": "{\"extendedRequestId\": \"$context.extendedRequestId\"}"
+              },
+              "responseParameters": {
+                "method.response.header.Access-Control-Allow-Origin": "'https://www.example.com'",
+                "method.response.header.Access-Control-Expose-Headers": "'Content-Length,Content-Type,X-Amzn-Errortype,X-Amzn-Requestid,X-Service-Output-Metadata'"
+              }
+            }
+          },
+          "type": "mock",
+          "passthroughBehavior": "never"
+        }
+      },
+      "options": {
+        "description": "Handles CORS-preflight requests",
+        "operationId": "CorsMock",
+        "responses": {
+          "200": {
+            "description": "Canned response for CORS-preflight requests",
+            "headers": {
+              "Access-Control-Allow-Headers": {
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Access-Control-Allow-Methods": {
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Access-Control-Allow-Origin": {
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Access-Control-Max-Age": {
+                "schema": {
+                  "type": "string"
+                }
+              }
+            }
+          }
+        },
+        "security": [],
+        "tags": [
+          "CORS"
+        ],
+        "x-amazon-apigateway-integration": {
+          "contentHandling": "CONVERT_TO_TEXT",
+          "requestTemplates": {
+            "application/xml": "{\"statusCode\":200}",
+            "application/x-www-form-urlencoded": "{\"statusCode\":200}",
+            "application/json": "{\"statusCode\":200}",
+            "text/plain": "{\"statusCode\":200}"
+          },
+          "responses": {
+            "default": {
+              "responseParameters": {
+                "method.response.header.Access-Control-Max-Age": "'86400'",
+                "method.response.header.Access-Control-Allow-Headers": "'Amz-Sdk-Invocation-Id,Amz-Sdk-Request,Authorization,Date,Host,X-Amz-Content-Sha256,X-Amz-Date,X-Amz-Security-Token,X-Amz-Target,X-Amz-User-Agent,X-Amzn-Trace-Id,X-Service-Input-Metadata'",
+                "method.response.header.Access-Control-Allow-Origin": "'https://www.example.com'",
+                "method.response.header.Access-Control-Allow-Methods": "'GET,PUT'"
+              },
+              "statusCode": "200"
+            }
+          },
+          "type": "mock",
+          "passthroughBehavior": "never"
+        }
+      },
+      "put": {
+        "operationId": "MockPut",
+        "responses": {
+          "201": {
+            "description": "MockPut 201 response",
+            "headers": {
+              "Access-Control-Allow-Origin": {
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Access-Control-Expose-Headers": {
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/MockPutResponseContent"
+                }
+              }
+            }
+          }
+        },
+        "x-amazon-apigateway-integration": {
+          "requestTemplates": {
+            "text/plain": "{\"statusCode\": 200}",
+            "application/xml": "{\"statusCode\": 200}"
+          },
+          "responses": {
+            "default": {
+              "statusCode": "200",
+              "responseTemplates": {
+                "application/json": "{\"extendedRequestId\": \"$context.extendedRequestId\"}"
+              },
+              "responseParameters": {
+                "method.response.header.Access-Control-Allow-Origin": "'https://www.example.com'",
+                "method.response.header.Access-Control-Expose-Headers": "'Content-Length,Content-Type,X-Amzn-Errortype,X-Amzn-Requestid,X-Service-Output-Metadata'"
+              }
+            }
+          },
+          "type": "mock",
+          "passthroughBehavior": "never"
+        }
+      }
+    }
+  },
+  "components": {
+    "schemas": {
+      "MockGetResponseContent": {
+        "type": "object",
+        "properties": {
+          "extendedRequestId": {
+            "type": "string"
+          }
+        },
+        "required": [
+          "extendedRequestId"
+        ]
+      },
+      "MockPutResponseContent": {
+        "type": "object",
+        "properties": {
+          "extendedRequestId": {
+            "type": "string"
+          }
+        },
+        "required": [
+          "extendedRequestId"
+        ]
+      }
+    },
+    "securitySchemes": {
+      "aws.auth.sigv4": {
+        "type": "apiKey",
+        "description": "AWS Signature Version 4 authentication",
+        "name": "Authorization",
+        "in": "header",
+        "x-amazon-apigateway-authtype": "awsSigv4"
+      }
+    }
+  },
+  "security": [
+    {
+      "aws.auth.sigv4": [ ]
+    }
+  ],
+  "x-amazon-apigateway-gateway-responses": {
+    "DEFAULT_4XX": {
+      "responseTemplates": {
+        "application/json": "{\"message\":$context.error.messageString}"
+      },
+      "responseParameters": {
+        "gatewayresponse.header.Access-Control-Allow-Origin": "'https://www.example.com'",
+        "gatewayresponse.header.Access-Control-Expose-Headers": "'X-Service-Output-Metadata'"
+      }
+    },
+    "DEFAULT_5XX": {
+      "responseTemplates": {
+        "application/json": "{\"message\":$context.error.messageString}"
+      },
+      "responseParameters": {
+        "gatewayresponse.header.Access-Control-Allow-Origin": "'https://www.example.com'",
+        "gatewayresponse.header.Access-Control-Expose-Headers": "'X-Service-Output-Metadata'"
+      }
+    }
+  }
+}
diff --git a/smithy-aws-apigateway-openapi/src/test/resources/software/amazon/smithy/aws/apigateway/openapi/cors-without-preflight-sync.openapi.json b/smithy-aws-apigateway-openapi/src/test/resources/software/amazon/smithy/aws/apigateway/openapi/cors-without-preflight-sync.openapi.json
new file mode 100644
index 000000000..2ce6e10fa
--- /dev/null
+++ b/smithy-aws-apigateway-openapi/src/test/resources/software/amazon/smithy/aws/apigateway/openapi/cors-without-preflight-sync.openapi.json
@@ -0,0 +1,219 @@
+{
+  "openapi": "3.0.2",
+  "info": {
+    "title": "MyService",
+    "version": "2006-03-01"
+  },
+  "paths": {
+    "/mock": {
+      "get": {
+        "operationId": "MockGet",
+        "responses": {
+          "200": {
+            "description": "MockGet 200 response",
+            "headers": {
+              "Access-Control-Allow-Origin": {
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Access-Control-Expose-Headers": {
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/MockGetResponseContent"
+                }
+              }
+            }
+          }
+        },
+        "x-amazon-apigateway-integration": {
+          "requestTemplates": {
+            "application/json": "{\"statusCode\": 200}",
+            "application/x-www-form-urlencoded": "{\"statusCode\": 200}"
+          },
+          "responses": {
+            "default": {
+              "statusCode": "200",
+              "responseTemplates": {
+                "application/json": "{\"extendedRequestId\": \"$context.extendedRequestId\"}"
+              },
+              "responseParameters": {
+                "method.response.header.Access-Control-Allow-Origin": "'https://www.example.com'",
+                "method.response.header.Access-Control-Expose-Headers": "'Content-Length,Content-Type,X-Amzn-Errortype,X-Amzn-Requestid,X-Service-Output-Metadata'"
+              }
+            }
+          },
+          "type": "mock",
+          "passthroughBehavior": "never"
+        }
+      },
+      "options": {
+        "description": "Handles CORS-preflight requests",
+        "operationId": "CorsMock",
+        "responses": {
+          "200": {
+            "description": "Canned response for CORS-preflight requests",
+            "headers": {
+              "Access-Control-Allow-Headers": {
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Access-Control-Allow-Methods": {
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Access-Control-Allow-Origin": {
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Access-Control-Max-Age": {
+                "schema": {
+                  "type": "string"
+                }
+              }
+            }
+          }
+        },
+        "security": [],
+        "tags": [
+          "CORS"
+        ],
+        "x-amazon-apigateway-integration": {
+          "contentHandling": "CONVERT_TO_TEXT",
+          "requestTemplates": {
+            "application/json": "{\"statusCode\":200}"
+          },
+          "responses": {
+            "default": {
+              "responseParameters": {
+                "method.response.header.Access-Control-Max-Age": "'86400'",
+                "method.response.header.Access-Control-Allow-Headers": "'Amz-Sdk-Invocation-Id,Amz-Sdk-Request,Authorization,Date,Host,X-Amz-Content-Sha256,X-Amz-Date,X-Amz-Security-Token,X-Amz-Target,X-Amz-User-Agent,X-Amzn-Trace-Id,X-Service-Input-Metadata'",
+                "method.response.header.Access-Control-Allow-Origin": "'https://www.example.com'",
+                "method.response.header.Access-Control-Allow-Methods": "'GET,PUT'"
+              },
+              "statusCode": "200"
+            }
+          },
+          "type": "mock",
+          "passthroughBehavior": "when_no_match"
+        }
+      },
+      "put": {
+        "operationId": "MockPut",
+        "responses": {
+          "201": {
+            "description": "MockPut 201 response",
+            "headers": {
+              "Access-Control-Allow-Origin": {
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Access-Control-Expose-Headers": {
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/MockPutResponseContent"
+                }
+              }
+            }
+          }
+        },
+        "x-amazon-apigateway-integration": {
+          "requestTemplates": {
+            "text/plain": "{\"statusCode\": 200}",
+            "application/xml": "{\"statusCode\": 200}"
+          },
+          "responses": {
+            "default": {
+              "statusCode": "200",
+              "responseTemplates": {
+                "application/json": "{\"extendedRequestId\": \"$context.extendedRequestId\"}"
+              },
+              "responseParameters": {
+                "method.response.header.Access-Control-Allow-Origin": "'https://www.example.com'",
+                "method.response.header.Access-Control-Expose-Headers": "'Content-Length,Content-Type,X-Amzn-Errortype,X-Amzn-Requestid,X-Service-Output-Metadata'"
+              }
+            }
+          },
+          "type": "mock",
+          "passthroughBehavior": "never"
+        }
+      }
+    }
+  },
+  "components": {
+    "schemas": {
+      "MockGetResponseContent": {
+        "type": "object",
+        "properties": {
+          "extendedRequestId": {
+            "type": "string"
+          }
+        },
+        "required": [
+          "extendedRequestId"
+        ]
+      },
+      "MockPutResponseContent": {
+        "type": "object",
+        "properties": {
+          "extendedRequestId": {
+            "type": "string"
+          }
+        },
+        "required": [
+          "extendedRequestId"
+        ]
+      }
+    },
+    "securitySchemes": {
+      "aws.auth.sigv4": {
+        "type": "apiKey",
+        "description": "AWS Signature Version 4 authentication",
+        "name": "Authorization",
+        "in": "header",
+        "x-amazon-apigateway-authtype": "awsSigv4"
+      }
+    }
+  },
+  "security": [
+    {
+      "aws.auth.sigv4": [ ]
+    }
+  ],
+  "x-amazon-apigateway-gateway-responses": {
+    "DEFAULT_4XX": {
+      "responseTemplates": {
+        "application/json": "{\"message\":$context.error.messageString}"
+      },
+      "responseParameters": {
+        "gatewayresponse.header.Access-Control-Allow-Origin": "'https://www.example.com'",
+        "gatewayresponse.header.Access-Control-Expose-Headers": "'X-Service-Output-Metadata'"
+      }
+    },
+    "DEFAULT_5XX": {
+      "responseTemplates": {
+        "application/json": "{\"message\":$context.error.messageString}"
+      },
+      "responseParameters": {
+        "gatewayresponse.header.Access-Control-Allow-Origin": "'https://www.example.com'",
+        "gatewayresponse.header.Access-Control-Expose-Headers": "'X-Service-Output-Metadata'"
+      }
+    }
+  }
+}
diff --git a/smithy-aws-iam-traits/src/test/resources/software/amazon/smithy/aws/iam/traits/errorfiles/iam-resources/duplicate-iam-resources-name.errors b/smithy-aws-iam-traits/src/test/resources/software/amazon/smithy/aws/iam/traits/errorfiles/iam-resources/duplicate-iam-resources-name.errors
new file mode 100644
index 000000000..976e0c872
--- /dev/null
+++ b/smithy-aws-iam-traits/src/test/resources/software/amazon/smithy/aws/iam/traits/errorfiles/iam-resources/duplicate-iam-resources-name.errors
@@ -0,0 +1,1 @@
+[ERROR] smithy.example#MyService: Multiple IAM resources defined with the same IAM resource name is not allowed in a service closure, but found multiple resources named `Beer` in the service `smithy.example#MyService`: [`smithy.example#BadIamResourceName1`, `smithy.example#BadIamResourceName2`, `smithy.example#Beer`] | IamResourceTraitConflictingName
diff --git a/smithy-aws-iam-traits/src/test/resources/software/amazon/smithy/aws/iam/traits/errorfiles/iam-resources/duplicate-iam-resources-name.smithy b/smithy-aws-iam-traits/src/test/resources/software/amazon/smithy/aws/iam/traits/errorfiles/iam-resources/duplicate-iam-resources-name.smithy
new file mode 100644
index 000000000..9833e42db
--- /dev/null
+++ b/smithy-aws-iam-traits/src/test/resources/software/amazon/smithy/aws/iam/traits/errorfiles/iam-resources/duplicate-iam-resources-name.smithy
@@ -0,0 +1,39 @@
+$version: "2"
+namespace smithy.example
+
+use aws.api#arn
+
+@aws.api#service(sdkId: "My")
+@aws.iam#defineConditionKeys("foo:baz": {type: "String", documentation: "Foo baz"})
+service MyService {
+    version: "2019-02-20",
+    resources: [
+        BadIamResourceName1,
+        BadIamResourceName2,
+        Beer,
+        ShouldNotThrowAnErrorFirst,
+        ShouldNotThrowAnErrorSecond
+    ]
+}
+
+resource Beer {}
+
+@aws.iam#iamResource(name: "Beer")
+resource BadIamResourceName1 {}
+
+@aws.iam#iamResource(name: "Beer")
+resource BadIamResourceName2 {}
+
+@aws.iam#iamResource(name: "shouldNotThrowErrorSecond")
+resource ShouldNotThrowAnErrorFirst {
+    identifiers: {
+        beerId: String
+    }
+}
+
+@aws.iam#iamResource(name: "shouldNotThrowErrorFirst")
+resource ShouldNotThrowAnErrorSecond {
+    identifiers: {
+        arn: String
+    }
+}
diff --git a/smithy-aws-protocol-tests/model/restJson1/defaults.smithy b/smithy-aws-protocol-tests/model/restJson1/defaults.smithy
new file mode 100644
index 000000000..f14363293
--- /dev/null
+++ b/smithy-aws-protocol-tests/model/restJson1/defaults.smithy
@@ -0,0 +1,460 @@
+$version: "2.0"
+
+namespace aws.protocoltests.restjson
+
+use aws.protocols#restJson1
+use smithy.test#httpRequestTests
+use smithy.test#httpResponseTests
+
+apply OperationWithDefaults @httpRequestTests([
+    {
+        id: "RestJsonClientPopulatesDefaultValuesInInput"
+        documentation: "Client populates default values in input."
+        appliesTo: "client"
+        tags: ["defaults"]
+        protocol: restJson1
+        method: "POST"
+        bodyMediaType: "application/json"
+        uri: "/OperationWithDefaults"
+        headers: {"Content-Type": "application/json"}
+        body: """
+            {
+                "defaults": {
+                    "defaultString": "hi",
+                    "defaultBoolean": true,
+                    "defaultList": [],
+                    "defaultDocumentMap": {},
+                    "defaultDocumentString": "hi",
+                    "defaultDocumentBoolean": true,
+                    "defaultDocumentList": [],
+                    "defaultTimestamp": 0,
+                    "defaultBlob": "YWJj",
+                    "defaultByte": 1,
+                    "defaultShort": 1,
+                    "defaultInteger": 10,
+                    "defaultLong": 100,
+                    "defaultFloat": 1.0,
+                    "defaultDouble": 1.0,
+                    "defaultMap": {},
+                    "defaultEnum": "FOO",
+                    "defaultIntEnum": 1,
+                    "emptyString": "",
+                    "falseBoolean": false,
+                    "emptyBlob": "",
+                    "zeroByte": 0,
+                    "zeroShort": 0,
+                    "zeroInteger": 0,
+                    "zeroLong": 0,
+                    "zeroFloat": 0.0,
+                    "zeroDouble": 0.0
+                }
+            }"""
+        params: {
+            defaults: {}
+        }
+    }
+    {
+        id: "RestJsonClientSkipsTopLevelDefaultValuesInInput"
+        documentation: "Client skips top level default values in input."
+        appliesTo: "client"
+        tags: ["defaults"]
+        protocol: restJson1
+        method: "POST"
+        bodyMediaType: "application/json"
+        uri: "/OperationWithDefaults"
+        headers: {"Content-Type": "application/json"}
+        body: """
+            {
+            }"""
+        params: {
+        }
+    }
+    {
+        id: "RestJsonClientUsesExplicitlyProvidedMemberValuesOverDefaults"
+        documentation: "Client uses explicitly provided member values over defaults"
+        appliesTo: "client"
+        tags: ["defaults"]
+        protocol: restJson1
+        method: "POST"
+        bodyMediaType: "application/json"
+        uri: "/OperationWithDefaults"
+        headers: {"Content-Type": "application/json"}
+        params: {
+            defaults: {
+                defaultString: "bye"
+                defaultBoolean: true
+                defaultList: ["a"]
+                defaultDocumentMap: {name: "Jack"}
+                defaultDocumentString: "bye"
+                defaultDocumentBoolean: true
+                defaultDocumentList: ["b"]
+                defaultNullDocument: "notNull"
+                defaultTimestamp: 1
+                defaultBlob: "hi"
+                defaultByte: 2
+                defaultShort: 2
+                defaultInteger: 20
+                defaultLong: 200
+                defaultFloat: 2.0
+                defaultDouble: 2.0
+                defaultMap: {name: "Jack"}
+                defaultEnum: "BAR"
+                defaultIntEnum: 2
+                emptyString: "foo"
+                falseBoolean: true
+                emptyBlob: "hi"
+                zeroByte: 1
+                zeroShort: 1
+                zeroInteger: 1
+                zeroLong: 1
+                zeroFloat: 1.0
+                zeroDouble: 1.0
+            }
+        }
+        body: """
+            {
+                "defaults": {
+                    "defaultString": "bye",
+                    "defaultBoolean": true,
+                    "defaultList": ["a"],
+                    "defaultDocumentMap": {"name": "Jack"},
+                    "defaultDocumentString": "bye",
+                    "defaultDocumentBoolean": true,
+                    "defaultDocumentList": ["b"],
+                    "defaultNullDocument": "notNull",
+                    "defaultTimestamp": 1,
+                    "defaultBlob": "aGk=",
+                    "defaultByte": 2,
+                    "defaultShort": 2,
+                    "defaultInteger": 20,
+                    "defaultLong": 200,
+                    "defaultFloat": 2.0,
+                    "defaultDouble": 2.0,
+                    "defaultMap": {"name": "Jack"},
+                    "defaultEnum": "BAR",
+                    "defaultIntEnum": 2,
+                    "emptyString": "foo",
+                    "falseBoolean": true,
+                    "emptyBlob": "aGk=",
+                    "zeroByte": 1,
+                    "zeroShort": 1,
+                    "zeroInteger": 1,
+                    "zeroLong": 1,
+                    "zeroFloat": 1.0,
+                    "zeroDouble": 1.0
+                }
+            }"""
+    }
+    {
+        id: "RestJsonServerPopulatesDefaultsWhenMissingInRequestBody"
+        documentation: "Server populates default values when missing in request body."
+        appliesTo: "server"
+        tags: ["defaults"]
+        protocol: restJson1
+        method: "POST"
+        bodyMediaType: "application/json"
+        uri: "/OperationWithDefaults"
+        headers: {"Content-Type": "application/json"}
+        body: """
+            {
+            "defaults": {}
+            }"""
+        params: {
+            defaults: {
+                defaultString: "hi"
+                defaultBoolean: true
+                defaultList: []
+                defaultDocumentMap: {}
+                defaultDocumentString: "hi"
+                defaultDocumentBoolean: true
+                defaultDocumentList: []
+                defaultTimestamp: 0
+                defaultBlob: "abc"
+                defaultByte: 1
+                defaultShort: 1
+                defaultInteger: 10
+                defaultLong: 100
+                defaultFloat: 1.0
+                defaultDouble: 1.0
+                defaultMap: {}
+                defaultEnum: "FOO"
+                defaultIntEnum: 1
+                emptyString: ""
+                falseBoolean: false
+                emptyBlob: ""
+                zeroByte: 0
+                zeroShort: 0
+                zeroInteger: 0
+                zeroLong: 0
+                zeroFloat: 0.0
+                zeroDouble: 0.0
+            },
+            topLevelDefault: "hi"
+            otherTopLevelDefault: 0
+        }
+    }
+    {
+        id: "RestJsonClientUsesExplicitlyProvidedValuesInTopLevel"
+        documentation: "Any time a value is provided for a member in the top level of input, it is used, regardless of if its the default."
+        appliesTo: "client"
+        tags: ["defaults"]
+        protocol: restJson1
+        method: "POST"
+        bodyMediaType: "application/json"
+        uri: "/OperationWithDefaults"
+        headers: {"Content-Type": "application/json"}
+        body: """
+            {
+                "topLevelDefault": "hi",
+                "otherTopLevelDefault": 0
+            }"""
+        params: {
+            topLevelDefault: "hi"
+            otherTopLevelDefault: 0
+        }
+    }
+    {
+        id: "RestJsonClientIgnoresNonTopLevelDefaultsOnMembersWithClientOptional"
+        documentation: "Typically, non top-level members would have defaults filled in, but if they have the clientOptional trait, the defaults should be ignored."
+        appliesTo: "client"
+        tags: ["defaults"]
+        protocol: restJson1
+        method: "POST"
+        bodyMediaType: "application/json"
+        uri: "/OperationWithDefaults"
+        headers: {"Content-Type": "application/json"}
+        body: """
+            {
+                "clientOptionalDefaults": {}
+            }"""
+        params: {
+            clientOptionalDefaults: {}
+        }
+    }
+])
+
+apply OperationWithDefaults @httpResponseTests([
+    {
+        id: "RestJsonClientPopulatesDefaultsValuesWhenMissingInResponse"
+        documentation: "Client populates default values when missing in response."
+        appliesTo: "client"
+        tags: ["defaults"]
+        protocol: restJson1
+        code: 200
+        bodyMediaType: "application/json"
+        headers: {"Content-Type": "application/json"}
+        body: "{}"
+        params: {
+            defaultString: "hi"
+            defaultBoolean: true
+            defaultList: []
+            defaultDocumentMap: {}
+            defaultDocumentString: "hi"
+            defaultDocumentBoolean: true
+            defaultDocumentList: []
+            defaultTimestamp: 0
+            defaultBlob: "abc"
+            defaultByte: 1
+            defaultShort: 1
+            defaultInteger: 10
+            defaultLong: 100
+            defaultFloat: 1.0
+            defaultDouble: 1.0
+            defaultMap: {}
+            defaultEnum: "FOO"
+            defaultIntEnum: 1
+            emptyString: ""
+            falseBoolean: false
+            emptyBlob: ""
+            zeroByte: 0
+            zeroShort: 0
+            zeroInteger: 0
+            zeroLong: 0
+            zeroFloat: 0.0
+            zeroDouble: 0.0
+        }
+    }
+    {
+        id: "RestJsonClientIgnoresDefaultValuesIfMemberValuesArePresentInResponse"
+        documentation: "Client ignores default values if member values are present in the response."
+        appliesTo: "client"
+        tags: ["defaults"]
+        protocol: restJson1
+        code: 200
+        bodyMediaType: "application/json"
+        headers: {"Content-Type": "application/json"}
+        body: """
+            {
+                "defaultString": "bye",
+                "defaultBoolean": false,
+                "defaultList": ["a"],
+                "defaultDocumentMap": {"name": "Jack"},
+                "defaultDocumentString": "bye",
+                "defaultDocumentBoolean": false,
+                "defaultDocumentList": ["b"],
+                "defaultNullDocument": "notNull",
+                "defaultTimestamp": 2,
+                "defaultBlob": "aGk=",
+                "defaultByte": 2,
+                "defaultShort": 2,
+                "defaultInteger": 20,
+                "defaultLong": 200,
+                "defaultFloat": 2.0,
+                "defaultDouble": 2.0,
+                "defaultMap": {"name": "Jack"},
+                "defaultEnum": "BAR",
+                "defaultIntEnum": 2,
+                "emptyString": "foo",
+                "falseBoolean": true,
+                "emptyBlob": "aGk=",
+                "zeroByte": 1,
+                "zeroShort": 1,
+                "zeroInteger": 1,
+                "zeroLong": 1,
+                "zeroFloat": 1.0,
+                "zeroDouble": 1.0
+            }"""
+        params: {
+            defaultString: "bye"
+            defaultBoolean: false
+            defaultList: ["a"]
+            defaultDocumentMap: {name: "Jack"}
+            defaultDocumentString: "bye"
+            defaultDocumentBoolean: false
+            defaultDocumentList: ["b"]
+            defaultNullDocument: "notNull"
+            defaultTimestamp: 1
+            defaultBlob: "hi"
+            defaultByte: 2
+            defaultShort: 2
+            defaultInteger: 20
+            defaultLong: 200
+            defaultFloat: 2.0
+            defaultDouble: 2.0
+            defaultMap: {name: "Jack"}
+            defaultEnum: "BAR"
+            defaultIntEnum: 2
+            emptyString: "foo"
+            falseBoolean: true
+            emptyBlob: "hi"
+            zeroByte: 1
+            zeroShort: 1
+            zeroInteger: 1
+            zeroLong: 1
+            zeroFloat: 1.0
+            zeroDouble: 1.0
+        }
+    }
+    {
+        id: "RestJsonServerPopulatesDefaultsInResponseWhenMissingInParams"
+        documentation: "Server populates default values in response when missing in params."
+        appliesTo: "server"
+        tags: ["defaults"]
+        protocol: restJson1
+        code: 200
+        bodyMediaType: "application/json"
+        headers: {"Content-Type": "application/json"}
+        body: """
+            {
+                "defaultString": "hi",
+                "defaultBoolean": true,
+                "defaultList": [],
+                "defaultDocumentMap": {},
+                "defaultDocumentString": "hi",
+                "defaultDocumentBoolean": true,
+                "defaultDocumentList": [],
+                "defaultTimestamp": 0,
+                "defaultBlob": "YWJj",
+                "defaultByte": 1,
+                "defaultShort": 1,
+                "defaultInteger": 10,
+                "defaultLong": 100,
+                "defaultFloat": 1.0,
+                "defaultDouble": 1.0,
+                "defaultMap": {},
+                "defaultEnum": "FOO",
+                "defaultIntEnum": 1,
+                "emptyString": "",
+                "falseBoolean": false,
+                "emptyBlob": "",
+                "zeroByte": 0,
+                "zeroShort": 0,
+                "zeroInteger": 0,
+                "zeroLong": 0,
+                "zeroFloat": 0.0,
+                "zeroDouble": 0.0
+            }"""
+        params: {}
+    }
+])
+
+@http(uri: "/OperationWithDefaults", method: "POST")
+operation OperationWithDefaults {
+    input := {
+        defaults: Defaults
+        clientOptionalDefaults: ClientOptionalDefaults
+        topLevelDefault: String = "hi" // Client should ignore default values in input shape
+        otherTopLevelDefault: Integer = 0
+    }
+
+    output := with [DefaultsMixin] {}
+}
+
+structure Defaults with [DefaultsMixin] {}
+
+structure ClientOptionalDefaults {
+    @clientOptional
+    member: Integer = 0
+}
+
+@mixin
+structure DefaultsMixin {
+    defaultString: String = "hi"
+    defaultBoolean: Boolean = true
+    defaultList: TestStringList = []
+    defaultDocumentMap: Document = {}
+    defaultDocumentString: Document = "hi"
+    defaultDocumentBoolean: Document = true
+    defaultDocumentList: Document = []
+    defaultNullDocument: Document = null
+    defaultTimestamp: Timestamp = 0
+    defaultBlob: Blob = "abc"
+    defaultByte: Byte = 1
+    defaultShort: Short = 1
+    defaultInteger: Integer = 10
+    defaultLong: Long = 100
+    defaultFloat: Float = 1.0
+    defaultDouble: Double = 1.0
+    defaultMap: TestStringMap = {}
+    defaultEnum: TestEnum = "FOO"
+    defaultIntEnum: TestIntEnum = 1
+    emptyString: String = ""
+    falseBoolean: Boolean = false
+    emptyBlob: Blob = ""
+    zeroByte: Byte = 0
+    zeroShort: Short = 0
+    zeroInteger: Integer = 0
+    zeroLong: Long = 0
+    zeroFloat: Float = 0.0
+    zeroDouble: Double = 0.0
+}
+
+list TestStringList {
+    member: String
+}
+
+map TestStringMap {
+    key: String
+    value: String
+}
+
+enum TestEnum {
+    FOO
+    BAR
+    BAZ
+}
+
+intEnum TestIntEnum {
+    ONE = 1
+    TWO = 2
+}
\ No newline at end of file
diff --git a/smithy-aws-protocol-tests/model/restJson1/main.smithy b/smithy-aws-protocol-tests/model/restJson1/main.smithy
index e5ae6f979..10c35886d 100644
--- a/smithy-aws-protocol-tests/model/restJson1/main.smithy
+++ b/smithy-aws-protocol-tests/model/restJson1/main.smithy
@@ -152,5 +152,9 @@ service RestJson {
 
         // requestCompression trait tests
         PutWithContentEncoding
+
+        // defaults
+        OperationWithDefaults
+        OperationWithNestedStructure
     ]
 }
diff --git a/smithy-aws-protocol-tests/model/restJson1/malformedRequests/malformed-union.smithy b/smithy-aws-protocol-tests/model/restJson1/malformedRequests/malformed-union.smithy
index cd0ca8cd4..ab4571cdb 100644
--- a/smithy-aws-protocol-tests/model/restJson1/malformedRequests/malformed-union.smithy
+++ b/smithy-aws-protocol-tests/model/restJson1/malformedRequests/malformed-union.smithy
@@ -78,6 +78,28 @@ apply MalformedUnion @httpMalformedRequestTests([
             }
         }
     },
+    {
+        id: "RestJsonMalformedUnionEmptyObjectNoFieldsSet",
+        documentation: """
+            When the union is an empty object, it has no fields set, so the
+            response should be a 400 SerializationException.""",
+        protocol: restJson1,
+        request: {
+            method: "POST",
+            uri: "/MalformedUnion",
+            body: """
+                { "union" : {  } }""",
+            headers: {
+                "content-type": "application/json"
+            }
+        },
+        response: {
+            code: 400,
+            headers: {
+                "x-amzn-errortype": "SerializationException"
+            }
+        }
+    },
     {
         id: "RestJsonMalformedUnionValueIsArray",
         documentation: """
diff --git a/smithy-aws-protocol-tests/model/restJson1/nested-defaults.smithy b/smithy-aws-protocol-tests/model/restJson1/nested-defaults.smithy
new file mode 100644
index 000000000..bba92f85e
--- /dev/null
+++ b/smithy-aws-protocol-tests/model/restJson1/nested-defaults.smithy
@@ -0,0 +1,409 @@
+$version: "2.0"
+
+namespace aws.protocoltests.restjson
+
+use aws.protocols#restJson1
+use smithy.test#httpRequestTests
+use smithy.test#httpResponseTests
+
+apply OperationWithNestedStructure @httpRequestTests([
+    {
+        id: "RestJsonClientPopulatesNestedDefaultValuesWhenMissing"
+        documentation: "Client populates nested default values when missing."
+        appliesTo: "client"
+        tags: ["defaults"]
+        protocol: restJson1
+        method: "POST"
+        bodyMediaType: "application/json"
+        uri: "/OperationWithNestedStructure"
+        headers: {"Content-Type": "application/json"}
+        body: """
+            {
+                "topLevel": {
+                    "dialog": {
+                        "language": "en",
+                        "greeting": "hi"
+                    },
+                    "dialogList": [
+                        {
+                            "greeting": "hi"
+                        },
+                        {
+                            "greeting": "hi",
+                            "farewell": {
+                                "phrase": "bye"
+                            }
+                        },
+                        {
+                            "language": "it",
+                            "greeting": "ciao",
+                            "farewell": {
+                                "phrase": "arrivederci"
+                            }
+                        }
+                    ],
+                    "dialogMap": {
+                        "emptyDialog": {
+                            "greeting": "hi"
+                        },
+                        "partialEmptyDialog": {
+                            "language": "en",
+                            "greeting": "hi",
+                            "farewell": {
+                                "phrase": "bye"
+                            }
+                        },
+                        "nonEmptyDialog": {
+                            "greeting": "konnichiwa",
+                            "farewell": {
+                                "phrase": "sayonara"
+                            }
+                        }
+                    }
+                }
+            }"""
+        params: {
+            "topLevel": {
+                "dialog": {
+                    "language": "en"
+                },
+                "dialogList": [
+                    {
+                    },
+                    {
+                        "farewell": {}
+                    },
+                    {
+                        "language": "it",
+                        "greeting": "ciao",
+                        "farewell": {
+                            "phrase": "arrivederci"
+                        }
+                    }
+                ],
+                "dialogMap": {
+                    "emptyDialog": {
+                    },
+                    "partialEmptyDialog": {
+                        "language": "en",
+                        "farewell": {}
+                    },
+                    "nonEmptyDialog": {
+                        "greeting": "konnichiwa",
+                        "farewell": {
+                            "phrase": "sayonara"
+                        }
+                    }
+                }
+            }
+        }
+    }
+    {
+        id: "RestJsonServerPopulatesNestedDefaultsWhenMissingInRequestBody"
+        documentation: "Server populates nested default values when missing in request body."
+        appliesTo: "server"
+        tags: ["defaults"]
+        protocol: restJson1
+        method: "POST"
+        bodyMediaType: "application/json"
+        uri: "/OperationWithNestedStructure"
+        headers: {"Content-Type": "application/json"}
+        body: """
+            {
+                "topLevel": {
+                    "dialog": {
+                        "language": "en"
+                    },
+                    "dialogList": [
+                        {
+                        },
+                        {
+                            "farewell": {}
+                        },
+                        {
+                            "language": "it",
+                            "greeting": "ciao",
+                            "farewell": {
+                                "phrase": "arrivederci"
+                            }
+                        }
+                    ],
+                    "dialogMap": {
+                        "emptyDialog": {
+                        },
+                        "partialEmptyDialog": {
+                            "language": "en",
+                            "farewell": {}
+                        },
+                        "nonEmptyDialog": {
+                            "greeting": "konnichiwa",
+                            "farewell": {
+                                "phrase": "sayonara"
+                            }
+                        }
+                    }
+                }
+            }"""
+        params: {
+            "topLevel": {
+                "dialog": {
+                    "language": "en"
+                    "greeting": "hi",
+                }
+                "dialogList": [
+                    {
+                        "greeting": "hi",
+                    },
+                    {
+                        "greeting": "hi",
+                        "farewell": {
+                            "phrase": "bye",
+                        }
+                    },
+                    {
+                        "language": "it",
+                        "greeting": "ciao",
+                        "farewell": {
+                            "phrase": "arrivederci"
+                        }
+                    }
+                ],
+                "dialogMap": {
+                    "emptyDialog": {
+                        "greeting": "hi",
+                    },
+                    "partialEmptyDialog": {
+                        "language": "en",
+                        "greeting": "hi",
+                        "farewell": {
+                            "phrase": "bye",
+                        }
+                    },
+                    "nonEmptyDialog": {
+                        "greeting": "konnichiwa",
+                        "farewell": {
+                            "phrase": "sayonara"
+                        }
+                    }
+                }
+            }
+        }
+    }
+])
+
+apply OperationWithNestedStructure @httpResponseTests([
+    {
+        id: "RestJsonClientPopulatesNestedDefaultsWhenMissingInResponseBody"
+        documentation: "Client populates nested default values when missing in response body."
+        appliesTo: "client"
+        tags: ["defaults"]
+        protocol: restJson1
+        code: 200
+        bodyMediaType: "application/json"
+        headers: {"Content-Type": "application/json"}
+        body: """
+            {
+                "dialog": {
+                    "language": "en"
+                },
+                "dialogList": [
+                    {
+                    },
+                    {
+                        "farewell": {}
+                    },
+                    {
+                        "language": "it",
+                        "greeting": "ciao",
+                        "farewell": {
+                            "phrase": "arrivederci"
+                        }
+                    }
+                ],
+                "dialogMap": {
+                    "emptyDialog": {
+                    },
+                    "partialEmptyDialog": {
+                        "language": "en",
+                        "farewell": {}
+                    },
+                    "nonEmptyDialog": {
+                        "greeting": "konnichiwa",
+                        "farewell": {
+                            "phrase": "sayonara"
+                        }
+                    }
+                }
+            }"""
+        params: {
+            "dialog": {
+                "language": "en"
+                "greeting": "hi",
+            }
+            "dialogList": [
+                {
+                    "greeting": "hi",
+                },
+                {
+                    "greeting": "hi",
+                    "farewell": {
+                        "phrase": "bye",
+                    }
+                },
+                {
+                    "language": "it",
+                    "greeting": "ciao",
+                    "farewell": {
+                        "phrase": "arrivederci"
+                    }
+                }
+            ],
+            "dialogMap": {
+                "emptyDialog": {
+                    "greeting": "hi",
+                },
+                "partialEmptyDialog": {
+                    "language": "en",
+                    "greeting": "hi",
+                    "farewell": {
+                        "phrase": "bye",
+                    }
+                },
+                "nonEmptyDialog": {
+                    "greeting": "konnichiwa",
+                    "farewell": {
+                        "phrase": "sayonara"
+                    }
+                }
+            }
+        }
+    }
+    {
+        id: "RestJsonServerPopulatesNestedDefaultValuesWhenMissingInInResponseParams"
+        documentation: "Server populates nested default values when missing in response params."
+        appliesTo: "server"
+        tags: ["defaults"]
+        protocol: restJson1
+        code: 200
+        bodyMediaType: "application/json"
+        headers: {"Content-Type": "application/json"}
+        body: """
+            {
+                "dialog": {
+                    "language": "en",
+                    "greeting": "hi"
+                },
+                "dialogList": [
+                    {
+                        "greeting": "hi"
+                    },
+                    {
+                        "greeting": "hi",
+                        "farewell": {
+                            "phrase": "bye"
+                        }
+                    },
+                    {
+                        "language": "it",
+                        "greeting": "ciao",
+                        "farewell": {
+                            "phrase": "arrivederci"
+                        }
+                    }
+                ],
+                "dialogMap": {
+                    "emptyDialog": {
+                        "greeting": "hi"
+                    },
+                    "partialEmptyDialog": {
+                        "language": "en",
+                        "greeting": "hi",
+                        "farewell": {
+                            "phrase": "bye"
+                        }
+                    },
+                    "nonEmptyDialog": {
+                        "greeting": "konnichiwa",
+                        "farewell": {
+                            "phrase": "sayonara"
+                        }
+                    }
+                }
+            }"""
+        params: {
+            "dialog": {
+                "language": "en"
+            },
+            "dialogList": [
+                {
+                },
+                {
+                    "farewell": {}
+                },
+                {
+                    "language": "it",
+                    "greeting": "ciao",
+                    "farewell": {
+                        "phrase": "arrivederci"
+                    }
+                }
+            ],
+            "dialogMap": {
+                "emptyDialog": {
+                },
+                "partialEmptyDialog": {
+                    "language": "en",
+                    "farewell": {}
+                },
+                "nonEmptyDialog": {
+                    "greeting": "konnichiwa",
+                    "farewell": {
+                        "phrase": "sayonara"
+                    }
+                }
+            }
+        }
+    }
+])
+
+@http(uri: "/OperationWithNestedStructure", method: "POST")
+operation OperationWithNestedStructure {
+    input := {
+        @required
+        topLevel: TopLevel
+    }
+
+    output := with [NestedDefaultsMixin] {
+    }
+}
+
+structure TopLevel with [NestedDefaultsMixin] {
+
+}
+
+@mixin
+structure NestedDefaultsMixin {
+    @required
+    dialog: Dialog
+    dialogList: DialogList = []
+    dialogMap: DialogMap = {}
+}
+
+structure Dialog {
+    language: String
+    greeting: String = "hi"
+    farewell: Farewell
+}
+
+structure Farewell {
+    phrase: String = "bye"
+}
+
+list DialogList {
+    member: Dialog
+}
+
+map DialogMap {
+    key: String
+    value: Dialog
+}
\ No newline at end of file
diff --git a/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/ChangedEnumTraitTest.java b/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/ChangedEnumTraitTest.java
index a1d6fc755..9907f615a 100644
--- a/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/ChangedEnumTraitTest.java
+++ b/smithy-diff/src/test/java/software/amazon/smithy/diff/evaluators/ChangedEnumTraitTest.java
@@ -47,6 +47,7 @@ public class ChangedEnumTraitTest {
                 .addTrait(EnumTrait.builder()
                         .addEnum(EnumDefinition.builder().value("foo").build())
                         .addEnum(EnumDefinition.builder().value("baz").build())
+                        .addEnum(EnumDefinition.builder().value("bar").build())
                         .sourceLocation(source)
                         .build())
                 .build();
@@ -54,9 +55,14 @@ public class ChangedEnumTraitTest {
         Model modelB = Model.assembler().addShape(s2).assemble().unwrap();
         List<ValidationEvent> events = ModelDiff.compare(modelA, modelB);
 
-        assertThat(TestHelper.findEvents(events, "ChangedEnumTrait").size(), equalTo(1));
-        assertThat(TestHelper.findEvents(events, "ChangedEnumTrait").get(0).getSeverity(), equalTo(Severity.NOTE));
-        assertThat(TestHelper.findEvents(events, "ChangedEnumTrait").get(0).getSourceLocation(), equalTo(source));
+        assertThat(TestHelper.findEvents(events, "ChangedEnumTrait").size(), equalTo(2));
+        assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.Appended").size(), equalTo(2));
+        assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.Appended.1").size(), equalTo(1));
+        assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.Appended.2").size(), equalTo(1));
+        assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.Appended").stream()
+                .allMatch(e -> e.getSeverity() == Severity.NOTE), equalTo(true));
+        assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.Appended").stream()
+                .allMatch(e -> source.equals(e.getSourceLocation())), equalTo(true));
     }
 
     @Test
@@ -86,9 +92,9 @@ public class ChangedEnumTraitTest {
                 equalTo(Severity.ERROR));
         assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.NameChanged.0").get(0).getSourceLocation(),
                 equalTo(source));
-        assertThat(TestHelper.findEvents(events, "ChangedEnumTrait").get(1).getSeverity(),
+        assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.Appended.1").get(0).getSeverity(),
                 equalTo(Severity.NOTE));
-        assertThat(TestHelper.findEvents(events, "ChangedEnumTrait").get(1).getSourceLocation(),
+        assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.Appended.1").get(0).getSourceLocation(),
                 equalTo(source));
     }
 
@@ -115,10 +121,10 @@ public class ChangedEnumTraitTest {
         Model modelB = Model.assembler().addShape(s2).assemble().unwrap();
         List<ValidationEvent> events = ModelDiff.compare(modelA, modelB);
 
-        assertThat(TestHelper.findEvents(events, "ChangedEnumTrait").size(), equalTo(1));
+        assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.Appended.1").size(), equalTo(1));
         assertThat(TestHelper.findEvents(events, "ChangedEnumTrait").get(0).getSourceLocation(),
                 equalTo(source));
-        assertThat(TestHelper.findEvents(events, "ChangedEnumTrait").stream()
+        assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.Appended").stream()
                 .allMatch(e -> e.getSeverity() == Severity.NOTE), equalTo(true));
     }
 
@@ -455,16 +461,15 @@ public class ChangedEnumTraitTest {
 
         List<ValidationEvent> changeEvents = TestHelper.findEvents(allEvents, "ChangedEnumTrait");
         assertThat(changeEvents.size(), equalTo(2));
-        assertThat(TestHelper.findEvents(changeEvents, "ChangedEnumTrait.Removed.1").size(), equalTo(1));
-        assertThat(TestHelper.findEvents(changeEvents, "ChangedEnumTrait.Removed.1").get(0).getSourceLocation(),
-                equalTo(beforeSource));
 
-        ValidationEvent removedEvent = changeEvents.get(0);
+        assertThat(TestHelper.findEvents(changeEvents, "ChangedEnumTrait.Removed.1").size(), equalTo(1));
+        ValidationEvent removedEvent = TestHelper.findEvents(changeEvents, "ChangedEnumTrait.Removed.1").get(0);
         assertThat(removedEvent.getSeverity(), equalTo(Severity.ERROR));
         assertThat(removedEvent.getMessage(), stringContainsInOrder("Enum value `old2` was removed"));
         assertThat(removedEvent.getSourceLocation(), equalTo(beforeSource));
 
-        ValidationEvent appendedEvent = changeEvents.get(1);
+        assertThat(TestHelper.findEvents(changeEvents, "ChangedEnumTrait.Appended.2").size(), equalTo(1));
+        ValidationEvent appendedEvent = TestHelper.findEvents(changeEvents, "ChangedEnumTrait.Appended.2").get(0);
         assertThat(appendedEvent.getSeverity(), equalTo(Severity.NOTE));
         assertThat(appendedEvent.getMessage(), stringContainsInOrder("Enum value `new1` was appended"));
         assertThat(appendedEvent.getSourceLocation(), equalTo(afterSource));
@@ -512,7 +517,7 @@ public class ChangedEnumTraitTest {
                 equalTo(afterSource));
         assertThat(TestHelper.findEvents(events, "ChangedEnumTrait").subList(0, 3).stream()
                 .allMatch(e -> e.getSeverity() == Severity.ERROR), equalTo(true));
-        assertThat(TestHelper.findEvents(events, "ChangedEnumTrait").subList(3, 4).stream()
+        assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.Appended.2").stream()
                 .allMatch(e -> e.getSeverity() == Severity.NOTE), equalTo(true));
     }
 
@@ -553,7 +558,7 @@ public class ChangedEnumTraitTest {
                 equalTo(source));
         assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.Removed.1").stream()
                 .allMatch(e -> e.getSeverity() == Severity.ERROR), equalTo(true));
-        assertThat(TestHelper.findEvents(events, "ChangedEnumTrait").subList(1, 2).stream()
+        assertThat(TestHelper.findEvents(events, "ChangedEnumTrait.Appended.2").stream()
                 .allMatch(e -> e.getSeverity() == Severity.NOTE), equalTo(true));
     }
 }
diff --git a/smithy-model/src/test/java/software/amazon/smithy/model/validation/NodeValidationVisitorTest.java b/smithy-model/src/test/java/software/amazon/smithy/model/validation/NodeValidationVisitorTest.java
index 091284703..779a5f7b3 100644
--- a/smithy-model/src/test/java/software/amazon/smithy/model/validation/NodeValidationVisitorTest.java
+++ b/smithy-model/src/test/java/software/amazon/smithy/model/validation/NodeValidationVisitorTest.java
@@ -246,9 +246,9 @@ public class NodeValidationVisitorTest {
 
                 // http-date
                 {"ns.foo#HttpDate", "\"Tue, 29 Apr 2014 18:30:38 GMT\"", null},
-                {"ns.foo#HttpDate", "\"Tuesday, 29 April 2014 18:30:38 GMT\"", new String[] {"Invalid value provided for http-date formatted timestamp. Expected a string value that matches the IMF-fixdate production of RFC 7231 section-7.1.1.1. Found: Tuesday, 29 April 2014 18:30:38 GMT"}},
-                {"ns.foo#HttpDate", "\"Tue, 29 Apr 2014 18:30:38 PST\"", new String[] {"Invalid value provided for http-date formatted timestamp. Expected a string value that matches the IMF-fixdate production of RFC 7231 section-7.1.1.1. Found: Tue, 29 Apr 2014 18:30:38 PST"}},
-                {"ns.foo#HttpDate", "11", new String[] {"Invalid value provided for http-date formatted timestamp. Expected a string value that matches the IMF-fixdate production of RFC 7231 section-7.1.1.1. Found: number"}},
+                {"ns.foo#HttpDate", "\"Tuesday, 29 April 2014 18:30:38 GMT\"", new String[] {"Invalid value provided for http-date formatted timestamp. Expected a string value that matches the IMF-fixdate production of RFC 9110 section-5.6.7. Found: Tuesday, 29 April 2014 18:30:38 GMT"}},
+                {"ns.foo#HttpDate", "\"Tue, 29 Apr 2014 18:30:38 PST\"", new String[] {"Invalid value provided for http-date formatted timestamp. Expected a string value that matches the IMF-fixdate production of RFC 9110 section-5.6.7. Found: Tue, 29 Apr 2014 18:30:38 PST"}},
+                {"ns.foo#HttpDate", "11", new String[] {"Invalid value provided for http-date formatted timestamp. Expected a string value that matches the IMF-fixdate production of RFC 9110 section-5.6.7. Found: number"}},
 
                 // date-time
                 {"ns.foo#DateTime", "\"1985-04-12T23:20:50.52Z\"", null},
@@ -267,8 +267,8 @@ public class NodeValidationVisitorTest {
                         "0: Invalid string value, `1985-04-12T23:20:50.52-07:00`, provided for timestamp, `ns.foo#TimestampList$member`. Expected an RFC 3339 formatted timestamp (e.g., \"1985-04-12T23:20:50.52Z\")"
                 }},
                 {"ns.foo#TimestampList", "[123]", new String[] {"0: Expected a string value for a date-time timestamp (e.g., \"1985-04-12T23:20:50.52Z\")"}},
-                {"ns.foo#Structure4", "{\"httpDate\": 1234}", new String[] {"httpDate: Invalid value provided for http-date formatted timestamp. Expected a string value that matches the IMF-fixdate production of RFC 7231 section-7.1.1.1. Found: number"}},
-                {"ns.foo#Structure4", "{\"httpDateTarget\": 1234}", new String[] {"httpDateTarget: Invalid value provided for http-date formatted timestamp. Expected a string value that matches the IMF-fixdate production of RFC 7231 section-7.1.1.1. Found: number"}},
+                {"ns.foo#Structure4", "{\"httpDate\": 1234}", new String[] {"httpDate: Invalid value provided for http-date formatted timestamp. Expected a string value that matches the IMF-fixdate production of RFC 9110 section-5.6.7. Found: number"}},
+                {"ns.foo#Structure4", "{\"httpDateTarget\": 1234}", new String[] {"httpDateTarget: Invalid value provided for http-date formatted timestamp. Expected a string value that matches the IMF-fixdate production of RFC 9110 section-5.6.7. Found: number"}},
 
                 // timestamp member with no format.
                 {"ns.foo#TimestampListNoFormatTrait", "[123]", null},
diff --git a/smithy-model/src/test/resources/software/amazon/smithy/model/errorfiles/validators/http-header-tchar-validator.errors b/smithy-model/src/test/resources/software/amazon/smithy/model/errorfiles/validators/http-header-tchar-validator.errors
index f1242ede6..b0650ee97 100644
--- a/smithy-model/src/test/resources/software/amazon/smithy/model/errorfiles/validators/http-header-tchar-validator.errors
+++ b/smithy-model/src/test/resources/software/amazon/smithy/model/errorfiles/validators/http-header-tchar-validator.errors
@@ -1,1 +1,1 @@
-[DANGER] ns.foo#SayHelloInput$myHeader: `Not valid!` is not a valid HTTP header field name according to section 3.2 of RFC 7230 | HttpHeaderTrait
+[DANGER] ns.foo#SayHelloInput$myHeader: `Not valid!` is not a valid HTTP header field name according to section 5.6.2 of RFC 9110 | HttpHeaderTrait
diff --git a/smithy-protocol-tests/model/rpcv2Cbor/float16.smithy b/smithy-protocol-tests/model/rpcv2Cbor/float16.smithy
new file mode 100644
index 000000000..a74682d63
--- /dev/null
+++ b/smithy-protocol-tests/model/rpcv2Cbor/float16.smithy
@@ -0,0 +1,94 @@
+$version: "2.0"
+
+namespace smithy.protocoltests.rpcv2Cbor
+
+use smithy.protocols#rpcv2Cbor
+use smithy.test#httpResponseTests
+
+// Verifies that clients can upcast float16s in responses.
+@tags(["client-only"])
+operation Float16 {
+    output: Float16Output
+}
+
+apply Float16 @httpResponseTests([
+    {
+        id: "RpcV2CborFloat16Inf",
+        documentation: "Ensures that clients can correctly parse float16 +Inf.",
+        protocol: rpcv2Cbor,
+        code: 200,
+        // https://cbor.nemo157.com/?type=hex&value=a16576616c7565f97c00
+        body: "oWV2YWx1Zfl8AA==",
+        headers: {
+            "smithy-protocol": "rpc-v2-cbor",
+            "Content-Type": "application/cbor"
+        },
+        params: { value: "Infinity" }
+        bodyMediaType: "application/cbor",
+        appliesTo: "client"
+    },
+    {
+        id: "RpcV2CborFloat16NegInf",
+        documentation: "Ensures that clients can correctly parse float16 -Inf.",
+        protocol: rpcv2Cbor,
+        code: 200,
+        // https://cbor.nemo157.com/?type=hex&value=a16576616c7565f9fc00
+        body: "oWV2YWx1Zfn8AA==",
+        headers: {
+            "smithy-protocol": "rpc-v2-cbor",
+            "Content-Type": "application/cbor"
+        },
+        params: { value: "-Infinity" }
+        bodyMediaType: "application/cbor",
+        appliesTo: "client"
+    },
+    {
+        id: "RpcV2CborFloat16LSBNaN",
+        documentation: "Ensures that clients can correctly parse float16 NaN with high LSB.",
+        protocol: rpcv2Cbor,
+        code: 200,
+        // https://cbor.nemo157.com/?type=hex&value=a16576616c7565f97c01
+        body: "oWV2YWx1Zfl8AQ==",
+        headers: {
+            "smithy-protocol": "rpc-v2-cbor",
+            "Content-Type": "application/cbor"
+        },
+        params: { value: "NaN" }
+        bodyMediaType: "application/cbor",
+        appliesTo: "client"
+    },
+    {
+        id: "RpcV2CborFloat16MSBNaN",
+        documentation: "Ensures that clients can correctly parse float16 NaN with high MSB.",
+        protocol: rpcv2Cbor,
+        code: 200,
+        // https://cbor.nemo157.com/?type=hex&value=a16576616c7565f97e00
+        body: "oWV2YWx1Zfl+AA==",
+        headers: {
+            "smithy-protocol": "rpc-v2-cbor",
+            "Content-Type": "application/cbor"
+        },
+        params: { value: "NaN" }
+        bodyMediaType: "application/cbor",
+        appliesTo: "client"
+    },
+    {
+        id: "RpcV2CborFloat16Subnormal",
+        documentation: "Ensures that clients can correctly parse a subnormal float16.",
+        protocol: rpcv2Cbor,
+        code: 200,
+        // https://cbor.nemo157.com/?type=hex&value=a16576616c7565f90050
+        body: "oWV2YWx1ZfkAUA==",
+        headers: {
+            "smithy-protocol": "rpc-v2-cbor",
+            "Content-Type": "application/cbor"
+        },
+        params: { value: 0.00000476837158203125 } // 1.25 * 2^-18
+        bodyMediaType: "application/cbor",
+        appliesTo: "client"
+    }
+])
+
+structure Float16Output {
+    value: Double
+}
diff --git a/smithy-protocol-tests/model/rpcv2Cbor/main.smithy b/smithy-protocol-tests/model/rpcv2Cbor/main.smithy
index 9d10e723e..504491c82 100644
--- a/smithy-protocol-tests/model/rpcv2Cbor/main.smithy
+++ b/smithy-protocol-tests/model/rpcv2Cbor/main.smithy
@@ -22,7 +22,8 @@ service RpcV2Protocol {
         GreetingWithErrors,
         FractionalSeconds,
         OperationWithDefaults,
-        SparseNullsOperation
+        SparseNullsOperation,
+        Float16
     ]
 }
 
diff --git a/smithy-syntax/src/test/resources/software/amazon/smithy/syntax/formatter/operation-errors-comments.formatted.smithy b/smithy-syntax/src/test/resources/software/amazon/smithy/syntax/formatter/operation-errors-comments.formatted.smithy
new file mode 100644
index 000000000..76fbcdd0c
--- /dev/null
+++ b/smithy-syntax/src/test/resources/software/amazon/smithy/syntax/formatter/operation-errors-comments.formatted.smithy
@@ -0,0 +1,27 @@
+$version: "2.0"
+
+namespace smithy.example
+
+operation Foo {
+    errors: [
+        // a
+        E1
+        // c
+        E2
+        // d
+    ]
+}
+
+operation Bar {
+    // a
+    // b
+    errors: [
+        // c
+    ]
+}
+
+@error("client")
+structure E1 {}
+
+@error("client")
+structure E2 {}
diff --git a/smithy-syntax/src/test/resources/software/amazon/smithy/syntax/formatter/operation-errors-comments.smithy b/smithy-syntax/src/test/resources/software/amazon/smithy/syntax/formatter/operation-errors-comments.smithy
new file mode 100644
index 000000000..6b66e0448
--- /dev/null
+++ b/smithy-syntax/src/test/resources/software/amazon/smithy/syntax/formatter/operation-errors-comments.smithy
@@ -0,0 +1,27 @@
+$version: "2.0"
+
+namespace smithy.example
+
+operation Foo {
+    errors: [
+        // a
+        E1
+        // c
+        E2
+        // d
+    ]
+}
+
+operation Bar {
+    errors // a
+    : // b
+    [
+        // c
+    ]
+}
+
+@error("client")
+structure E1 {}
+
+@error("client")
+structure E2 {}