From 6b8a015cf31e868100570c52df81ce9a2fa9149d Mon Sep 17 00:00:00 2001
From: Chan Yoo <55515281+sichanyoo@users.noreply.github.com>
Date: Thu, 9 Nov 2023 13:28:52 -0800
Subject: [PATCH] chore: update epic branch with new changes in main (#617)

* chore: Require Swift 5.7, fix deprecation warnings (#600)

* feat: support initial-response in RPC based event streams (#597)

* chore: Updates version to 0.32.0

* chore: Add newline to README.md (#602)

* feat: add limited support in smithy-swift for visionOS (#606)

* feat: add support for requiresLength trait and Transfer-Encoding: Chunked (#604)

* chore: Update to aws-crt-swift 0.15.0 (#607)

* fix: content-length middleware should not error on event streams (#608)

* chore: Updates version to 0.33.0

* chore: Improved downstream task (#568)

* chore: Convert idempotency token middleware from closure to reusable type (#610)

* fix: Update aws-crt-swift dependency to 0.17.0 (#612)

* chore: Updates version to 0.34.0

* fix: Endpoint url should be nil if host or scheme is missing (#614)

* fix: Pool HTTP connections based on scheme, host, and port (#615)

* add default log level to initialize method (#616)

* feat: add utility method for converting SdkHttpRequest to URLRequest. (#613)

* Add extension constructor to URLRequest to convert SDKHttpRequest

* Add preprocessor conditional import functionality to SwiftWriter.

---------

Co-authored-by: Sichan Yoo <chanyoo@amazon.com>

* chore: Updates version to 0.35.0

* Update test cases added from main to reflect sra identity & auth fields in middleware context & sra identity & auth middlewares in operation stack.

---------

Co-authored-by: Josh Elkins <jbelkins@users.noreply.github.com>
Co-authored-by: David Yaffe <dayaffe@amazon.com>
Co-authored-by: AWS SDK Swift Automation <github-aws-sdk-swift-automation@amazon.com>
Co-authored-by: Cyprien Ricque <48893621+CyprienRicque@users.noreply.github.com>
Co-authored-by: Sichan Yoo <chanyoo@amazon.com>
---
 .github/workflows/continuous-integration.yml  | 145 ++++++++++++++----
 Package.swift                                 |   6 +-
 Package.version                               |   2 +-
 README.md                                     |   1 +
 .../IdempotencyTokenMiddleware.swift          |  33 ++++
 .../Logging/SDKLoggingSystem.swift            |   4 +-
 .../ClientRuntime/Networking/Endpoint.swift   |   4 +-
 .../Networking/Http/CRT/CRTClientEngine.swift |  35 ++++-
 .../Middlewares/ContentLengthMiddleware.swift |  28 +++-
 .../Networking/Http/SdkHttpRequest.swift      |  33 ++++
 .../DefaultRetryStrategy/RetryQuota.swift     |   2 +-
 .../Util/PlatformOperatingSystem.swift        |   3 +
 Sources/ClientRuntime/Util/SwiftVersion.swift |  14 --
 .../IdempotencyTokenMiddlewareTests.swift     |  86 +++++++++++
 .../ContentLengthMiddlewareTests.swift        |  92 +++++++++++
 .../NetworkingTests/HttpRequestTests.swift    |  36 ++++-
 scripts/ci_steps/select_dependency_branch.sh  |  33 ++++
 .../swift/codegen/ClientRuntimeTypes.kt       |   1 +
 .../swift/codegen/ImportDeclarations.kt       |  26 +++-
 .../smithy/swift/codegen/SwiftWriter.kt       |   9 +-
 .../HttpBindingProtocolGenerator.kt           |  51 ++++--
 .../HttpResponseTraitWithoutHttpPayload.kt    |  60 +++++++-
 .../middlewares/ContentLengthMiddleware.kt    |  18 +--
 .../middlewares/IdempotencyTokenMiddleware.kt |  25 +--
 .../test/kotlin/ContentMd5MiddlewareTests.kt  |   9 +-
 .../EventStreamsInitialResponseTests.kt       |  72 +++++++++
 .../HttpBindingProtocolGeneratorTests.kt      |   3 +-
 .../HttpProtocolClientGeneratorTests.kt       | 126 ++++++++++++++-
 .../test/kotlin/IdempotencyTokenTraitTests.kt |   9 +-
 .../MockHttpAWSJson11ProtocolGenerator.kt     |   3 +-
 ...ent-stream-initial-request-response.smithy |  39 +++++
 .../service-generator-test-operations.smithy  |  36 ++++-
 32 files changed, 914 insertions(+), 130 deletions(-)
 create mode 100644 Sources/ClientRuntime/Idempotency/IdempotencyTokenMiddleware.swift
 create mode 100644 Tests/ClientRuntimeTests/Idempotency/IdempotencyTokenMiddlewareTests.swift
 create mode 100644 Tests/ClientRuntimeTests/NetworkingTests/ContentLengthMiddlewareTests.swift
 create mode 100755 scripts/ci_steps/select_dependency_branch.sh
 create mode 100644 smithy-swift-codegen/src/test/kotlin/EventStreamsInitialResponseTests.kt
 create mode 100644 smithy-swift-codegen/src/test/resources/event-stream-initial-request-response.smithy

diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml
index 64cecb321..e5c851b65 100644
--- a/.github/workflows/continuous-integration.yml
+++ b/.github/workflows/continuous-integration.yml
@@ -7,43 +7,109 @@ on:
   workflow_dispatch:
 
 env:
-  BUILDER_VERSION: v0.9.11
-  BUILDER_SOURCE: releases
-  # host owned by CRT team to host aws-crt-builder releases. Contact their on-call with any issues
-  BUILDER_HOST: https://d19elf31gohf1l.cloudfront.net
-  PACKAGE_NAME: smithy-swift
-  LINUX_BASE_IMAGE: ubuntu-16-x64
-  RUN: ${{ github.run_id }}-${{ github.run_number }}
-  AWS_SDK_SWIFT_CI_DIR: /Users/runner/work/smithy-swift/smithy-swift/target/build/deps/aws-sdk-swift
-  AWS_CRT_SWIFT_CI_DIR: /Users/runner/work/smithy-swift/smithy-swift/target/build/deps/aws-crt-swift
-  SMITHY_SWIFT_CI_DIR: /Users/runner/work/smithy-swift/smithy-swift
+  AWS_SWIFT_SDK_USE_LOCAL_DEPS: 1
 
 jobs:
   downstream:
-    runs-on: macos-13
+    runs-on: ${{ matrix.runner }}
     env:
-      DEVELOPER_DIR: /Applications/Xcode_14.3.app/Contents/Developer
+      DEVELOPER_DIR: /Applications/${{ matrix.xcode }}.app/Contents/Developer
+    strategy:
+      fail-fast: false
+      matrix:
+        # This matrix runs tests on iOS sim & Mac, on oldest & newest supported Xcodes
+        runner:
+          - macos-12
+          - macos-13
+        xcode:
+          - Xcode_14.0.1
+          - Xcode_15.0
+        destination:
+          - 'platform=iOS Simulator,OS=16.0,name=iPhone 13'
+          - 'platform=iOS Simulator,OS=17.0,name=iPhone 15'
+          - 'platform=OS X'
+        exclude:
+          # Don't run old macOS with new Xcode
+          - runner: macos-12
+            xcode: Xcode_15.0
+          # Don't run new macOS with old Xcode
+          - runner: macos-13
+            xcode: Xcode_14.0.1
+          # Don't run old iOS simulator with new Xcode
+          - destination: 'platform=iOS Simulator,OS=16.0,name=iPhone 13'
+            xcode: Xcode_15.0
+          # Don't run new iOS simulator with old Xcode
+          - destination: 'platform=iOS Simulator,OS=17.0,name=iPhone 15'
+            xcode: Xcode_14.0.1
     steps:
-      - name: Checkout sources
+      - name: Checkout smithy-swift
         uses: actions/checkout@v3
-      - uses: actions/cache@v3
+      - name: Select aws-sdk-swift branch
+        run: |
+          ORIGINAL_REPO_HEAD_REF="$GITHUB_HEAD_REF" \
+          DEPENDENCY_REPO_URL="https://github.com/awslabs/aws-sdk-swift.git" \
+          ./scripts/ci_steps/select_dependency_branch.sh
+      - name: Checkout aws-sdk-swift
+        uses: actions/checkout@v3
+        with:
+          repository: awslabs/aws-sdk-swift
+          ref: ${{ env.DEPENDENCY_REPO_SHA }}
+          path: aws-sdk-swift
+      - name: Move aws-sdk-swift into place
+        run: mv aws-sdk-swift ..
+      - name: Cache Gradle
+        uses: actions/cache@v3
         with:
           path: |
             ~/.gradle/caches
             ~/.gradle/wrapper
-          key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}
+          key: 1-${{ runner.os }}-gradle-${{ hashFiles('settings.gradle.kts', 'gradle/wrapper/gradle-wrapper.properties') }}
+          restore-keys: |
+            1-${{ runner.os }}-gradle-${{ hashFiles('settings.gradle.kts', 'gradle/wrapper/gradle-wrapper.properties') }}
+            1-${{ runner.os }}-gradle-
+      - name: Cache Swift
+        uses: actions/cache@v3
+        with:
+          path: |
+            ~/Library/Caches/org.swift.swiftpm
+            ~/.cache/org.swift.swiftpm
+          key: 1-${{ runner.os }}-${{ matrix.xcode }}-spm-${{ hashFiles('Package.swift') }}
           restore-keys: |
-            ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}
-            ${{ runner.os }}-gradle-
-      - uses: actions/setup-java@v3
+            1-${{ runner.os }}-${{ matrix.xcode }}-spm-${{ hashFiles('Package.swift') }}
+            1-${{ runner.os }}-${{ matrix.xcode }}-spm-
+      - name: Setup Java
+        uses: actions/setup-java@v3
         with:
           distribution: corretto
           java-version: 17
-      - name: Build and Test ${{ env.PACKAGE_NAME }} Downstream Consumers
+      - name: Tools Versions
+        run: |
+          cd ../aws-sdk-swift
+          ./scripts/ci_steps/log_tool_versions.sh
+      - name: Build & Run smithy-swift Kotlin Unit Tests
+        run: ./gradlew build
+      - name: Build & Run smithy-swift Swift Unit Tests
+        run: |
+          set -o pipefail && \
+          NSUnbufferedIO=YES xcodebuild \
+            -scheme smithy-swift-Package \
+            -destination '${{ matrix.destination }}' \
+            test 2>&1 \
+            | xcpretty
+      - name: Prepare aws-sdk-swift Protocol & Unit Tests
         run: |
-          python3 -c "from urllib.request import urlretrieve; urlretrieve('${{ env.BUILDER_HOST }}/${{ env.BUILDER_SOURCE }}/${{ env.BUILDER_VERSION }}/builder.pyz?run=${{ env.RUN }}', 'builder')"
-          chmod a+x builder
-          AWS_CRT_SWIFT_CI_DIR="${{ env.AWS_CRT_SWIFT_CI_DIR }}" AWS_SDK_SWIFT_CI_DIR="${{ env.AWS_SDK_SWIFT_CI_DIR }}" SMITHY_SWIFT_CI_DIR="${{ env.SMITHY_SWIFT_CI_DIR }}" AWS_SWIFT_SDK_USE_LOCAL_DEPS=1 ./builder build -p ${{ env.PACKAGE_NAME }} --spec downstream
+          cd ../aws-sdk-swift
+          ./scripts/ci_steps/prepare_protocol_and_unit_tests.sh
+      - name: Build and Run aws-sdk-swift Protocol & Unit Tests
+        run: |
+          cd ../aws-sdk-swift
+          set -o pipefail && \
+          NSUnbufferedIO=YES xcodebuild \
+            -scheme aws-sdk-swift \
+            -destination '${{ matrix.destination }}' \
+            test 2>&1 \
+            | xcpretty
+
   linux:
     runs-on: ubuntu-latest
     strategy:
@@ -57,14 +123,41 @@ jobs:
     container:
       image: swift:${{ matrix.swift }}
     steps:
+      - name: Checkout Sources
+        uses: actions/checkout@v3
       - name: Install openssl
         run: |
           if [ -x "$(command -v apt)" ]; then
             apt-get update && apt-get install -y libssl-dev
           else
-            yum install -y openssl-devel
+            yum install -y openssl-devel which
           fi
-      - name: Checkout Sources
-        uses: actions/checkout@v3
-      - name: Build and Test
+      - name: Cache Gradle
+        uses: actions/cache@v3
+        with:
+          path: |
+            ~/.gradle/caches
+            ~/.gradle/wrapper
+          key: 1-${{ runner.os }}-gradle-${{ hashFiles('settings.gradle.kts', 'gradle/wrapper/gradle-wrapper.properties') }}
+          restore-keys: |
+            1-${{ runner.os }}-gradle-${{ hashFiles('settings.gradle.kts', 'gradle/wrapper/gradle-wrapper.properties') }}
+            1-${{ runner.os }}-gradle-
+      - name: Cache Swift
+        uses: actions/cache@v3
+        with:
+          path: |
+            ~/Library/Caches/org.swift.swiftpm
+            ~/.cache/org.swift.swiftpm
+          key: 1-${{ runner.os }}-${{ matrix.xcode }}-spm-${{ hashFiles('Package.swift') }}
+          restore-keys: |
+            1-${{ runner.os }}-${{ matrix.xcode }}-spm-${{ hashFiles('Package.swift') }}
+            1-${{ runner.os }}-${{ matrix.xcode }}-spm-
+      - name: Setup Java
+        uses: actions/setup-java@v3
+        with:
+          distribution: corretto
+          java-version: 17
+      - name: Build & Run Kotlin Unit Tests
+        run: ./gradlew build
+      - name: Build & Run Swift Unit Tests
         run: swift test
diff --git a/Package.swift b/Package.swift
index 1f5c6ead8..36e9d0bc3 100644
--- a/Package.swift
+++ b/Package.swift
@@ -1,4 +1,4 @@
-// swift-tools-version:5.5
+// swift-tools-version:5.7
 
 import PackageDescription
 
@@ -13,9 +13,9 @@ let package = Package(
         .library(name: "SmithyTestUtil", targets: ["SmithyTestUtil"])
     ],
     dependencies: [
-        .package(url: "https://github.com/awslabs/aws-crt-swift.git", .exact("0.13.0")),
+        .package(url: "https://github.com/awslabs/aws-crt-swift.git", exact: "0.17.0"),
         .package(url: "https://github.com/apple/swift-log.git", from: "1.0.0"),
-        .package(url: "https://github.com/MaxDesiatov/XMLCoder.git", .exact("0.17.0"))
+        .package(url: "https://github.com/MaxDesiatov/XMLCoder.git", exact: "0.17.0")
     ],
     targets: [
         .target(
diff --git a/Package.version b/Package.version
index f0e1a438f..4d8ac4d2e 100644
--- a/Package.version
+++ b/Package.version
@@ -1 +1 @@
-0.31.0
\ No newline at end of file
+0.35.0
\ No newline at end of file
diff --git a/README.md b/README.md
index b919cec7a..b589f7cbc 100644
--- a/README.md
+++ b/README.md
@@ -28,3 +28,4 @@ This project is licensed under the Apache-2.0 License.
 
 See [CONTRIBUTING](CONTRIBUTING.md) for more information.
 
+
diff --git a/Sources/ClientRuntime/Idempotency/IdempotencyTokenMiddleware.swift b/Sources/ClientRuntime/Idempotency/IdempotencyTokenMiddleware.swift
new file mode 100644
index 000000000..a8a536121
--- /dev/null
+++ b/Sources/ClientRuntime/Idempotency/IdempotencyTokenMiddleware.swift
@@ -0,0 +1,33 @@
+//
+// Copyright Amazon.com Inc. or its affiliates.
+// All Rights Reserved.
+//
+// SPDX-License-Identifier: Apache-2.0
+//
+
+public struct IdempotencyTokenMiddleware<OperationStackInput,
+                                         OperationStackOutput: HttpResponseBinding,
+                                         OperationStackError: HttpResponseErrorBinding>: ClientRuntime.Middleware {
+    public let id: Swift.String = "IdempotencyTokenMiddleware"
+    private let keyPath: WritableKeyPath<OperationStackInput, String?>
+
+    public init(keyPath: WritableKeyPath<OperationStackInput, String?>) {
+        self.keyPath = keyPath
+    }
+
+    public func handle<H>(context: Context,
+                          input: MInput,
+                          next: H) async throws -> MOutput
+    where H: Handler, Self.MInput == H.Input, Self.MOutput == H.Output, Self.Context == H.Context {
+        var copiedInput = input
+        if input[keyPath: keyPath] == nil {
+            let idempotencyTokenGenerator = context.getIdempotencyTokenGenerator()
+            copiedInput[keyPath: keyPath] = idempotencyTokenGenerator.generateToken()
+        }
+        return try await next.handle(context: context, input: copiedInput)
+    }
+
+    public typealias MInput = OperationStackInput
+    public typealias MOutput = OperationOutput<OperationStackOutput>
+    public typealias Context = HttpContext
+}
diff --git a/Sources/ClientRuntime/Logging/SDKLoggingSystem.swift b/Sources/ClientRuntime/Logging/SDKLoggingSystem.swift
index 584011547..a408f5a4e 100644
--- a/Sources/ClientRuntime/Logging/SDKLoggingSystem.swift
+++ b/Sources/ClientRuntime/Logging/SDKLoggingSystem.swift
@@ -15,13 +15,13 @@ public class SDKLoggingSystem {
         factories[label] = logHandlerFactory
     }
 
-    public class func initialize() {
+    public class func initialize(defaultLogLevel: SDKLogLevel = .info) {
         LoggingSystem.bootstrap { label in
             if let factory = factories[label] {
                 return factory.construct(label: label)
             }
             var handler = StreamLogHandler.standardOutput(label: label)
-            handler.logLevel = .info
+            handler.logLevel = defaultLogLevel.toLoggerType()
             return handler
         }
     }
diff --git a/Sources/ClientRuntime/Networking/Endpoint.swift b/Sources/ClientRuntime/Networking/Endpoint.swift
index f51cf8dd5..9dbb65857 100644
--- a/Sources/ClientRuntime/Networking/Endpoint.swift
+++ b/Sources/ClientRuntime/Networking/Endpoint.swift
@@ -63,10 +63,10 @@ extension Endpoint {
     public var url: URL? {
         var components = URLComponents()
         components.scheme = protocolType?.rawValue
-        components.host = host
+        components.host = host.isEmpty ? nil : host // If host is empty, URL is invalid
         components.percentEncodedPath = path
         components.percentEncodedQuery = queryItemString
-        return components.url
+        return (components.host == nil || components.scheme == nil) ? nil : components.url
     }
 
     var queryItemString: String? {
diff --git a/Sources/ClientRuntime/Networking/Http/CRT/CRTClientEngine.swift b/Sources/ClientRuntime/Networking/Http/CRT/CRTClientEngine.swift
index 836d35d40..b89c954c6 100644
--- a/Sources/ClientRuntime/Networking/Http/CRT/CRTClientEngine.swift
+++ b/Sources/ClientRuntime/Networking/Http/CRT/CRTClientEngine.swift
@@ -12,12 +12,31 @@ import Darwin
 
 public class CRTClientEngine: HttpClientEngine {
     actor SerialExecutor {
+
+        /// Stores the common properties of requests that should share a HTTP connection, such that requests
+        /// with equal `ConnectionID` values should be pooled together.
+        ///
+        /// Used as a dictionary key for storing CRT connection managers once they have been created.
+        /// When a new request is made, a connection manager is reused if it matches the request's scheme,
+        /// host, and port.
+        private struct ConnectionPoolID: Hashable {
+            private let protocolType: ProtocolType?
+            private let host: String
+            private let port: Int16
+
+            init(endpoint: Endpoint) {
+                self.protocolType = endpoint.protocolType
+                self.host = endpoint.host
+                self.port = endpoint.port
+            }
+        }
+
         private var logger: LogAgent
 
         private let windowSize: Int
         private let maxConnectionsPerEndpoint: Int
-        private var connectionPools: [Endpoint: HTTPClientConnectionManager] = [:]
-        private var http2ConnectionPools: [Endpoint: HTTP2StreamManager] = [:]
+        private var connectionPools: [ConnectionPoolID: HTTPClientConnectionManager] = [:]
+        private var http2ConnectionPools: [ConnectionPoolID: HTTP2StreamManager] = [:]
         private let sharedDefaultIO = SDKDefaultIO.shared
         private let connectTimeoutMs: UInt32?
 
@@ -29,22 +48,22 @@ public class CRTClientEngine: HttpClientEngine {
         }
 
         func getOrCreateConnectionPool(endpoint: Endpoint) throws -> HTTPClientConnectionManager {
-            guard let connectionPool = connectionPools[endpoint] else {
+            let poolID = ConnectionPoolID(endpoint: endpoint)
+            guard let connectionPool = connectionPools[poolID] else {
                 let newConnectionPool = try createConnectionPool(endpoint: endpoint)
-                connectionPools[endpoint] = newConnectionPool // save in dictionary
+                connectionPools[poolID] = newConnectionPool // save in dictionary
                 return newConnectionPool
             }
-
             return connectionPool
         }
 
         func getOrCreateHTTP2ConnectionPool(endpoint: Endpoint) throws -> HTTP2StreamManager {
-            guard let connectionPool = http2ConnectionPools[endpoint] else {
+            let poolID = ConnectionPoolID(endpoint: endpoint)
+            guard let connectionPool = http2ConnectionPools[poolID] else {
                 let newConnectionPool = try createHTTP2ConnectionPool(endpoint: endpoint)
-                http2ConnectionPools[endpoint] = newConnectionPool // save in dictionary
+                http2ConnectionPools[poolID] = newConnectionPool // save in dictionary
                 return newConnectionPool
             }
-
             return connectionPool
         }
 
diff --git a/Sources/ClientRuntime/Networking/Http/Middlewares/ContentLengthMiddleware.swift b/Sources/ClientRuntime/Networking/Http/Middlewares/ContentLengthMiddleware.swift
index d7e76b9ad..ef39978a2 100644
--- a/Sources/ClientRuntime/Networking/Http/Middlewares/ContentLengthMiddleware.swift
+++ b/Sources/ClientRuntime/Networking/Http/Middlewares/ContentLengthMiddleware.swift
@@ -6,7 +6,20 @@ public struct ContentLengthMiddleware<OperationStackOutput: HttpResponseBinding>
 
     private let contentLengthHeaderName = "Content-Length"
 
-    public init() {}
+    private var requiresLength: Bool?
+
+    private var unsignedPayload: Bool?
+
+    /// Creates a new `ContentLengthMiddleware` with the supplied parameters
+    /// - Parameters:
+    ///   - requiresLength: Trait requires the length of a blob stream to be known. 
+    ///     When the request body is not a streaming blob, `nil` should be passed. Defaults to `nil`.
+    ///   - unsignedPayload: Trait signifies that the length of a stream in payload does not need to be known.
+    ///     When the request body is not a streaming blob, `nil` should be passed. Defaults to `nil`.
+    public init(requiresLength: Bool? = nil, unsignedPayload: Bool? = nil) {
+        self.requiresLength = requiresLength
+        self.unsignedPayload = unsignedPayload
+    }
 
     public func handle<H>(context: Context,
                           input: MInput,
@@ -22,8 +35,19 @@ public struct ContentLengthMiddleware<OperationStackOutput: HttpResponseBinding>
         case .stream(let stream):
             if let length = stream.length {
                 input.headers.update(name: "Content-Length", value: String(length))
+            } else if (requiresLength == false && unsignedPayload == true) ||
+                        (requiresLength == nil && unsignedPayload == nil) {
+                // Transfer-Encoding can be sent on all Event Streams where length cannot be determined
+                // or on blob Data Streams where requiresLength is true and unsignedPayload is false
+                // Only for HTTP/1.1 requests, will be removed in all HTTP/2 requests
+                input.headers.update(name: "Transfer-Encoding", value: "Chunked")
             } else {
-                input.headers.update(name: "Transfer-Encoded", value: "Chunked")
+                let operation = context.attributes.get(key: AttributeKey<String>(name: "Operation"))
+                             ?? "Error getting operation name"
+                let errorMessage = (unsignedPayload ?? false) ?
+                    "Missing content-length for operation: \(operation)" :
+                    "Missing content-length for SigV4 signing on operation: \(operation)"
+                throw StreamError.notSupported(errorMessage)
             }
         default:
             input.headers.update(name: "Content-Length", value: "0")
diff --git a/Sources/ClientRuntime/Networking/Http/SdkHttpRequest.swift b/Sources/ClientRuntime/Networking/Http/SdkHttpRequest.swift
index d6c5febcc..6a45a3067 100644
--- a/Sources/ClientRuntime/Networking/Http/SdkHttpRequest.swift
+++ b/Sources/ClientRuntime/Networking/Http/SdkHttpRequest.swift
@@ -6,6 +6,12 @@ import struct Foundation.CharacterSet
 import struct Foundation.URLQueryItem
 import struct Foundation.URLComponents
 import AwsCommonRuntimeKit
+// In Linux, Foundation.URLRequest is moved to FoundationNetworking.
+#if canImport(FoundationNetworking)
+import FoundationNetworking
+#else
+import struct Foundation.URLRequest
+#endif
 
 // we need to maintain a reference to this same request while we add headers
 // in the CRT engine so that is why it's a class
@@ -75,6 +81,9 @@ extension SdkHttpRequest {
         httpRequest.path = [endpoint.path, endpoint.queryItemString].compactMap { $0 }.joined(separator: "?")
         httpRequest.addHeaders(headers: headers.toHttpHeaders())
 
+        // Remove the "Transfer-Encoding" header if it exists since h2 does not support it
+        httpRequest.removeHeader(name: "Transfer-Encoding")
+
         // HTTP2Request used with manual writes hence we need to set the body to nil
         // so that CRT does not write the body for us (we will write it manually)
         httpRequest.body = nil
@@ -82,6 +91,30 @@ extension SdkHttpRequest {
     }
 }
 
+public extension URLRequest {
+    init(sdkRequest: SdkHttpRequest) async throws {
+        // Set URL
+        guard let url = sdkRequest.endpoint.url else {
+            throw ClientError.dataNotFound("Failed to construct URLRequest due to missing URL.")
+        }
+        self.init(url: url)
+        // Set method type
+        self.httpMethod = sdkRequest.method.rawValue
+        // Set body, handling any serialization errors
+        do {
+            self.httpBody = try await sdkRequest.body.readData()
+        } catch {
+            throw ClientError.serializationFailed("Failed to construct URLRequest due to HTTP body conversion failure.")
+        }
+        // Set headers
+        sdkRequest.headers.headers.forEach { header in
+            header.value.forEach { value in
+                self.addValue(value, forHTTPHeaderField: header.name)
+            }
+        }
+    }
+}
+
 extension SdkHttpRequest: CustomDebugStringConvertible, CustomStringConvertible {
 
     public var debugDescriptionWithBody: String {
diff --git a/Sources/ClientRuntime/Retries/DefaultRetryStrategy/RetryQuota.swift b/Sources/ClientRuntime/Retries/DefaultRetryStrategy/RetryQuota.swift
index 717783dd2..d516d658c 100644
--- a/Sources/ClientRuntime/Retries/DefaultRetryStrategy/RetryQuota.swift
+++ b/Sources/ClientRuntime/Retries/DefaultRetryStrategy/RetryQuota.swift
@@ -55,7 +55,7 @@ final actor RetryQuota {
 
     /// Creates a new quota with settings from the passed options.
     /// - Parameter options: The retry strategy options from which to configure this retry quota
-    convenience init(options: RetryStrategyOptions) {
+    init(options: RetryStrategyOptions) {
         self.init(
             availableCapacity: options.availableCapacity,
             maxCapacity: options.maxCapacity,
diff --git a/Sources/ClientRuntime/Util/PlatformOperatingSystem.swift b/Sources/ClientRuntime/Util/PlatformOperatingSystem.swift
index 60a1782d3..0caf3b786 100644
--- a/Sources/ClientRuntime/Util/PlatformOperatingSystem.swift
+++ b/Sources/ClientRuntime/Util/PlatformOperatingSystem.swift
@@ -12,6 +12,7 @@ public enum PlatformOperatingSystem: String {
     case macOS
     case watchOS
     case tvOS
+    case visionOS
     case unknown
 }
 
@@ -28,6 +29,8 @@ public var currentOS: PlatformOperatingSystem {
     return .windows
     #elseif os(tvOS)
     return .tvOS
+    #elseif os(visionOS)
+    return .visionOS
     #else
      #error("Cannot use a an operating system we do not support")
     #endif
diff --git a/Sources/ClientRuntime/Util/SwiftVersion.swift b/Sources/ClientRuntime/Util/SwiftVersion.swift
index 6c167d527..6d1633b2c 100644
--- a/Sources/ClientRuntime/Util/SwiftVersion.swift
+++ b/Sources/ClientRuntime/Util/SwiftVersion.swift
@@ -49,20 +49,6 @@ private func swift5Version() -> String? {
     return "5.8"
     #elseif swift(>=5.7)
     return "5.7"
-    #elseif swift(>=5.6)
-    return "5.6"
-    #elseif swift(>=5.5)
-    return "5.5"
-    #elseif swift(>=5.4)
-    return "5.4"
-    #elseif swift(>=5.3)
-    return "5.3"
-    #elseif swift(>=5.2)
-    return "5.2"
-    #elseif swift(>=5.1)
-    return "5.1"
-    #elseif swift(>=5.0)
-    return "5.0"
     #else
     return nil
     #endif
diff --git a/Tests/ClientRuntimeTests/Idempotency/IdempotencyTokenMiddlewareTests.swift b/Tests/ClientRuntimeTests/Idempotency/IdempotencyTokenMiddlewareTests.swift
new file mode 100644
index 000000000..1728c396e
--- /dev/null
+++ b/Tests/ClientRuntimeTests/Idempotency/IdempotencyTokenMiddlewareTests.swift
@@ -0,0 +1,86 @@
+//
+// Copyright Amazon.com Inc. or its affiliates.
+// All Rights Reserved.
+//
+// SPDX-License-Identifier: Apache-2.0
+//
+
+import Foundation
+import ClientRuntime
+import XCTest
+
+class IdempotencyTokenMiddlewareTests: XCTestCase {
+
+    private typealias Subject = IdempotencyTokenMiddleware<TestInputType, TestOutputType, TestOutputErrorType>
+
+    let token = "def"
+    let previousToken = "abc"
+    private var tokenGenerator: IdempotencyTokenGenerator!
+    private var context: HttpContext!
+    private var subject: Subject!
+
+    override func setUp() async throws {
+        try await super.setUp()
+        tokenGenerator = TestIdempotencyTokenGenerator(token: token)
+        context = HttpContextBuilder().withIdempotencyTokenGenerator(value: tokenGenerator).build()
+        subject = Subject(keyPath: \.tokenMember)
+    }
+
+    func test_handle_itSetsAnIdempotencyTokenIfNoneIsSet() async throws {
+        let input = TestInputType(tokenMember: nil)
+        let next = MockHandler<TestInputType, TestOutputType> { (context, input) in
+            XCTAssertEqual(input.tokenMember, self.token)
+        }
+        _ = try await subject.handle(context: context, input: input, next: next)
+    }
+
+    func test_handle_itDoesNotChangeTheIdempotencyTokenIfAlreadySet() async throws {
+        let input = TestInputType(tokenMember: previousToken)
+        let next = MockHandler<TestInputType, TestOutputType> { (context, input) in
+            XCTAssertEqual(input.tokenMember, self.previousToken)
+        }
+        _ = try await subject.handle(context: context, input: input, next: next)
+    }
+}
+
+// MARK: - Test fixtures & types
+
+private struct TestIdempotencyTokenGenerator: IdempotencyTokenGenerator {
+    let token: String
+    func generateToken() -> String { token }
+}
+
+private struct TestInputType {
+    var tokenMember: String?
+}
+
+private struct TestOutputType: HttpResponseBinding {
+    init(httpResponse: ClientRuntime.HttpResponse, decoder: ClientRuntime.ResponseDecoder?) async throws {
+        // no-op
+    }
+}
+
+private enum TestOutputErrorType: HttpResponseErrorBinding {
+    static func makeError(httpResponse: ClientRuntime.HttpResponse, decoder: ClientRuntime.ResponseDecoder?) async throws -> Error {
+        return TestError()
+    }
+}
+
+private struct TestError: Error {}
+
+private struct MockHandler<I, O: HttpResponseBinding>: Handler {
+    typealias Output = OperationOutput<O>
+    typealias Context = HttpContext
+    typealias MockHandlerCallback = (Context, I) async throws -> Void
+
+    private let handleCallback: MockHandlerCallback
+
+    init(handleCallback: @escaping MockHandlerCallback) {
+        self.handleCallback = handleCallback
+    }
+
+    func handle(context: Context, input: I) async throws -> Output {
+        try await handleCallback(context, input)
+        return OperationOutput(httpResponse: HttpResponse())
+    }
+}
diff --git a/Tests/ClientRuntimeTests/NetworkingTests/ContentLengthMiddlewareTests.swift b/Tests/ClientRuntimeTests/NetworkingTests/ContentLengthMiddlewareTests.swift
new file mode 100644
index 000000000..e2b48fe23
--- /dev/null
+++ b/Tests/ClientRuntimeTests/NetworkingTests/ContentLengthMiddlewareTests.swift
@@ -0,0 +1,92 @@
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0.
+
+import XCTest
+import SmithyTestUtil
+@testable import ClientRuntime
+
+class ContentLengthMiddlewareTests: XCTestCase {
+    private var builtContext: HttpContext!
+    private var stack: OperationStack<MockInput, MockOutput, MockMiddlewareError>!
+
+    override func setUpWithError() throws {
+        try super.setUpWithError()
+        builtContext = HttpContextBuilder()
+                  .withMethod(value: .get)
+                  .withPath(value: "/")
+                  .withEncoder(value: JSONEncoder())
+                  .withDecoder(value: JSONDecoder())
+                  .withOperation(value: "Test Operation")
+                  .build()
+        stack = OperationStack<MockInput, MockOutput, MockMiddlewareError>(id: "Test Operation")
+    }
+
+    func testTransferEncodingChunkedSetWhenStreamLengthIsNil() async throws {
+        addContentLengthMiddlewareWith(requiresLength: false, unsignedPayload: true)
+        forceEmptyStream()
+        try await AssertHeadersArePresent(expectedHeaders: ["Transfer-Encoding": "Chunked"])
+    }
+
+    func testTransferEncodingChunkedSetWithNilTraits() async throws {
+        // default constructor
+        addContentLengthMiddlewareWith(requiresLength: nil, unsignedPayload: nil)
+        forceEmptyStream()
+        try await AssertHeadersArePresent(expectedHeaders: ["Transfer-Encoding": "Chunked"])
+    }
+
+    func testContentLengthSetWhenStreamLengthAvailableAndRequiresLengthSet() async throws {
+        addContentLengthMiddlewareWith(requiresLength: true, unsignedPayload: false)
+        try await AssertHeadersArePresent(expectedHeaders: ["Content-Length": "0"])
+    }
+
+    func testContentLengthSetWhenRequiresLengthAndUnsignedPayload() async throws {
+        addContentLengthMiddlewareWith(requiresLength: true, unsignedPayload: true)
+        try await AssertHeadersArePresent(expectedHeaders: ["Content-Length": "0"])
+    }
+
+    func testRequiresLengthSetWithNilStreamShouldThrowError() async throws {
+        addContentLengthMiddlewareWith(requiresLength: true, unsignedPayload: false)
+        forceEmptyStream()
+        do {
+            try await AssertHeadersArePresent(expectedHeaders: ["Content-Length": "0"])
+            XCTFail("Should throw error")
+        } catch let error as StreamError {
+            switch error {
+            case .notSupported("Missing content-length for SigV4 signing on operation: Test Operation"), .notSupported("Missing content-length for operation: Test Operation"):
+                // The error matches one of the expected cases, test passes
+                break
+            default:
+                XCTFail("Error is not StreamError.notSupported with expected message")
+            }
+        }
+    }
+
+    private func addContentLengthMiddlewareWith(requiresLength: Bool?, unsignedPayload: Bool?) {
+        stack.finalizeStep.intercept(
+            position: .before,
+            middleware: ContentLengthMiddleware(requiresLength: requiresLength, unsignedPayload: unsignedPayload)
+        )
+    }
+
+    private func forceEmptyStream() {
+        // Force stream length to be nil
+        stack.finalizeStep.intercept(position: .before, id: "set nil stream length") { (context, input, next) -> OperationOutput<MockOutput> in
+            input.body = .stream(BufferedStream()) // Set the stream length to nil
+            return try await next.handle(context: context, input: input)
+        }
+    }
+        
+    private func AssertHeadersArePresent(expectedHeaders: [String: String], file: StaticString = #file, line: UInt = #line) async throws -> Void {
+        let mockHandler = MockHandler { (_, input) in
+            for (key, value) in expectedHeaders {
+                XCTAssert(input.headers.value(for: key) == value, file: file, line: line)
+            }
+            let httpResponse = HttpResponse(body: HttpBody.none, statusCode: HttpStatusCode.ok)
+            let mockOutput = try! MockOutput(httpResponse: httpResponse, decoder: nil)
+            let output = OperationOutput<MockOutput>(httpResponse: httpResponse, output: mockOutput)
+            return output
+        }
+
+        _ = try await stack.handleMiddleware(context: builtContext, input: MockInput(), next: mockHandler)
+    }
+}
\ No newline at end of file
diff --git a/Tests/ClientRuntimeTests/NetworkingTests/HttpRequestTests.swift b/Tests/ClientRuntimeTests/NetworkingTests/HttpRequestTests.swift
index 2c07eb4b0..c1bc09257 100644
--- a/Tests/ClientRuntimeTests/NetworkingTests/HttpRequestTests.swift
+++ b/Tests/ClientRuntimeTests/NetworkingTests/HttpRequestTests.swift
@@ -7,6 +7,12 @@ import XCTest
 import AwsCommonRuntimeKit
 import struct Foundation.URLQueryItem
 @testable import ClientRuntime
+// In Linux, Foundation.URLRequest is moved to FoundationNetworking.
+#if canImport(FoundationNetworking)
+import FoundationNetworking
+#else
+import struct Foundation.URLRequest
+#endif
 
 class HttpRequestTests: NetworkingTestUtils {
 
@@ -51,6 +57,30 @@ class HttpRequestTests: NetworkingTestUtils {
         }
     }
 
+    func testSdkHttpRequestToURLRequest() async throws {
+        let headers = Headers(["Testname-1": "testvalue-1", "Testname-2": "testvalue-2"])
+        let endpoint = Endpoint(host: "host.com", path: "/", headers: headers)
+
+        let httpBody = HttpBody.data(expectedMockRequestData)
+        let mockHttpRequest = SdkHttpRequest(method: .get, endpoint: endpoint, body: httpBody)
+        let urlRequest = try await URLRequest(sdkRequest: mockHttpRequest)
+
+        XCTAssertNotNil(urlRequest)
+        guard let headersFromRequest = urlRequest.allHTTPHeaderFields else {
+            XCTFail("Headers in SdkHttpRequest were not successfully converted to headers in URLRequest.")
+            // Compiler doesn't recognize XCTFail as return / exception thrown
+            return
+        }
+
+        // Check URLRequest fields
+        XCTAssertTrue(headersFromRequest.contains { $0.key == "Testname-1" && $0.value == "testvalue-1" })
+        XCTAssertTrue(headersFromRequest.contains { $0.key == "Testname-2" && $0.value == "testvalue-2" })
+        let expectedBody = try await httpBody.readData()
+        XCTAssertEqual(urlRequest.httpBody, expectedBody)
+        XCTAssertEqual(urlRequest.url, endpoint.url)
+        XCTAssertEqual(urlRequest.httpMethod, mockHttpRequest.method.rawValue)
+    }
+
     func testCRTHeadersToSdkHeaders() throws {
         let builder = SdkHttpRequestBuilder()
             .withHeader(name: "Host", value: "amazon.aws.com")
@@ -111,7 +141,9 @@ class HttpRequestTests: NetworkingTestUtils {
     }
 
     func testConversionToUrlRequestFailsWithInvalidEndpoint() {
-        // TODO:: When is the endpoint invalid or endpoint.url nil?
-        _ = Endpoint(host: "", path: "", protocolType: nil)
+        // Testing with an invalid endpoint where host is empty,
+        // path is empty, and protocolType is nil.
+        let endpoint = Endpoint(host: "", path: "", protocolType: nil)
+        XCTAssertNil(endpoint.url, "An invalid endpoint should result in a nil URL.")
     }
 }
diff --git a/scripts/ci_steps/select_dependency_branch.sh b/scripts/ci_steps/select_dependency_branch.sh
new file mode 100755
index 000000000..eb1d534bb
--- /dev/null
+++ b/scripts/ci_steps/select_dependency_branch.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+
+set -e
+
+# This script selects the Git reference for a locally installed dependency of another "original" repo.
+# It matches the original's checked-out branch name if available, and if not, falls back to main.
+
+# Checks to see if Git repository at DEPENDENCY_REPO_URL has a branch named ORIGINAL_REPO_HEAD_REF.
+# If so, the latest SHA for that branch is obtained and stored as DEPENDENCY_REPO_SHA in the Github env.
+#
+# If a branch named ORIGINAL_REPO_HEAD_REF does not exist in the Git repository at DEPENDENCY_REPO_URL,
+# the SHA for the main branch is obtained and stored as DEPENDENCY_REPO_SHA in the Github env.
+
+# Parameters:
+#   ORIGINAL_REPO_HEAD_REF : the branch or tag name for the original repo branch being built.
+#   DEPENDENCY_REPO_URL : the URL to the dependency that will be matched to the branch
+
+# Output:
+#   DEPENDENCY_REPO_SHA : the Git SHA for the dependency repo commit to be built (set in the Github environment)
+
+echo "Finding correct branch for dependency repo: $DEPENDENCY_REPO_URL"
+DEPENDENCY_BRANCH_SHA=`git ls-remote --heads "$DEPENDENCY_REPO_URL" "refs/heads/$ORIGINAL_REPO_HEAD_REF" | awk '{print $1}'`
+if [[ ! -z "${DEPENDENCY_BRANCH_SHA}" ]]; then
+  echo "Ref $ORIGINAL_REPO_HEAD_REF was found on dependency repo at SHA $DEPENDENCY_BRANCH_SHA"
+  echo "Selecting dependency repo branch $ORIGINAL_REPO_HEAD_REF at $DEPENDENCY_BRANCH_SHA"
+  echo "DEPENDENCY_REPO_SHA=$DEPENDENCY_BRANCH_SHA" >> "$GITHUB_ENV"
+else
+  echo "Ref $ORIGINAL_REPO_HEAD_REF was not found on dependency repo at SHA $DEPENDENCY_BRANCH_SHA"
+  DEPENDENCY_MAIN_SHA=`git ls-remote --heads "$ORIGINAL_REPO_HEAD_REF" "refs/heads/main" | awk '{print $1}'`
+  echo "Selecting dependency repo main branch at $DEPENDENCY_MAIN_SHA"
+  echo "DEPENDENCY_REPO_SHA=$DEPENDENCY_MAIN_SHA" >> "$GITHUB_ENV"
+fi
+
diff --git a/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/ClientRuntimeTypes.kt b/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/ClientRuntimeTypes.kt
index 79f21a629..7e9ec15ee 100644
--- a/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/ClientRuntimeTypes.kt
+++ b/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/ClientRuntimeTypes.kt
@@ -75,6 +75,7 @@ object ClientRuntimeTypes {
         val HeaderMiddleware = runtimeSymbol("HeaderMiddleware")
         val SerializableBodyMiddleware = runtimeSymbol("SerializableBodyMiddleware")
         val RetryMiddleware = runtimeSymbol("RetryMiddleware")
+        val IdempotencyTokenMiddleware = runtimeSymbol("IdempotencyTokenMiddleware")
         val NoopHandler = runtimeSymbol("NoopHandler")
         val SigningMiddleware = runtimeSymbol("SignerMiddleware")
         val AuthSchemeMiddleware = runtimeSymbol("AuthSchemeMiddleware")
diff --git a/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/ImportDeclarations.kt b/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/ImportDeclarations.kt
index da05a1b2f..eb305b223 100644
--- a/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/ImportDeclarations.kt
+++ b/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/ImportDeclarations.kt
@@ -8,7 +8,12 @@ package software.amazon.smithy.swift.codegen
 class ImportDeclarations {
     private val imports = mutableSetOf<ImportStatement>()
 
-    fun addImport(packageName: String, isTestable: Boolean = false, internalSPIName: String? = null) {
+    fun addImport(
+        packageName: String,
+        isTestable: Boolean = false,
+        internalSPIName: String? = null,
+        importOnlyIfCanImport: Boolean = false
+    ) {
         val existingImport = imports.find { it.packageName == packageName }
         if (existingImport != null) {
             // Update isTestable to true if needed
@@ -17,10 +22,12 @@ class ImportDeclarations {
             if (internalSPIName != null) {
                 existingImport.internalSPINames.add(internalSPIName)
             }
+            // Update importOnlyIfCanImport to true if needed
+            existingImport.importOnlyIfCanImport = existingImport.importOnlyIfCanImport || importOnlyIfCanImport
         } else {
             // Otherwise, we have a new package to import, so add it
             val internalSPINames = listOf(internalSPIName).mapNotNull { it }.toMutableSet()
-            imports.add(ImportStatement(packageName, isTestable, internalSPINames))
+            imports.add(ImportStatement(packageName, isTestable, internalSPINames, importOnlyIfCanImport))
         }
     }
 
@@ -36,7 +43,12 @@ class ImportDeclarations {
     }
 }
 
-private data class ImportStatement(val packageName: String, var isTestable: Boolean, val internalSPINames: MutableSet<String>) {
+private data class ImportStatement(
+    val packageName: String,
+    var isTestable: Boolean,
+    val internalSPINames: MutableSet<String>,
+    var importOnlyIfCanImport: Boolean
+) {
     val statement: String
         get() {
             var import = "import $packageName"
@@ -46,6 +58,14 @@ private data class ImportStatement(val packageName: String, var isTestable: Bool
             if (isTestable) {
                 import = "@testable $import"
             }
+            if (importOnlyIfCanImport) {
+                import =
+                    """
+                    #if canImport($packageName)
+                    $import
+                    #endif
+                    """.trimIndent()
+            }
             return import
         }
 
diff --git a/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/SwiftWriter.kt b/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/SwiftWriter.kt
index 56f099200..232a517f9 100644
--- a/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/SwiftWriter.kt
+++ b/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/SwiftWriter.kt
@@ -101,8 +101,13 @@ class SwiftWriter(private val fullPackageName: String) : CodeWriter() {
         }
     }
 
-    fun addImport(packageName: String, isTestable: Boolean = false, internalSPIName: String? = null) {
-        imports.addImport(packageName, isTestable, internalSPIName)
+    fun addImport(
+        packageName: String,
+        isTestable: Boolean = false,
+        internalSPIName: String? = null,
+        importOnlyIfCanImport: Boolean = false
+    ) {
+        imports.addImport(packageName, isTestable, internalSPIName, importOnlyIfCanImport)
     }
 
     fun addFoundationImport() {
diff --git a/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/integration/HttpBindingProtocolGenerator.kt b/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/integration/HttpBindingProtocolGenerator.kt
index ec4ad1b88..9c3b72311 100644
--- a/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/integration/HttpBindingProtocolGenerator.kt
+++ b/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/integration/HttpBindingProtocolGenerator.kt
@@ -4,6 +4,7 @@
  */
 package software.amazon.smithy.swift.codegen.integration
 
+import software.amazon.smithy.aws.traits.auth.UnsignedPayloadTrait
 import software.amazon.smithy.codegen.core.Symbol
 import software.amazon.smithy.model.knowledge.HttpBinding
 import software.amazon.smithy.model.knowledge.HttpBindingIndex
@@ -30,6 +31,7 @@ import software.amazon.smithy.model.traits.HttpPrefixHeadersTrait
 import software.amazon.smithy.model.traits.HttpQueryParamsTrait
 import software.amazon.smithy.model.traits.HttpQueryTrait
 import software.amazon.smithy.model.traits.MediaTypeTrait
+import software.amazon.smithy.model.traits.RequiresLengthTrait
 import software.amazon.smithy.model.traits.StreamingTrait
 import software.amazon.smithy.model.traits.TimestampFormatTrait
 import software.amazon.smithy.swift.codegen.ClientRuntimeTypes
@@ -62,6 +64,7 @@ import software.amazon.smithy.swift.codegen.integration.serde.UnionEncodeGenerat
 import software.amazon.smithy.swift.codegen.middleware.OperationMiddlewareGenerator
 import software.amazon.smithy.swift.codegen.model.ShapeMetadata
 import software.amazon.smithy.swift.codegen.model.bodySymbol
+import software.amazon.smithy.swift.codegen.model.findStreamingMember
 import software.amazon.smithy.swift.codegen.model.hasEventStreamMember
 import software.amazon.smithy.swift.codegen.model.hasTrait
 import software.amazon.smithy.utils.OptionalUtils
@@ -93,9 +96,8 @@ fun formatHeaderOrQueryValue(
     memberShape: MemberShape,
     location: HttpBinding.Location,
     bindingIndex: HttpBindingIndex,
-    defaultTimestampFormat: TimestampFormatTrait.Format
+    defaultTimestampFormat: TimestampFormatTrait.Format,
 ): Pair<String, Boolean> {
-
     return when (val shape = ctx.model.expectShape(memberShape.target)) {
         is TimestampShape -> {
             val timestampFormat = bindingIndex.determineTimestampFormat(memberShape, location, defaultTimestampFormat)
@@ -167,7 +169,7 @@ abstract class HttpBindingProtocolGenerator : ProtocolGenerator {
                     writer.openBlock(
                         "extension $symbolName: \$N {",
                         "}",
-                        SwiftTypes.Protocols.Encodable
+                        SwiftTypes.Protocols.Encodable,
                     ) {
                         writer.addImport(SwiftDependency.CLIENT_RUNTIME.target)
 
@@ -288,7 +290,7 @@ abstract class HttpBindingProtocolGenerator : ProtocolGenerator {
     private fun generateCodingKeysForMembers(
         ctx: ProtocolGenerator.GenerationContext,
         writer: SwiftWriter,
-        members: List<MemberShape>
+        members: List<MemberShape>,
     ) {
         codingKeysGenerator.generateCodingKeysForMembers(ctx, writer, members)
     }
@@ -300,7 +302,7 @@ abstract class HttpBindingProtocolGenerator : ProtocolGenerator {
             val inputType = ctx.model.expectShape(operation.input.get())
             var metadata = mapOf<ShapeMetadata, Any>(
                 Pair(ShapeMetadata.OPERATION_SHAPE, operation),
-                Pair(ShapeMetadata.SERVICE_VERSION, ctx.service.version)
+                Pair(ShapeMetadata.SERVICE_VERSION, ctx.service.version),
             )
             shapesInfo.put(inputType, metadata)
         }
@@ -338,7 +340,6 @@ abstract class HttpBindingProtocolGenerator : ProtocolGenerator {
     }
 
     private fun resolveShapesNeedingCodableConformance(ctx: ProtocolGenerator.GenerationContext): Set<Shape> {
-
         val topLevelOutputMembers = getHttpBindingOperations(ctx).flatMap {
             val outputShape = ctx.model.expectShape(it.output.get())
             outputShape.members()
@@ -392,7 +393,8 @@ abstract class HttpBindingProtocolGenerator : ProtocolGenerator {
                     RelationshipType.LIST_MEMBER,
                     RelationshipType.SET_MEMBER,
                     RelationshipType.MAP_VALUE,
-                    RelationshipType.UNION_MEMBER -> true
+                    RelationshipType.UNION_MEMBER,
+                    -> true
                     else -> false
                 }
             }.forEach {
@@ -405,6 +407,29 @@ abstract class HttpBindingProtocolGenerator : ProtocolGenerator {
         return resolved
     }
 
+    // Checks for @requiresLength trait
+    // Returns true if the operation:
+    // - has a streaming member with @httpPayload trait
+    // - target is a blob shape with @requiresLength trait
+    private fun hasRequiresLengthTrait(ctx: ProtocolGenerator.GenerationContext, op: OperationShape): Boolean {
+        if (op.input.isPresent) {
+            val inputShape = ctx.model.expectShape(op.input.get())
+            val streamingMember = inputShape.findStreamingMember(ctx.model)
+            if (streamingMember != null) {
+                val targetShape = ctx.model.expectShape(streamingMember.target)
+                if (targetShape != null) {
+                    return streamingMember.hasTrait<HttpPayloadTrait>() &&
+                        targetShape.isBlobShape &&
+                        targetShape.hasTrait<RequiresLengthTrait>()
+                }
+            }
+        }
+        return false
+    }
+
+    // Checks for @unsignedPayload trait on an operation
+    private fun hasUnsignedPayloadTrait(op: OperationShape): Boolean = op.hasTrait<UnsignedPayloadTrait>()
+
     override fun generateProtocolClient(ctx: ProtocolGenerator.GenerationContext) {
         val symbol = ctx.symbolProvider.toSymbol(ctx.service)
         ctx.delegator.useFileWriter("./${ctx.settings.moduleName}/${symbol.name}.swift") { writer ->
@@ -416,7 +441,7 @@ abstract class HttpBindingProtocolGenerator : ProtocolGenerator {
                 serviceSymbol.name,
                 defaultContentType,
                 httpProtocolCustomizable,
-                operationMiddleware
+                operationMiddleware,
             )
             clientGenerator.render()
         }
@@ -435,7 +460,7 @@ abstract class HttpBindingProtocolGenerator : ProtocolGenerator {
             operationMiddleware.appendMiddleware(operation, ContentTypeMiddleware(ctx.model, ctx.symbolProvider, resolver.determineRequestContentType(operation)))
             operationMiddleware.appendMiddleware(operation, OperationInputBodyMiddleware(ctx.model, ctx.symbolProvider))
 
-            operationMiddleware.appendMiddleware(operation, ContentLengthMiddleware(ctx.model, shouldRenderEncodableConformance))
+            operationMiddleware.appendMiddleware(operation, ContentLengthMiddleware(ctx.model, shouldRenderEncodableConformance, hasRequiresLengthTrait(ctx, operation), hasUnsignedPayloadTrait(operation)))
 
             operationMiddleware.appendMiddleware(operation, DeserializeMiddleware(ctx.model, ctx.symbolProvider))
             operationMiddleware.appendMiddleware(operation, LoggingMiddleware(ctx.model, ctx.symbolProvider))
@@ -469,7 +494,7 @@ abstract class HttpBindingProtocolGenerator : ProtocolGenerator {
         members: List<MemberShape>,
         writer: SwiftWriter,
         defaultTimestampFormat: TimestampFormatTrait.Format,
-        path: String? = null
+        path: String? = null,
     )
     protected abstract fun renderStructDecode(
         ctx: ProtocolGenerator.GenerationContext,
@@ -477,7 +502,7 @@ abstract class HttpBindingProtocolGenerator : ProtocolGenerator {
         members: List<MemberShape>,
         writer: SwiftWriter,
         defaultTimestampFormat: TimestampFormatTrait.Format,
-        path: String
+        path: String,
     )
     protected abstract fun addProtocolSpecificMiddleware(ctx: ProtocolGenerator.GenerationContext, operation: OperationShape)
 
@@ -493,11 +518,11 @@ abstract class HttpBindingProtocolGenerator : ProtocolGenerator {
         for (operation in topDownIndex.getContainedOperations(ctx.service)) {
             OptionalUtils.ifPresentOrElse(
                 Optional.of(getProtocolHttpBindingResolver(ctx, defaultContentType).httpTrait(operation)::class.java),
-                { containedOperations.add(operation) }
+                { containedOperations.add(operation) },
             ) {
                 LOGGER.warning(
                     "Unable to fetch $protocolName protocol request bindings for ${operation.id} because " +
-                        "it does not have an http binding trait"
+                        "it does not have an http binding trait",
                 )
             }
         }
diff --git a/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/integration/httpResponse/bindingTraits/HttpResponseTraitWithoutHttpPayload.kt b/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/integration/httpResponse/bindingTraits/HttpResponseTraitWithoutHttpPayload.kt
index 8cf4024a0..cd76dd545 100644
--- a/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/integration/httpResponse/bindingTraits/HttpResponseTraitWithoutHttpPayload.kt
+++ b/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/integration/httpResponse/bindingTraits/HttpResponseTraitWithoutHttpPayload.kt
@@ -50,15 +50,18 @@ class HttpResponseTraitWithoutHttpPayload(
             .filter { !it.member.hasTrait(HttpQueryTrait::class.java) }
             .toMutableSet()
         val streamingMember = bodyMembers.firstOrNull { it.member.targetOrSelf(ctx.model).hasTrait(StreamingTrait::class.java) }
-
         if (streamingMember != null) {
-            writeStreamingMember(streamingMember)
+            val initialResponseMembers = bodyMembers.filter {
+                val targetShape = it.member.targetOrSelf(ctx.model)
+                targetShape?.hasTrait(StreamingTrait::class.java) == false
+            }.toSet()
+            writeStreamingMember(streamingMember, initialResponseMembers)
         } else if (bodyMembersWithoutQueryTrait.isNotEmpty()) {
             writeNonStreamingMembers(bodyMembersWithoutQueryTrait)
         }
     }
 
-    fun writeStreamingMember(streamingMember: HttpBindingDescriptor) {
+    fun writeStreamingMember(streamingMember: HttpBindingDescriptor, initialResponseMembers: Set<HttpBindingDescriptor>) {
         val shape = ctx.model.expectShape(streamingMember.member.target)
         val symbol = ctx.symbolProvider.toSymbol(shape)
         val memberName = ctx.symbolProvider.toMemberName(streamingMember.member)
@@ -74,6 +77,9 @@ class HttpResponseTraitWithoutHttpPayload(
                         symbol
                     )
                     writer.write("self.\$L = decoderStream.toAsyncStream()", memberName)
+                    if (isRPCService(ctx) && initialResponseMembers.isNotEmpty()) {
+                        writeInitialResponseMembers(initialResponseMembers)
+                    }
                 }
                 writer.indent()
                 writer.write("self.\$L = nil", memberName).closeBlock("}")
@@ -133,4 +139,52 @@ class HttpResponseTraitWithoutHttpPayload(
     }
 
     private val path: String = "properties.".takeIf { outputShape.hasTrait<ErrorTrait>() } ?: ""
+
+    private fun writeInitialResponseMembers(initialResponseMembers: Set<HttpBindingDescriptor>) {
+        writer.apply {
+            write("if let initialDataWithoutHttp = await messageDecoder.awaitInitialResponse() {")
+            indent()
+            write("let decoder = JSONDecoder()")
+            write("do {")
+            indent()
+            write("let response = try decoder.decode([String: String].self, from: initialDataWithoutHttp)")
+            initialResponseMembers.forEach { responseMember ->
+                val responseMemberName = ctx.symbolProvider.toMemberName(responseMember.member)
+                write("self.$responseMemberName = response[\"$responseMemberName\"].map { value in KinesisClientTypes.Tag(value: value) }")
+            }
+            dedent()
+            write("} catch {")
+            indent()
+            write("print(\"Error decoding JSON: \\(error)\")")
+            initialResponseMembers.forEach { responseMember ->
+                val responseMemberName = ctx.symbolProvider.toMemberName(responseMember.member)
+                write("self.$responseMemberName = nil")
+            }
+            dedent()
+            write("}")
+            dedent()
+            write("} else {")
+            indent()
+            initialResponseMembers.forEach { responseMember ->
+                val responseMemberName = ctx.symbolProvider.toMemberName(responseMember.member)
+                write("self.$responseMemberName = nil")
+            }
+            dedent()
+            write("}")
+        }
+    }
+
+    private fun isRPCService(ctx: ProtocolGenerator.GenerationContext): Boolean {
+        return rpcBoundProtocols.contains(ctx.protocol.name)
+    }
+
+    /**
+     * A set of RPC-bound Smithy protocols
+     */
+    private val rpcBoundProtocols = setOf(
+        "awsJson1_0",
+        "awsJson1_1",
+        "awsQuery",
+        "ec2Query",
+    )
 }
diff --git a/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/integration/middlewares/ContentLengthMiddleware.kt b/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/integration/middlewares/ContentLengthMiddleware.kt
index 22d70721f..af6975535 100644
--- a/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/integration/middlewares/ContentLengthMiddleware.kt
+++ b/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/integration/middlewares/ContentLengthMiddleware.kt
@@ -9,7 +9,7 @@ import software.amazon.smithy.swift.codegen.middleware.MiddlewarePosition
 import software.amazon.smithy.swift.codegen.middleware.MiddlewareRenderable
 import software.amazon.smithy.swift.codegen.middleware.MiddlewareStep
 
-class ContentLengthMiddleware(val model: Model, private val alwaysIntercept: Boolean) : MiddlewareRenderable {
+class ContentLengthMiddleware(val model: Model, private val alwaysIntercept: Boolean, private val requiresLength: Boolean, private val unsignedPayload: Boolean) : MiddlewareRenderable {
 
     override val name = "ContentLengthMiddleware"
 
@@ -20,17 +20,17 @@ class ContentLengthMiddleware(val model: Model, private val alwaysIntercept: Boo
     override fun render(
         writer: SwiftWriter,
         op: OperationShape,
-        operationStackName: String
+        operationStackName: String,
     ) {
         val hasHttpBody = MiddlewareShapeUtils.hasHttpBody(model, op)
         if (hasHttpBody || alwaysIntercept) {
-            writer.write(
-                "\$L.\$L.intercept(position: \$L, middleware: \$N())",
-                operationStackName,
-                middlewareStep.stringValue(),
-                position.stringValue(),
-                ClientRuntimeTypes.Middleware.ContentLengthMiddleware
-            )
+            val str = "requiresLength: $requiresLength, unsignedPayload: $unsignedPayload"
+            val middlewareArgs = str.takeIf { requiresLength || unsignedPayload } ?: ""
+
+            val interceptStatement = "$operationStackName.${middlewareStep.stringValue()}.intercept(" +
+                "position: ${position.stringValue()}, middleware: ${ClientRuntimeTypes.Middleware.ContentLengthMiddleware}($middlewareArgs))"
+
+            writer.write(interceptStatement)
         }
     }
 }
diff --git a/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/integration/middlewares/IdempotencyTokenMiddleware.kt b/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/integration/middlewares/IdempotencyTokenMiddleware.kt
index 9f9963187..3fb6e4025 100644
--- a/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/integration/middlewares/IdempotencyTokenMiddleware.kt
+++ b/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/integration/middlewares/IdempotencyTokenMiddleware.kt
@@ -24,25 +24,26 @@ class IdempotencyTokenMiddleware(
     override val name = "IdempotencyTokenMiddleware"
     override val middlewareStep = MiddlewareStep.INITIALIZESTEP
     override val position = MiddlewarePosition.AFTER
-    override fun render(writer: SwiftWriter, op: OperationShape, operationStackName: String) {
 
+    override fun render(writer: SwiftWriter, op: OperationShape, operationStackName: String) {
         val inputShape = model.expectShape(op.input.get())
         val idempotentMember = inputShape.members().firstOrNull { it.hasTrait<IdempotencyTokenTrait>() }
         idempotentMember?.let {
             val idempotentMemberName = it.memberName.decapitalize()
+            val inputShapeName = MiddlewareShapeUtils.inputSymbol(symbolProvider, model, op).name
             val outputShapeName = MiddlewareShapeUtils.outputSymbol(symbolProvider, model, op).name
             val outputErrorShapeName = MiddlewareShapeUtils.outputErrorSymbolName(op)
-            writer.openBlock(
-                "$operationStackName.${middlewareStep.stringValue()}.intercept(position: ${position.stringValue()}, id: \"${name}\") { (context, input, next) -> \$N<$outputShapeName> in", "}",
-                ClientRuntimeTypes.Middleware.OperationOutput
-            ) {
-                writer.write("let idempotencyTokenGenerator = context.getIdempotencyTokenGenerator()")
-                writer.write("var copiedInput = input")
-                writer.openBlock("if input.$idempotentMemberName == nil {", "}") {
-                    writer.write("copiedInput.$idempotentMemberName = idempotencyTokenGenerator.generateToken()")
-                }
-                writer.write("return try await next.handle(context: context, input: copiedInput)")
-            }
+            writer.write(
+                "\$L.\$L.intercept(position: \$L, middleware: \$N<\$L, \$L, \$L>(keyPath: \\.\$L))",
+                operationStackName,
+                middlewareStep.stringValue(),
+                position.stringValue(),
+                ClientRuntimeTypes.Middleware.IdempotencyTokenMiddleware,
+                inputShapeName,
+                outputShapeName,
+                outputErrorShapeName,
+                idempotentMemberName
+            )
         }
     }
 }
diff --git a/smithy-swift-codegen/src/test/kotlin/ContentMd5MiddlewareTests.kt b/smithy-swift-codegen/src/test/kotlin/ContentMd5MiddlewareTests.kt
index 1931499d8..412500644 100644
--- a/smithy-swift-codegen/src/test/kotlin/ContentMd5MiddlewareTests.kt
+++ b/smithy-swift-codegen/src/test/kotlin/ContentMd5MiddlewareTests.kt
@@ -29,14 +29,7 @@ class ContentMd5MiddlewareTests {
                                   .withAuthSchemeResolver(value: config.serviceSpecific.authSchemeResolver)
                                   .build()
                     var operation = ClientRuntime.OperationStack<IdempotencyTokenWithStructureInput, IdempotencyTokenWithStructureOutput, IdempotencyTokenWithStructureOutputError>(id: "idempotencyTokenWithStructure")
-                    operation.initializeStep.intercept(position: .after, id: "IdempotencyTokenMiddleware") { (context, input, next) -> ClientRuntime.OperationOutput<IdempotencyTokenWithStructureOutput> in
-                        let idempotencyTokenGenerator = context.getIdempotencyTokenGenerator()
-                        var copiedInput = input
-                        if input.token == nil {
-                            copiedInput.token = idempotencyTokenGenerator.generateToken()
-                        }
-                        return try await next.handle(context: context, input: copiedInput)
-                    }
+                    operation.initializeStep.intercept(position: .after, middleware: ClientRuntime.IdempotencyTokenMiddleware<IdempotencyTokenWithStructureInput, IdempotencyTokenWithStructureOutput, IdempotencyTokenWithStructureOutputError>(keyPath: \.token))
                     operation.initializeStep.intercept(position: .after, middleware: ClientRuntime.URLPathMiddleware<IdempotencyTokenWithStructureInput, IdempotencyTokenWithStructureOutput, IdempotencyTokenWithStructureOutputError>())
                     operation.initializeStep.intercept(position: .after, middleware: ClientRuntime.URLHostMiddleware<IdempotencyTokenWithStructureInput, IdempotencyTokenWithStructureOutput>())
                     operation.buildStep.intercept(position: .before, middleware: ClientRuntime.ContentMD5Middleware<IdempotencyTokenWithStructureOutput>())
diff --git a/smithy-swift-codegen/src/test/kotlin/EventStreamsInitialResponseTests.kt b/smithy-swift-codegen/src/test/kotlin/EventStreamsInitialResponseTests.kt
new file mode 100644
index 000000000..ad10072bd
--- /dev/null
+++ b/smithy-swift-codegen/src/test/kotlin/EventStreamsInitialResponseTests.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+
+import io.kotest.matchers.string.shouldContainOnlyOnce
+import mocks.MockHttpAWSJson11ProtocolGenerator
+import org.junit.jupiter.api.Test
+import software.amazon.smithy.swift.codegen.integration.HttpBindingProtocolGenerator
+
+class EventStreamsInitialResponseTests {
+    @Test
+    fun `should attempt to decode response if initial-response members are present in RPC (awsJson) smithy model`() {
+        val context = setupInitialMessageTests(
+            "event-stream-initial-request-response.smithy",
+            "com.test#Example",
+            MockHttpAWSJson11ProtocolGenerator()
+        )
+        val contents = getFileContents(
+            context.manifest,
+            "/InitialMessageEventStreams/models/TestStreamOperationWithInitialRequestResponseOutput+HttpResponseBinding.swift"
+        )
+        contents.shouldSyntacticSanityCheck()
+        contents.shouldContainOnlyOnce(
+            """
+            extension TestStreamOperationWithInitialRequestResponseOutput: ClientRuntime.HttpResponseBinding {
+                public init(httpResponse: ClientRuntime.HttpResponse, decoder: ClientRuntime.ResponseDecoder? = nil) async throws {
+                    if case let .stream(stream) = httpResponse.body, let responseDecoder = decoder {
+                        let messageDecoder: ClientRuntime.MessageDecoder? = nil
+                        let decoderStream = ClientRuntime.EventStream.DefaultMessageDecoderStream<InitialMessageEventStreamsClientTypes.TestStream>(stream: stream, messageDecoder: messageDecoder, responseDecoder: responseDecoder)
+                        self.value = decoderStream.toAsyncStream()
+                        if let initialDataWithoutHttp = await messageDecoder.awaitInitialResponse() {
+                            let decoder = JSONDecoder()
+                            do {
+                                let response = try decoder.decode([String: String].self, from: initialDataWithoutHttp)
+                                self.initial1 = response["initial1"].map { value in KinesisClientTypes.Tag(value: value) }
+                                self.initial2 = response["initial2"].map { value in KinesisClientTypes.Tag(value: value) }
+                            } catch {
+                                print("Error decoding JSON: \(error)")
+                                self.initial1 = nil
+                                self.initial2 = nil
+                            }
+                        } else {
+                            self.initial1 = nil
+                            self.initial2 = nil
+                        }
+                    } else {
+                        self.value = nil
+                    }
+                }
+            }
+            """.trimIndent()
+        )
+    }
+
+    private fun setupInitialMessageTests(
+        smithyFile: String,
+        serviceShapeId: String,
+        protocolGenerator: HttpBindingProtocolGenerator
+    ): TestContext {
+        val context = TestContext.initContextFrom(smithyFile, serviceShapeId, protocolGenerator) { model ->
+            model.defaultSettings(serviceShapeId, "InitialMessageEventStreams", "123", "InitialMessageEventStreams")
+        }
+        context.generator.initializeMiddleware(context.generationCtx)
+        context.generator.generateSerializers(context.generationCtx)
+        context.generator.generateProtocolClient(context.generationCtx)
+        context.generator.generateDeserializers(context.generationCtx)
+        context.generator.generateCodableConformanceForNestedTypes(context.generationCtx)
+        context.generationCtx.delegator.flushWriters()
+        return context
+    }
+}
diff --git a/smithy-swift-codegen/src/test/kotlin/HttpBindingProtocolGeneratorTests.kt b/smithy-swift-codegen/src/test/kotlin/HttpBindingProtocolGeneratorTests.kt
index 46e608384..4f996a72b 100644
--- a/smithy-swift-codegen/src/test/kotlin/HttpBindingProtocolGeneratorTests.kt
+++ b/smithy-swift-codegen/src/test/kotlin/HttpBindingProtocolGeneratorTests.kt
@@ -38,7 +38,7 @@ class TestHttpProtocolClientGeneratorFactory : HttpProtocolClientGeneratorFactor
     private fun getClientProperties(ctx: ProtocolGenerator.GenerationContext): List<ClientProperty> {
         return mutableListOf(
             DefaultRequestEncoder(),
-            DefaultResponseDecoder()
+            DefaultResponseDecoder(),
         )
     }
 
@@ -125,6 +125,7 @@ extension InlineDocumentAsPayloadOutput: ClientRuntime.HttpResponseBinding {
             """.trimIndent()
         contents.shouldContainOnlyOnce(expectedContents)
     }
+
     @Test
     fun `default fooMap to an empty map if keysForFooMap is empty`() {
         val contents = getModelFileContents("example", "HttpPrefixHeadersOutput+HttpResponseBinding.swift", newTestContext.manifest)
diff --git a/smithy-swift-codegen/src/test/kotlin/HttpProtocolClientGeneratorTests.kt b/smithy-swift-codegen/src/test/kotlin/HttpProtocolClientGeneratorTests.kt
index fd8c8aaac..2bbf4a1d2 100644
--- a/smithy-swift-codegen/src/test/kotlin/HttpProtocolClientGeneratorTests.kt
+++ b/smithy-swift-codegen/src/test/kotlin/HttpProtocolClientGeneratorTests.kt
@@ -129,14 +129,7 @@ class HttpProtocolClientGeneratorTests {
                               .withAuthSchemeResolver(value: config.serviceSpecific.authSchemeResolver)
                               .build()
                 var operation = ClientRuntime.OperationStack<AllocateWidgetInput, AllocateWidgetOutput, AllocateWidgetOutputError>(id: "allocateWidget")
-                operation.initializeStep.intercept(position: .after, id: "IdempotencyTokenMiddleware") { (context, input, next) -> ClientRuntime.OperationOutput<AllocateWidgetOutput> in
-                    let idempotencyTokenGenerator = context.getIdempotencyTokenGenerator()
-                    var copiedInput = input
-                    if input.clientToken == nil {
-                        copiedInput.clientToken = idempotencyTokenGenerator.generateToken()
-                    }
-                    return try await next.handle(context: context, input: copiedInput)
-                }
+                operation.initializeStep.intercept(position: .after, middleware: ClientRuntime.IdempotencyTokenMiddleware<AllocateWidgetInput, AllocateWidgetOutput, AllocateWidgetOutputError>(keyPath: \.clientToken))
                 operation.initializeStep.intercept(position: .after, middleware: ClientRuntime.URLPathMiddleware<AllocateWidgetInput, AllocateWidgetOutput, AllocateWidgetOutputError>())
                 operation.initializeStep.intercept(position: .after, middleware: ClientRuntime.URLHostMiddleware<AllocateWidgetInput, AllocateWidgetOutput>())
                 operation.buildStep.intercept(position: .before, middleware: ClientRuntime.AuthSchemeMiddleware<AllocateWidgetOutput, AllocateWidgetOutputError>())
@@ -154,6 +147,123 @@ class HttpProtocolClientGeneratorTests {
         contents.shouldContainOnlyOnce(expected)
     }
 
+    @Test
+    fun `ContentLengthMiddleware generates correctly with requiresLength false and unsignedPayload true`() {
+        val context = setupTests("service-generator-test-operations.smithy", "com.test#Example")
+        val contents = getFileContents(context.manifest, "/RestJson/RestJsonProtocolClient.swift")
+        contents.shouldSyntacticSanityCheck()
+        val expected =
+            """
+            public func unsignedFooBlobStream(input: UnsignedFooBlobStreamInput) async throws -> UnsignedFooBlobStreamOutput
+                {
+                    let context = ClientRuntime.HttpContextBuilder()
+                                  .withEncoder(value: encoder)
+                                  .withDecoder(value: decoder)
+                                  .withMethod(value: .post)
+                                  .withServiceName(value: serviceName)
+                                  .withOperation(value: "unsignedFooBlobStream")
+                                  .withIdempotencyTokenGenerator(value: config.idempotencyTokenGenerator)
+                                  .withLogger(value: config.logger)
+                                  .withPartitionID(value: config.partitionID)
+                                  .withAuthSchemes(value: config.authSchemes!)
+                                  .withAuthSchemeResolver(value: config.serviceSpecific.authSchemeResolver)
+                                  .build()
+                    var operation = ClientRuntime.OperationStack<UnsignedFooBlobStreamInput, UnsignedFooBlobStreamOutput, UnsignedFooBlobStreamOutputError>(id: "unsignedFooBlobStream")
+                    operation.initializeStep.intercept(position: .after, middleware: ClientRuntime.URLPathMiddleware<UnsignedFooBlobStreamInput, UnsignedFooBlobStreamOutput, UnsignedFooBlobStreamOutputError>())
+                    operation.initializeStep.intercept(position: .after, middleware: ClientRuntime.URLHostMiddleware<UnsignedFooBlobStreamInput, UnsignedFooBlobStreamOutput>())
+                    operation.buildStep.intercept(position: .before, middleware: ClientRuntime.AuthSchemeMiddleware<UnsignedFooBlobStreamOutput, UnsignedFooBlobStreamOutputError>())
+                    operation.serializeStep.intercept(position: .after, middleware: ContentTypeMiddleware<UnsignedFooBlobStreamInput, UnsignedFooBlobStreamOutput>(contentType: "application/json"))
+                    operation.serializeStep.intercept(position: .after, middleware: ClientRuntime.SerializableBodyMiddleware<UnsignedFooBlobStreamInput, UnsignedFooBlobStreamOutput>(xmlName: "GetFooStreamingRequest"))
+                    operation.finalizeStep.intercept(position: .before, middleware: ClientRuntime.ContentLengthMiddleware(requiresLength: false, unsignedPayload: true))
+                    operation.finalizeStep.intercept(position: .after, middleware: ClientRuntime.RetryMiddleware<ClientRuntime.DefaultRetryStrategy, ClientRuntime.DefaultRetryErrorInfoProvider, UnsignedFooBlobStreamOutput, UnsignedFooBlobStreamOutputError>(options: config.retryStrategyOptions))
+                    operation.finalizeStep.intercept(position: .before, middleware: ClientRuntime.SignerMiddleware<UnsignedFooBlobStreamOutput, UnsignedFooBlobStreamOutputError>())
+                    operation.deserializeStep.intercept(position: .after, middleware: ClientRuntime.DeserializeMiddleware<UnsignedFooBlobStreamOutput, UnsignedFooBlobStreamOutputError>())
+                    operation.deserializeStep.intercept(position: .after, middleware: ClientRuntime.LoggerMiddleware<UnsignedFooBlobStreamOutput, UnsignedFooBlobStreamOutputError>(clientLogMode: config.clientLogMode))
+                    let result = try await operation.handleMiddleware(context: context, input: input, next: client.getHandler())
+                    return result
+                }
+            """.trimIndent()
+        contents.shouldContainOnlyOnce(expected)
+    }
+
+    @Test
+    fun `ContentLengthMiddleware generates correctly with requiresLength true and unsignedPayload false`() {
+        val context = setupTests("service-generator-test-operations.smithy", "com.test#Example")
+        val contents = getFileContents(context.manifest, "/RestJson/RestJsonProtocolClient.swift")
+        contents.shouldSyntacticSanityCheck()
+        val expected =
+            """
+            public func unsignedFooBlobStreamWithLength(input: UnsignedFooBlobStreamWithLengthInput) async throws -> UnsignedFooBlobStreamWithLengthOutput
+                {
+                    let context = ClientRuntime.HttpContextBuilder()
+                                  .withEncoder(value: encoder)
+                                  .withDecoder(value: decoder)
+                                  .withMethod(value: .post)
+                                  .withServiceName(value: serviceName)
+                                  .withOperation(value: "unsignedFooBlobStreamWithLength")
+                                  .withIdempotencyTokenGenerator(value: config.idempotencyTokenGenerator)
+                                  .withLogger(value: config.logger)
+                                  .withPartitionID(value: config.partitionID)
+                                  .withAuthSchemes(value: config.authSchemes!)
+                                  .withAuthSchemeResolver(value: config.serviceSpecific.authSchemeResolver)
+                                  .build()
+                    var operation = ClientRuntime.OperationStack<UnsignedFooBlobStreamWithLengthInput, UnsignedFooBlobStreamWithLengthOutput, UnsignedFooBlobStreamWithLengthOutputError>(id: "unsignedFooBlobStreamWithLength")
+                    operation.initializeStep.intercept(position: .after, middleware: ClientRuntime.URLPathMiddleware<UnsignedFooBlobStreamWithLengthInput, UnsignedFooBlobStreamWithLengthOutput, UnsignedFooBlobStreamWithLengthOutputError>())
+                    operation.initializeStep.intercept(position: .after, middleware: ClientRuntime.URLHostMiddleware<UnsignedFooBlobStreamWithLengthInput, UnsignedFooBlobStreamWithLengthOutput>())
+                    operation.buildStep.intercept(position: .before, middleware: ClientRuntime.AuthSchemeMiddleware<UnsignedFooBlobStreamWithLengthOutput, UnsignedFooBlobStreamWithLengthOutputError>())
+                    operation.serializeStep.intercept(position: .after, middleware: ContentTypeMiddleware<UnsignedFooBlobStreamWithLengthInput, UnsignedFooBlobStreamWithLengthOutput>(contentType: "application/octet-stream"))
+                    operation.serializeStep.intercept(position: .after, middleware: UnsignedFooBlobStreamWithLengthInputBodyMiddleware())
+                    operation.finalizeStep.intercept(position: .before, middleware: ClientRuntime.ContentLengthMiddleware(requiresLength: true, unsignedPayload: true))
+                    operation.finalizeStep.intercept(position: .after, middleware: ClientRuntime.RetryMiddleware<ClientRuntime.DefaultRetryStrategy, ClientRuntime.DefaultRetryErrorInfoProvider, UnsignedFooBlobStreamWithLengthOutput, UnsignedFooBlobStreamWithLengthOutputError>(options: config.retryStrategyOptions))
+                    operation.finalizeStep.intercept(position: .before, middleware: ClientRuntime.SignerMiddleware<UnsignedFooBlobStreamWithLengthOutput, UnsignedFooBlobStreamWithLengthOutputError>())
+                    operation.deserializeStep.intercept(position: .after, middleware: ClientRuntime.DeserializeMiddleware<UnsignedFooBlobStreamWithLengthOutput, UnsignedFooBlobStreamWithLengthOutputError>())
+                    operation.deserializeStep.intercept(position: .after, middleware: ClientRuntime.LoggerMiddleware<UnsignedFooBlobStreamWithLengthOutput, UnsignedFooBlobStreamWithLengthOutputError>(clientLogMode: config.clientLogMode))
+                    let result = try await operation.handleMiddleware(context: context, input: input, next: client.getHandler())
+                    return result
+                }
+            """.trimIndent()
+        contents.shouldContainOnlyOnce(expected)
+    }
+
+    @Test
+    fun `ContentLengthMiddleware generates correctly with requiresLength true and unsignedPayload true`() {
+        val context = setupTests("service-generator-test-operations.smithy", "com.test#Example")
+        val contents = getFileContents(context.manifest, "/RestJson/RestJsonProtocolClient.swift")
+        contents.shouldSyntacticSanityCheck()
+        val expected =
+            """
+            public func unsignedFooBlobStreamWithLength(input: UnsignedFooBlobStreamWithLengthInput) async throws -> UnsignedFooBlobStreamWithLengthOutput
+                {
+                    let context = ClientRuntime.HttpContextBuilder()
+                                  .withEncoder(value: encoder)
+                                  .withDecoder(value: decoder)
+                                  .withMethod(value: .post)
+                                  .withServiceName(value: serviceName)
+                                  .withOperation(value: "unsignedFooBlobStreamWithLength")
+                                  .withIdempotencyTokenGenerator(value: config.idempotencyTokenGenerator)
+                                  .withLogger(value: config.logger)
+                                  .withPartitionID(value: config.partitionID)
+                                  .withAuthSchemes(value: config.authSchemes!)
+                                  .withAuthSchemeResolver(value: config.serviceSpecific.authSchemeResolver)
+                                  .build()
+                    var operation = ClientRuntime.OperationStack<UnsignedFooBlobStreamWithLengthInput, UnsignedFooBlobStreamWithLengthOutput, UnsignedFooBlobStreamWithLengthOutputError>(id: "unsignedFooBlobStreamWithLength")
+                    operation.initializeStep.intercept(position: .after, middleware: ClientRuntime.URLPathMiddleware<UnsignedFooBlobStreamWithLengthInput, UnsignedFooBlobStreamWithLengthOutput, UnsignedFooBlobStreamWithLengthOutputError>())
+                    operation.initializeStep.intercept(position: .after, middleware: ClientRuntime.URLHostMiddleware<UnsignedFooBlobStreamWithLengthInput, UnsignedFooBlobStreamWithLengthOutput>())
+                    operation.buildStep.intercept(position: .before, middleware: ClientRuntime.AuthSchemeMiddleware<UnsignedFooBlobStreamWithLengthOutput, UnsignedFooBlobStreamWithLengthOutputError>())
+                    operation.serializeStep.intercept(position: .after, middleware: ContentTypeMiddleware<UnsignedFooBlobStreamWithLengthInput, UnsignedFooBlobStreamWithLengthOutput>(contentType: "application/octet-stream"))
+                    operation.serializeStep.intercept(position: .after, middleware: UnsignedFooBlobStreamWithLengthInputBodyMiddleware())
+                    operation.finalizeStep.intercept(position: .before, middleware: ClientRuntime.ContentLengthMiddleware(requiresLength: true, unsignedPayload: true))
+                    operation.finalizeStep.intercept(position: .after, middleware: ClientRuntime.RetryMiddleware<ClientRuntime.DefaultRetryStrategy, ClientRuntime.DefaultRetryErrorInfoProvider, UnsignedFooBlobStreamWithLengthOutput, UnsignedFooBlobStreamWithLengthOutputError>(options: config.retryStrategyOptions))
+                    operation.finalizeStep.intercept(position: .before, middleware: ClientRuntime.SignerMiddleware<UnsignedFooBlobStreamWithLengthOutput, UnsignedFooBlobStreamWithLengthOutputError>())
+                    operation.deserializeStep.intercept(position: .after, middleware: ClientRuntime.DeserializeMiddleware<UnsignedFooBlobStreamWithLengthOutput, UnsignedFooBlobStreamWithLengthOutputError>())
+                    operation.deserializeStep.intercept(position: .after, middleware: ClientRuntime.LoggerMiddleware<UnsignedFooBlobStreamWithLengthOutput, UnsignedFooBlobStreamWithLengthOutputError>(clientLogMode: config.clientLogMode))
+                    let result = try await operation.handleMiddleware(context: context, input: input, next: client.getHandler())
+                    return result
+                }
+            """.trimIndent()
+        contents.shouldContainOnlyOnce(expected)
+    }
+
     private fun setupTests(smithyFile: String, serviceShapeId: String): TestContext {
         val context = TestContext.initContextFrom(smithyFile, serviceShapeId, MockHttpRestJsonProtocolGenerator()) { model ->
             model.defaultSettings(serviceShapeId, "RestJson", "2019-12-16", "Rest Json Protocol")
diff --git a/smithy-swift-codegen/src/test/kotlin/IdempotencyTokenTraitTests.kt b/smithy-swift-codegen/src/test/kotlin/IdempotencyTokenTraitTests.kt
index 661568a78..381176188 100644
--- a/smithy-swift-codegen/src/test/kotlin/IdempotencyTokenTraitTests.kt
+++ b/smithy-swift-codegen/src/test/kotlin/IdempotencyTokenTraitTests.kt
@@ -29,14 +29,7 @@ class IdempotencyTokenTraitTests {
                                   .withAuthSchemeResolver(value: config.serviceSpecific.authSchemeResolver)
                                   .build()
                     var operation = ClientRuntime.OperationStack<IdempotencyTokenWithStructureInput, IdempotencyTokenWithStructureOutput, IdempotencyTokenWithStructureOutputError>(id: "idempotencyTokenWithStructure")
-                    operation.initializeStep.intercept(position: .after, id: "IdempotencyTokenMiddleware") { (context, input, next) -> ClientRuntime.OperationOutput<IdempotencyTokenWithStructureOutput> in
-                        let idempotencyTokenGenerator = context.getIdempotencyTokenGenerator()
-                        var copiedInput = input
-                        if input.token == nil {
-                            copiedInput.token = idempotencyTokenGenerator.generateToken()
-                        }
-                        return try await next.handle(context: context, input: copiedInput)
-                    }
+                    operation.initializeStep.intercept(position: .after, middleware: ClientRuntime.IdempotencyTokenMiddleware<IdempotencyTokenWithStructureInput, IdempotencyTokenWithStructureOutput, IdempotencyTokenWithStructureOutputError>(keyPath: \.token))
                     operation.initializeStep.intercept(position: .after, middleware: ClientRuntime.URLPathMiddleware<IdempotencyTokenWithStructureInput, IdempotencyTokenWithStructureOutput, IdempotencyTokenWithStructureOutputError>())
                     operation.initializeStep.intercept(position: .after, middleware: ClientRuntime.URLHostMiddleware<IdempotencyTokenWithStructureInput, IdempotencyTokenWithStructureOutput>())
                     operation.buildStep.intercept(position: .before, middleware: ClientRuntime.AuthSchemeMiddleware<IdempotencyTokenWithStructureOutput, IdempotencyTokenWithStructureOutputError>())
diff --git a/smithy-swift-codegen/src/test/kotlin/mocks/MockHttpAWSJson11ProtocolGenerator.kt b/smithy-swift-codegen/src/test/kotlin/mocks/MockHttpAWSJson11ProtocolGenerator.kt
index 30f5c040a..04d70b2f4 100644
--- a/smithy-swift-codegen/src/test/kotlin/mocks/MockHttpAWSJson11ProtocolGenerator.kt
+++ b/smithy-swift-codegen/src/test/kotlin/mocks/MockHttpAWSJson11ProtocolGenerator.kt
@@ -53,7 +53,8 @@ class MockAWSJson11HttpProtocolCustomizations() : DefaultHttpProtocolCustomizati
         writer: SwiftWriter,
         op: OperationShape,
     ) {
-        TODO("Not yet implemented")
+        // Not yet implemented
+        return
     }
 }
 
diff --git a/smithy-swift-codegen/src/test/resources/event-stream-initial-request-response.smithy b/smithy-swift-codegen/src/test/resources/event-stream-initial-request-response.smithy
new file mode 100644
index 000000000..417462aa9
--- /dev/null
+++ b/smithy-swift-codegen/src/test/resources/event-stream-initial-request-response.smithy
@@ -0,0 +1,39 @@
+namespace com.test
+
+use aws.protocols#awsJson1_1
+use aws.api#service
+use aws.auth#sigv4
+
+@awsJson1_1
+@sigv4(name: "event-stream-test")
+@service(sdkId: "InitialMessageEventStreams")
+service Example {
+    version: "123",
+    operations: [TestStreamOperationWithInitialRequestResponse]
+}
+
+operation TestStreamOperationWithInitialRequestResponse {
+    input: TestStreamInputOutputInitialRequestResponse,
+    output: TestStreamInputOutputInitialRequestResponse,
+    errors: [SomeError],
+}
+
+structure TestStreamInputOutputInitialRequestResponse {
+    @required
+    value: TestStream
+    initial1: String
+    initial2: String
+}
+
+@error("client")
+structure SomeError {
+    Message: String,
+}
+
+structure MessageWithString { @eventPayload data: String }
+
+@streaming
+union TestStream {
+    MessageWithString: MessageWithString,
+    SomeError: SomeError,
+}
\ No newline at end of file
diff --git a/smithy-swift-codegen/src/test/resources/service-generator-test-operations.smithy b/smithy-swift-codegen/src/test/resources/service-generator-test-operations.smithy
index 537e5531c..f1a6f4e71 100644
--- a/smithy-swift-codegen/src/test/resources/service-generator-test-operations.smithy
+++ b/smithy-swift-codegen/src/test/resources/service-generator-test-operations.smithy
@@ -2,6 +2,7 @@ $version: "1.0"
 namespace com.test
 
 use aws.protocols#awsJson1_1
+use aws.auth#unsignedPayload
 
 @awsJson1_1
 service Example {
@@ -15,7 +16,10 @@ service Example {
         GetFooStreamingOutputNoInput,
         GetFooStreamingInputNoOutput,
         AllocateWidget,
-        OperationWithDeprecatedTrait
+        OperationWithDeprecatedTrait,
+        UnsignedFooBlobStream,
+        UnsignedFooBlobStreamWithLength,
+        ExplicitBlobStreamWithLength
     ]
 }
 
@@ -89,4 +93,34 @@ operation AllocateWidget {
 structure AllocateWidgetInput {
     @idempotencyToken
     clientToken: String
+}
+
+// Stream must have a known size
+@streaming
+@requiresLength
+blob BodyStreamWithLength
+
+@http(method: "POST", uri: "/explicit/blobstreamunsigned")
+@unsignedPayload
+operation UnsignedFooBlobStream {
+    input: GetFooStreamingRequest,
+    output: GetFooStreamingResponse
+}
+
+@http(method: "POST", uri: "/explicit/blobstreamunsignedwithlength")
+@unsignedPayload
+operation UnsignedFooBlobStreamWithLength {
+    input: ExplicitBlobStreamWithLengthRequest,
+    output: GetFooStreamingResponse
+}
+
+@http(method: "POST", uri: "/explicit/blobstreamwithlength")
+operation ExplicitBlobStreamWithLength {
+    input: ExplicitBlobStreamWithLengthRequest,
+    output: GetFooStreamingResponse
+}
+
+structure ExplicitBlobStreamWithLengthRequest {
+    @httpPayload
+    payload1: BodyStreamWithLength
 }
\ No newline at end of file