From d8dac500b80438608e7946f17de863071e128c56 Mon Sep 17 00:00:00 2001 From: Adam Fowler Date: Fri, 28 Jul 2023 15:39:33 +0100 Subject: [PATCH] Merge request and response types (#569) * reorder execute * process response in execute * Collapse AWSHTTPResponse and AWSResponse into one * Collpase AWSRequest and AWSHTTPRequest into one * Add HTTP to request and response type names * Remove new middleware until we need it No need to include in this PR * Remove re-org to make PR review easier * Changes from PR comments * Another fix --- Sources/SotoCore/AWSClient.swift | 151 ++++++------ Sources/SotoCore/Encoder/QueryEncoder.swift | 2 +- .../SotoCore/Encoder/ResponseContainer.swift | 2 +- .../{AWSHTTPTypes.swift => AWSHTTPBody.swift} | 34 --- .../AWSHTTPRequest.swift} | 90 +++---- .../AWSHTTPResponse+HAL.swift} | 2 +- .../AWSHTTPResponse.swift} | 35 +-- Sources/SotoCore/Message/AWSMiddleware.swift | 11 +- .../Middleware/EditHeadersMiddleware.swift | 8 +- .../Middleware/LoggingMiddleware.swift | 10 +- .../Message/Middleware/S3Middleware.swift | 30 +-- .../Middleware/TreeHashMiddleware.swift | 6 +- Tests/SotoCoreTests/AWSClientTests.swift | 46 ---- Tests/SotoCoreTests/AWSRequestTests.swift | 226 +++++++++--------- Tests/SotoCoreTests/AWSResponseTests.swift | 68 ++---- Tests/SotoCoreTests/MiddlewareTests.swift | 14 +- Tests/SotoCoreTests/TimeStampTests.swift | 45 ++-- 17 files changed, 329 insertions(+), 451 deletions(-) rename Sources/SotoCore/HTTP/{AWSHTTPTypes.swift => AWSHTTPBody.swift} (79%) rename Sources/SotoCore/{Message/AWSRequest.swift => HTTP/AWSHTTPRequest.swift} (86%) rename Sources/SotoCore/{Message/AWSResponse+HAL.swift => HTTP/AWSHTTPResponse+HAL.swift} (98%) rename Sources/SotoCore/{Message/AWSResponse.swift => HTTP/AWSHTTPResponse.swift} (93%) diff --git a/Sources/SotoCore/AWSClient.swift b/Sources/SotoCore/AWSClient.swift index ad8fb86cc..64c98d0e8 100644 --- a/Sources/SotoCore/AWSClient.swift +++ b/Sources/SotoCore/AWSClient.swift @@ -247,18 +247,22 @@ extension AWSClient { return try await self.execute( operation: operationName, createRequest: { - try AWSRequest( + try AWSHTTPRequest( operation: operationName, path: path, - httpMethod: httpMethod, + method: httpMethod, input: input, hostPrefix: hostPrefix, configuration: serviceConfig ) }, processResponse: { response in - // flush response body contents to complete response read - for try await _ in response.body {} + return try await self.processEmptyResponse( + operation: operationName, + response: response, + serviceConfig: serviceConfig, + logger: logger + ) }, config: serviceConfig, logger: logger @@ -282,16 +286,20 @@ extension AWSClient { return try await self.execute( operation: operationName, createRequest: { - try AWSRequest( + try AWSHTTPRequest( operation: operationName, path: path, - httpMethod: httpMethod, + method: httpMethod, configuration: serviceConfig ) }, processResponse: { response in - // flush response body contents to complete response read - for try await _ in response.body {} + return try await self.processEmptyResponse( + operation: operationName, + response: response, + serviceConfig: serviceConfig, + logger: logger + ) }, config: serviceConfig, logger: logger @@ -317,15 +325,20 @@ extension AWSClient { return try await self.execute( operation: operationName, createRequest: { - try AWSRequest( + try AWSHTTPRequest( operation: operationName, path: path, - httpMethod: httpMethod, + method: httpMethod, configuration: serviceConfig ) }, processResponse: { response in - return try await self.validate(operation: operationName, response: response, serviceConfig: serviceConfig) + return try await self.processResponse( + operation: operationName, + response: response, + serviceConfig: serviceConfig, + logger: logger + ) }, config: serviceConfig, logger: logger @@ -355,17 +368,17 @@ extension AWSClient { return try await self.execute( operation: operationName, createRequest: { - try AWSRequest( + try AWSHTTPRequest( operation: operationName, path: path, - httpMethod: httpMethod, + method: httpMethod, input: input, hostPrefix: hostPrefix, configuration: serviceConfig ) }, processResponse: { response in - return try await self.validate(operation: operationName, response: response, serviceConfig: serviceConfig) + return try await self.processResponse(operation: operationName, response: response, serviceConfig: serviceConfig, logger: logger) }, config: serviceConfig, logger: logger @@ -375,7 +388,7 @@ extension AWSClient { /// internal version of execute internal func execute( operation operationName: String, - createRequest: @escaping () throws -> AWSRequest, + createRequest: @escaping () throws -> AWSHTTPRequest, processResponse: @escaping (AWSHTTPResponse) async throws -> Output, config: AWSServiceConfig, logger: Logger = AWSClient.loggingDisabled @@ -396,18 +409,17 @@ extension AWSClient { // construct signer let signer = AWSSigner(credentials: credential, name: config.signingName, region: config.region.rawValue) // create request and sign with signer - let awsRequest = try createRequest() - .applyMiddlewares(config.middlewares + self.middlewares, config: config) - .createHTTPRequest(signer: signer, serviceConfig: config) - // send request to AWS and process result - let streaming = awsRequest.body.isStreaming + var request = try createRequest() + .applyMiddlewares(config.middlewares + self.middlewares, context: .init(operation: operationName, serviceConfig: config)) + request.signHeaders(signer: signer, serviceConfig: config) try Task.checkCancellation() + // apply middleware and sign let response = try await self.invoke( - request: awsRequest, + request: request, + operation: operationName, with: config, logger: logger, - processResponse: processResponse, - streaming: streaming + processResponse: processResponse ) logger.trace("AWS Response") Metrics.Timer( @@ -431,30 +443,25 @@ extension AWSClient { func invoke( request: AWSHTTPRequest, + operation operationName: String, with serviceConfig: AWSServiceConfig, logger: Logger, - processResponse: @escaping (AWSHTTPResponse) async throws -> Output, - streaming: Bool + processResponse: @escaping (AWSHTTPResponse) async throws -> Output ) async throws -> Output { var attempt = 0 while true { do { let response = try await self.httpClient.execute(request: request, timeout: serviceConfig.timeout, logger: logger) - // if it returns an HTTP status code outside 2xx then throw an error + .applyMiddlewares(serviceConfig.middlewares + self.middlewares, context: .init(operation: operationName, serviceConfig: serviceConfig)) + // if response has an HTTP status code outside 2xx then throw an error guard (200..<300).contains(response.status.code) else { - let error = try await self.createError(for: response, serviceConfig: serviceConfig, logger: logger) + let error = await self.createError(for: response, serviceConfig: serviceConfig, logger: logger) throw error } + let output = try await processResponse(response) return output } catch { - // if streaming and the error returned is an AWS error fail immediately. Do not attempt - // to retry as the streaming function will not know you are retrying - if streaming, - error is AWSErrorType || error is AWSRawError - { - throw error - } // If I get a retry wait time for this error then attempt to retry request if case .retry(let retryTime) = self.retryPolicy.getRetryWaitTime(error: error, attempt: attempt) { logger.trace("Retrying request", metadata: [ @@ -553,26 +560,37 @@ extension AWSClient { // response validator extension AWSClient { /// Generate an AWS Response from the operation HTTP response and return the output shape from it. This is only every called if the response includes a successful http status code - internal func validate( + internal func processResponse( operation operationName: String, response: AWSHTTPResponse, - serviceConfig: AWSServiceConfig + serviceConfig: AWSServiceConfig, + logger: Logger ) async throws -> Output { - assert((200..<300).contains(response.status.code), "Shouldn't get here if error was returned") - let raw = Output._options.contains(.rawPayload) == true - let awsResponse = try await AWSResponse(from: response, streaming: raw) - .applyMiddlewares(serviceConfig.middlewares + middlewares, config: serviceConfig) + var response = response + if !raw { + try await response.collateBody() + } + return try response.generateOutputShape(operation: operationName, serviceProtocol: serviceConfig.serviceProtocol) + } - return try awsResponse.generateOutputShape(operation: operationName, serviceProtocol: serviceConfig.serviceProtocol) + /// Generate an AWS Response from the operation HTTP response and return the output shape from it. This is only ever called if the response includes a successful http status code + internal func processEmptyResponse( + operation operationName: String, + response: AWSHTTPResponse, + serviceConfig: AWSServiceConfig, + logger: Logger + ) async throws { + // flush response body contents to complete response read + for try await _ in response.body {} } /// Create error from HTTPResponse. This is only called if we received an unsuccessful http status code. - internal func createError(for response: AWSHTTPResponse, serviceConfig: AWSServiceConfig, logger: Logger) async throws -> Error { + internal func createError(for response: AWSHTTPResponse, serviceConfig: AWSServiceConfig, logger: Logger) async -> Error { // if we can create an AWSResponse and create an error from it return that - let awsResponse: AWSResponse + var response = response do { - awsResponse = try await AWSResponse(from: response, streaming: false) + try await response.collateBody() } catch { // else return "Unhandled error message" with rawBody attached let context = AWSErrorContext( @@ -582,32 +600,27 @@ extension AWSClient { ) return AWSRawError(rawBody: nil, context: context) } - do { - let awsResponseWithMiddleware = try awsResponse.applyMiddlewares(serviceConfig.middlewares + middlewares, config: serviceConfig) - if let error = awsResponseWithMiddleware.generateError( - serviceConfig: serviceConfig, - logLevel: options.errorLogLevel, - logger: logger - ) { - return error - } else { - // else return "Unhandled error message" with rawBody attached - let context = AWSErrorContext( - message: "Unhandled Error", - responseCode: response.status, - headers: response.headers - ) - let responseBody: String? - switch awsResponseWithMiddleware.body.storage { - case .byteBuffer(let buffer): - responseBody = String(buffer: buffer) - default: - responseBody = nil - } - return AWSRawError(rawBody: responseBody, context: context) - } - } catch { + if let error = response.generateError( + serviceConfig: serviceConfig, + logLevel: options.errorLogLevel, + logger: logger + ) { return error + } else { + // else return "Unhandled error message" with rawBody attached + let context = AWSErrorContext( + message: "Unhandled Error", + responseCode: response.status, + headers: response.headers + ) + let responseBody: String? + switch response.body.storage { + case .byteBuffer(let buffer): + responseBody = String(buffer: buffer) + default: + responseBody = nil + } + return AWSRawError(rawBody: responseBody, context: context) } } } diff --git a/Sources/SotoCore/Encoder/QueryEncoder.swift b/Sources/SotoCore/Encoder/QueryEncoder.swift index 178c5ad47..c8f6d0d25 100644 --- a/Sources/SotoCore/Encoder/QueryEncoder.swift +++ b/Sources/SotoCore/Encoder/QueryEncoder.swift @@ -55,7 +55,7 @@ public struct QueryEncoder { static let queryAllowedCharacters = CharacterSet(charactersIn: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~") private static func urlEncodeQueryParam(_ value: String) -> String { - return value.addingPercentEncoding(withAllowedCharacters: AWSRequest.queryAllowedCharacters) ?? value + return value.addingPercentEncoding(withAllowedCharacters: AWSHTTPRequest.queryAllowedCharacters) ?? value } // generate string from diff --git a/Sources/SotoCore/Encoder/ResponseContainer.swift b/Sources/SotoCore/Encoder/ResponseContainer.swift index 0f5b56777..330ba8f7e 100644 --- a/Sources/SotoCore/Encoder/ResponseContainer.swift +++ b/Sources/SotoCore/Encoder/ResponseContainer.swift @@ -26,7 +26,7 @@ public struct HeaderDecodingError: Error { } public struct ResponseDecodingContainer { - let response: AWSResponse + let response: AWSHTTPResponse public func decode(_ type: Value.Type = Value.self, forHeader header: String) throws -> Value where Value.RawValue == String { guard let headerValue = response.headers[header].first else { diff --git a/Sources/SotoCore/HTTP/AWSHTTPTypes.swift b/Sources/SotoCore/HTTP/AWSHTTPBody.swift similarity index 79% rename from Sources/SotoCore/HTTP/AWSHTTPTypes.swift rename to Sources/SotoCore/HTTP/AWSHTTPBody.swift index 0f4035a70..01765e405 100644 --- a/Sources/SotoCore/HTTP/AWSHTTPTypes.swift +++ b/Sources/SotoCore/HTTP/AWSHTTPBody.swift @@ -100,37 +100,3 @@ extension AWSHTTPBody: Decodable { preconditionFailure("Cannot decode an AWSHTTPBody") } } - -/// HTTP Request -struct AWSHTTPRequest { - let url: URL - let method: HTTPMethod - let headers: HTTPHeaders - let body: AWSHTTPBody - - init(url: URL, method: HTTPMethod, headers: HTTPHeaders = [:], body: AWSHTTPBody = .init()) { - self.url = url - self.method = method - self.headers = headers - self.body = body - } -} - -/// Generic HTTP Response returned from HTTP Client -struct AWSHTTPResponse: Sendable { - /// Initialize AWSHTTPResponse - init(status: HTTPResponseStatus, headers: HTTPHeaders, body: AWSHTTPBody = .init()) { - self.status = status - self.headers = headers - self.body = body - } - - /// The HTTP status for this response. - var status: HTTPResponseStatus - - /// The HTTP headers of this response. - var headers: HTTPHeaders - - /// The body of this HTTP response. - var body: AWSHTTPBody -} diff --git a/Sources/SotoCore/Message/AWSRequest.swift b/Sources/SotoCore/HTTP/AWSHTTPRequest.swift similarity index 86% rename from Sources/SotoCore/Message/AWSRequest.swift rename to Sources/SotoCore/HTTP/AWSHTTPRequest.swift index cb433e059..25472018e 100644 --- a/Sources/SotoCore/Message/AWSRequest.swift +++ b/Sources/SotoCore/HTTP/AWSHTTPRequest.swift @@ -23,40 +23,26 @@ import NIOHTTP1 import SotoSignerV4 /// Object encapsulating all the information needed to generate a raw HTTP request to AWS -public struct AWSRequest { - /// request AWS region - public let region: Region +public struct AWSHTTPRequest { /// request URL public var url: URL - /// request communication protocol - public let serviceProtocol: ServiceProtocol - /// AWS operation name - public let operation: String /// request HTTP method - public let httpMethod: HTTPMethod + public let method: HTTPMethod /// request headers - public var httpHeaders: HTTPHeaders + public var headers: HTTPHeaders /// request body public var body: AWSHTTPBody - /// Create HTTP Client request from AWSRequest. - /// If the signer's credentials are available the request will be signed. Otherwise defaults to an unsigned request - func createHTTPRequest(signer: AWSSigner, serviceConfig: AWSServiceConfig) -> AWSHTTPRequest { - // if credentials are empty don't sign request - if signer.credentials.isEmpty() { - return self.toHTTPRequest(byteBufferAllocator: serviceConfig.byteBufferAllocator) - } - - return self.toHTTPRequestWithSignedHeader(signer: signer, serviceConfig: serviceConfig) - } - - /// Create HTTP Client request from AWSRequest - func toHTTPRequest(byteBufferAllocator: ByteBufferAllocator) -> AWSHTTPRequest { - return AWSHTTPRequest(url: url, method: httpMethod, headers: httpHeaders, body: body) + internal init(url: URL, method: HTTPMethod, headers: HTTPHeaders, body: AWSHTTPBody) { + self.url = url + self.method = method + self.headers = headers + self.body = body } - /// Create HTTP Client request with signed headers from AWSRequest - func toHTTPRequestWithSignedHeader(signer: AWSSigner, serviceConfig: AWSServiceConfig) -> AWSHTTPRequest { + /// Create signed headers for request + mutating func signHeaders(signer: AWSSigner, serviceConfig: AWSServiceConfig) { + guard !signer.credentials.isEmpty() else { return } let payload = self.body let bodyDataForSigning: AWSSigner.BodyData? switch payload.storage { @@ -65,30 +51,32 @@ public struct AWSRequest { case .asyncSequence(let sequence, let length): if signer.name == "s3", !serviceConfig.options.contains(.s3DisableChunkedUploads) { assert(length != nil, "S3 stream requires size") - var headers = httpHeaders + var headers = headers // need to add these headers here as it needs to be included in the signed headers headers.add(name: "x-amz-decoded-content-length", value: length!.description) headers.add(name: "content-encoding", value: "aws-chunked") // get signed headers and seed signing data - let (signedHeaders, seedSigningData) = signer.startSigningChunks(url: url, method: httpMethod, headers: headers, date: Date()) + let (signedHeaders, seedSigningData) = signer.startSigningChunks(url: url, method: method, headers: headers, date: Date()) // create s3 signed Sequence let s3Signed = sequence.s3Signed(signer: signer, seedSigningData: seedSigningData) // create new payload and return request let payload = AWSHTTPBody(asyncSequence: s3Signed, length: s3Signed.contentSize(from: length!)) - return AWSHTTPRequest(url: url, method: httpMethod, headers: signedHeaders, body: payload) + + self.headers = signedHeaders + self.body = payload + return } else { bodyDataForSigning = .unsignedPayload } } - let signedHeaders = signer.signHeaders(url: url, method: httpMethod, headers: httpHeaders, body: bodyDataForSigning, date: Date()) - return AWSHTTPRequest(url: url, method: httpMethod, headers: signedHeaders, body: payload) + let signedHeaders = signer.signHeaders(url: url, method: method, headers: headers, body: bodyDataForSigning, date: Date()) + self.headers = signedHeaders } // return new request with middleware applied - func applyMiddlewares(_ middlewares: [AWSServiceMiddleware], config: AWSServiceConfig) throws -> AWSRequest { + func applyMiddlewares(_ middlewares: [AWSServiceMiddleware], context: AWSMiddlewareContext) throws -> AWSHTTPRequest { var awsRequest = self // apply middleware to request - let context = AWSMiddlewareContext(options: config.options) for middleware in middlewares { awsRequest = try middleware.chain(request: awsRequest, context: context) } @@ -96,8 +84,8 @@ public struct AWSRequest { } } -extension AWSRequest { - internal init(operation operationName: String, path: String, httpMethod: HTTPMethod, configuration: AWSServiceConfig) throws { +extension AWSHTTPRequest { + internal init(operation operationName: String, path: String, method: HTTPMethod, configuration: AWSServiceConfig) throws { var headers = HTTPHeaders() guard let url = URL(string: "\(configuration.endpoint)\(path)"), let _ = url.host else { @@ -109,12 +97,9 @@ extension AWSRequest { headers.replaceOrAdd(name: "x-amz-target", value: "\(target).\(operationName)") } - self.region = configuration.region self.url = url - self.serviceProtocol = configuration.serviceProtocol - self.operation = operationName - self.httpMethod = httpMethod - self.httpHeaders = headers + self.method = method + self.headers = headers // Query and EC2 protocols require the Action and API Version in the body switch configuration.serviceProtocol { case .query, .ec2: @@ -134,7 +119,7 @@ extension AWSRequest { internal init( operation operationName: String, path: String, - httpMethod: HTTPMethod, + method: HTTPMethod, input: Input, hostPrefix: String? = nil, configuration: AWSServiceConfig @@ -224,7 +209,7 @@ extension AWSRequest { // only include the body if there are members that are output in the body. if memberVariablesCount > 0 { body = try .init(buffer: input.encodeAsJSON(byteBufferAllocator: configuration.byteBufferAllocator)) - } else if httpMethod == .PUT || httpMethod == .POST { + } else if method == .PUT || method == .POST { // PUT and POST requests require a body even if it is empty. This is not the case with XML body = .init(buffer: configuration.byteBufferAllocator.buffer(string: "{}")) } else { @@ -321,12 +306,9 @@ extension AWSRequest { configuration: configuration ) - self.region = configuration.region self.url = url - self.serviceProtocol = configuration.serviceProtocol - self.operation = operationName - self.httpMethod = httpMethod - self.httpHeaders = headers + self.method = method + self.headers = headers self.body = body addStandardHeaders(serviceProtocol: configuration.serviceProtocol, raw: raw) @@ -396,20 +378,20 @@ extension AWSRequest { /// Add headers standard to all requests "content-type" and "user-agent" private mutating func addStandardHeaders(serviceProtocol: ServiceProtocol, raw: Bool) { - httpHeaders.add(name: "user-agent", value: "Soto/6.0") - guard httpHeaders["content-type"].first == nil else { + headers.add(name: "user-agent", value: "Soto/6.0") + guard headers["content-type"].first == nil else { return } - guard httpMethod != .GET, httpMethod != .HEAD else { + guard method != .GET, method != .HEAD else { return } if case .byteBuffer(let buffer) = body.storage, buffer.readableBytes == 0 { // don't add a content-type header when there is no content } else if case .restjson = serviceProtocol, raw { - httpHeaders.replaceOrAdd(name: "content-type", value: "binary/octet-stream") + headers.replaceOrAdd(name: "content-type", value: "binary/octet-stream") } else { - httpHeaders.replaceOrAdd(name: "content-type", value: serviceProtocol.contentType) + headers.replaceOrAdd(name: "content-type", value: serviceProtocol.contentType) } } @@ -420,17 +402,17 @@ extension AWSRequest { /// percent encode query parameter value. private static func urlEncodeQueryParam(_ value: String) -> String { - return value.addingPercentEncoding(withAllowedCharacters: AWSRequest.queryAllowedCharacters) ?? value + return value.addingPercentEncoding(withAllowedCharacters: AWSHTTPRequest.queryAllowedCharacters) ?? value } /// percent encode path value. private static func urlEncodePath(_ value: String) -> String { - return value.addingPercentEncoding(withAllowedCharacters: AWSRequest.pathAllowedCharacters) ?? value + return value.addingPercentEncoding(withAllowedCharacters: AWSHTTPRequest.pathAllowedCharacters) ?? value } /// percent encode path component value. ie also encode "/" private static func urlEncodePathComponent(_ value: String) -> String { - return value.addingPercentEncoding(withAllowedCharacters: AWSRequest.pathComponentAllowedCharacters) ?? value + return value.addingPercentEncoding(withAllowedCharacters: AWSHTTPRequest.pathComponentAllowedCharacters) ?? value } /// verify streaming is allowed for this operation diff --git a/Sources/SotoCore/Message/AWSResponse+HAL.swift b/Sources/SotoCore/HTTP/AWSHTTPResponse+HAL.swift similarity index 98% rename from Sources/SotoCore/Message/AWSResponse+HAL.swift rename to Sources/SotoCore/HTTP/AWSHTTPResponse+HAL.swift index c0d4bcab2..6c642d2d1 100644 --- a/Sources/SotoCore/Message/AWSResponse+HAL.swift +++ b/Sources/SotoCore/HTTP/AWSHTTPResponse+HAL.swift @@ -17,7 +17,7 @@ import class Foundation.JSONSerialization import NIOCore // AWS HAL services I know of are APIGateway, Pinpoint, Greengrass -extension AWSResponse { +extension AWSHTTPResponse { /// return if body is hypertext application language var isHypertextApplicationLanguage: Bool { guard let contentType = self.headers["content-type"].first, diff --git a/Sources/SotoCore/Message/AWSResponse.swift b/Sources/SotoCore/HTTP/AWSHTTPResponse.swift similarity index 93% rename from Sources/SotoCore/Message/AWSResponse.swift rename to Sources/SotoCore/HTTP/AWSHTTPResponse.swift index a33e087e8..448264e99 100644 --- a/Sources/SotoCore/Message/AWSResponse.swift +++ b/Sources/SotoCore/HTTP/AWSHTTPResponse.swift @@ -26,8 +26,8 @@ import NIOFoundationCompat import NIOHTTP1 import SotoXML -/// Structure encapsulating a processed HTTP Response -public struct AWSResponse { +/// Structure encapsulating an HTTP Response +public struct AWSHTTPResponse { /// response status public let status: HTTPResponseStatus /// response headers @@ -35,30 +35,21 @@ public struct AWSResponse { /// response body public var body: AWSHTTPBody - /// initialize an AWSResponse Object - /// - parameters: - /// - from: Raw HTTP Response - /// - streaming: Whether Body should be treated as streamed data or collated into - /// one ByteBuffer - init(from response: AWSHTTPResponse, streaming: Bool) async throws { - self.status = response.status - - // headers - self.headers = response.headers - - // body - if streaming { - self.body = response.body - } else { - self.body = try await .init(buffer: response.body.collect(upTo: .max)) - } + /// Initialize AWSResponse + init(status: HTTPResponseStatus, headers: HTTPHeaders, body: AWSHTTPBody = .init()) { + self.status = status + self.headers = headers + self.body = body + } + + mutating func collateBody() async throws { + self.body = try await .init(buffer: self.body.collect(upTo: .max)) } /// return new response with middleware applied - func applyMiddlewares(_ middlewares: [AWSServiceMiddleware], config: AWSServiceConfig) throws -> AWSResponse { + func applyMiddlewares(_ middlewares: [AWSServiceMiddleware], context: AWSMiddlewareContext) throws -> AWSHTTPResponse { var awsResponse = self - // apply middleware to respons - let context = AWSMiddlewareContext(options: config.options) + // apply middleware to response for middleware in middlewares { awsResponse = try middleware.chain(response: awsResponse, context: context) } diff --git a/Sources/SotoCore/Message/AWSMiddleware.swift b/Sources/SotoCore/Message/AWSMiddleware.swift index 89ff1c6c6..1ae5996e5 100644 --- a/Sources/SotoCore/Message/AWSMiddleware.swift +++ b/Sources/SotoCore/Message/AWSMiddleware.swift @@ -14,25 +14,26 @@ /// Context object sent to `AWSServiceMiddleware` `chain` functions public struct AWSMiddlewareContext { - public let options: AWSServiceConfig.Options + public let operation: String + public let serviceConfig: AWSServiceConfig } /// Middleware protocol. Process requests before they are sent to AWS and process responses before they are converted into output shapes public protocol AWSServiceMiddleware: Sendable { /// Process AWSRequest before it is converted to a HTTPClient Request to be sent to AWS - func chain(request: AWSRequest, context: AWSMiddlewareContext) throws -> AWSRequest + func chain(request: AWSHTTPRequest, context: AWSMiddlewareContext) throws -> AWSHTTPRequest /// Process response before it is converted to an output AWSShape - func chain(response: AWSResponse, context: AWSMiddlewareContext) throws -> AWSResponse + func chain(response: AWSHTTPResponse, context: AWSMiddlewareContext) throws -> AWSHTTPResponse } /// Default versions of protocol functions public extension AWSServiceMiddleware { - func chain(request: AWSRequest, context: AWSMiddlewareContext) throws -> AWSRequest { + func chain(request: AWSHTTPRequest, context: AWSMiddlewareContext) throws -> AWSHTTPRequest { return request } - func chain(response: AWSResponse, context: AWSMiddlewareContext) throws -> AWSResponse { + func chain(response: AWSHTTPResponse, context: AWSMiddlewareContext) throws -> AWSHTTPResponse { return response } } diff --git a/Sources/SotoCore/Message/Middleware/EditHeadersMiddleware.swift b/Sources/SotoCore/Message/Middleware/EditHeadersMiddleware.swift index 2d0b52454..3c6a8b6ce 100644 --- a/Sources/SotoCore/Message/Middleware/EditHeadersMiddleware.swift +++ b/Sources/SotoCore/Message/Middleware/EditHeadersMiddleware.swift @@ -32,16 +32,16 @@ public struct AWSEditHeadersMiddleware: AWSServiceMiddleware { self.init(edits) } - public func chain(request: AWSRequest, context: AWSMiddlewareContext) throws -> AWSRequest { + public func chain(request: AWSHTTPRequest, context: AWSMiddlewareContext) throws -> AWSHTTPRequest { var request = request for edit in self.edits { switch edit { case .add(let name, let value): - request.httpHeaders.add(name: name, value: value) + request.headers.add(name: name, value: value) case .replace(let name, let value): - request.httpHeaders.replaceOrAdd(name: name, value: value) + request.headers.replaceOrAdd(name: name, value: value) case .remove(let name): - request.httpHeaders.remove(name: name) + request.headers.remove(name: name) } } return request diff --git a/Sources/SotoCore/Message/Middleware/LoggingMiddleware.swift b/Sources/SotoCore/Message/Middleware/LoggingMiddleware.swift index 6fd0f431b..23768f77f 100644 --- a/Sources/SotoCore/Message/Middleware/LoggingMiddleware.swift +++ b/Sources/SotoCore/Message/Middleware/LoggingMiddleware.swift @@ -57,19 +57,19 @@ public struct AWSLoggingMiddleware: AWSServiceMiddleware { } /// output request - public func chain(request: AWSRequest, context: AWSMiddlewareContext) throws -> AWSRequest { + public func chain(request: AWSHTTPRequest, context: AWSMiddlewareContext) throws -> AWSHTTPRequest { self.log( "Request:\n" + - " \(request.operation)\n" + - " \(request.httpMethod) \(request.url)\n" + - " Headers: \(self.getHeadersOutput(request.httpHeaders))\n" + + " \(context.operation)\n" + + " \(request.method) \(request.url)\n" + + " Headers: \(self.getHeadersOutput(request.headers))\n" + " Body: \(self.getBodyOutput(request.body))" ) return request } /// output response - public func chain(response: AWSResponse, context: AWSMiddlewareContext) throws -> AWSResponse { + public func chain(response: AWSHTTPResponse, context: AWSMiddlewareContext) throws -> AWSHTTPResponse { self.log( "Response:\n" + " Status : \(response.status.code)\n" + diff --git a/Sources/SotoCore/Message/Middleware/S3Middleware.swift b/Sources/SotoCore/Message/Middleware/S3Middleware.swift index 9bbbffd77..fcfa4141c 100644 --- a/Sources/SotoCore/Message/Middleware/S3Middleware.swift +++ b/Sources/SotoCore/Message/Middleware/S3Middleware.swift @@ -33,12 +33,12 @@ public struct S3Middleware: AWSServiceMiddleware { public init() {} /// edit request before sending to S3 - public func chain(request: AWSRequest, context: AWSMiddlewareContext) throws -> AWSRequest { + public func chain(request: AWSHTTPRequest, context: AWSMiddlewareContext) throws -> AWSHTTPRequest { var request = request self.virtualAddressFixup(request: &request, context: context) - self.createBucketFixup(request: &request) - if !context.options.contains(.s3Disable100Continue) { + self.createBucketFixup(request: &request, context: context) + if !context.serviceConfig.options.contains(.s3Disable100Continue) { self.expect100Continue(request: &request) } @@ -46,7 +46,7 @@ public struct S3Middleware: AWSServiceMiddleware { } /// Edit responses coming back from S3 - public func chain(response: AWSResponse, context: AWSMiddlewareContext) throws -> AWSResponse { + public func chain(response: AWSHTTPResponse, context: AWSMiddlewareContext) throws -> AWSHTTPResponse { var response = response // self.getLocationResponseFixup(response: &response) @@ -55,7 +55,7 @@ public struct S3Middleware: AWSServiceMiddleware { return response } - func virtualAddressFixup(request: inout AWSRequest, context: AWSMiddlewareContext) { + func virtualAddressFixup(request: inout AWSHTTPRequest, context: AWSMiddlewareContext) { /// process URL into form ${bucket}.s3.amazon.com let paths = request.url.path.split(separator: "/", omittingEmptySubsequences: true) if paths.count > 0 { @@ -69,7 +69,7 @@ public struct S3Middleware: AWSServiceMiddleware { let isAmazonUrl = host.hasSuffix("amazonaws.com") var hostComponents = host.split(separator: ".") - if isAmazonUrl, context.options.contains(.s3UseTransferAcceleratedEndpoint) { + if isAmazonUrl, context.serviceConfig.options.contains(.s3UseTransferAcceleratedEndpoint) { if let s3Index = hostComponents.firstIndex(where: { $0 == "s3" }) { var s3 = "s3" s3 += "-accelerate" @@ -82,7 +82,7 @@ public struct S3Middleware: AWSServiceMiddleware { } // if host name contains amazonaws.com and bucket name doesn't contain a period do virtual address look up - if isAmazonUrl || context.options.contains(.s3ForceVirtualHost), !bucket.contains(".") { + if isAmazonUrl || context.serviceConfig.options.contains(.s3ForceVirtualHost), !bucket.contains(".") { let pathsWithoutBucket = paths.dropFirst() // bucket urlPath = pathsWithoutBucket.joined(separator: "/") @@ -116,15 +116,15 @@ public struct S3Middleware: AWSServiceMiddleware { return value.addingPercentEncoding(withAllowedCharacters: Self.s3PathAllowedCharacters) ?? value } - func createBucketFixup(request: inout AWSRequest) { - switch request.operation { + func createBucketFixup(request: inout AWSHTTPRequest, context: AWSMiddlewareContext) { + switch context.operation { // fixup CreateBucket to include location case "CreateBucket": var xml = "" - if request.region != .useast1 { + if context.serviceConfig.region != .useast1 { xml += "" xml += "" - xml += request.region.rawValue + xml += context.serviceConfig.region.rawValue xml += "" xml += "" } @@ -136,12 +136,12 @@ public struct S3Middleware: AWSServiceMiddleware { } } - func expect100Continue(request: inout AWSRequest) { - if request.httpMethod == .PUT, + func expect100Continue(request: inout AWSHTTPRequest) { + if request.method == .PUT, let length = request.body.length, length > 128 * 1024 { - request.httpHeaders.replaceOrAdd(name: "Expect", value: "100-continue") + request.headers.replaceOrAdd(name: "Expect", value: "100-continue") } } @@ -160,7 +160,7 @@ public struct S3Middleware: AWSServiceMiddleware { } } */ - func fixupHeadErrors(response: inout AWSResponse) { + func fixupHeadErrors(response: inout AWSHTTPResponse) { if response.status == .notFound, response.body.length == 0 { let errorNode = XML.Element(name: "Error") let codeNode = XML.Element(name: "Code", stringValue: "NotFound") diff --git a/Sources/SotoCore/Message/Middleware/TreeHashMiddleware.swift b/Sources/SotoCore/Message/Middleware/TreeHashMiddleware.swift index 3d4bf5be2..672d658df 100644 --- a/Sources/SotoCore/Message/Middleware/TreeHashMiddleware.swift +++ b/Sources/SotoCore/Message/Middleware/TreeHashMiddleware.swift @@ -28,12 +28,12 @@ public struct TreeHashMiddleware: AWSServiceMiddleware { self.treeHashHeader = header } - public func chain(request: AWSRequest, context: AWSMiddlewareContext) throws -> AWSRequest { + public func chain(request: AWSHTTPRequest, context: AWSMiddlewareContext) throws -> AWSHTTPRequest { var request = request - if request.httpHeaders[self.treeHashHeader].first == nil { + if request.headers[self.treeHashHeader].first == nil { if case .byteBuffer(let buffer) = request.body.storage { let treeHash = try computeTreeHash(buffer).hexDigest() - request.httpHeaders.replaceOrAdd(name: self.treeHashHeader, value: treeHash) + request.headers.replaceOrAdd(name: self.treeHashHeader, value: treeHash) } } diff --git a/Tests/SotoCoreTests/AWSClientTests.swift b/Tests/SotoCoreTests/AWSClientTests.swift index 2da71e71c..2319384d5 100644 --- a/Tests/SotoCoreTests/AWSClientTests.swift +++ b/Tests/SotoCoreTests/AWSClientTests.swift @@ -576,52 +576,6 @@ class AWSClientTests: XCTestCase { } } - /// verify we are not calling the Retry handler when streaming a request - func testDontRetryStreamingRequests() async { - final class TestRetryPolicy: RetryPolicy { - func getRetryWaitTime(error: Error, attempt: Int) -> RetryStatus? { - XCTFail("This should not be called as streaming has disabled retries") - return .dontRetry - } - } - struct Input: AWSEncodableShape & AWSShapeWithPayload { - static var _payloadPath: String = "payload" - static var _options: AWSShapeOptions = [.allowStreaming, .allowChunkedStreaming, .rawPayload] - let payload: AWSHTTPBody - private enum CodingKeys: CodingKey {} - } - let retryPolicy = TestRetryPolicy() - do { - let httpClient = AsyncHTTPClient.HTTPClient(eventLoopGroupProvider: .singleton) - let awsServer = AWSTestServer(serviceProtocol: .json) - let config = createServiceConfig(serviceProtocol: .json(version: "1.1"), endpoint: awsServer.address) - let client = createAWSClient(credentialProvider: .empty, retryPolicy: .init(retryPolicy: retryPolicy), httpClientProvider: .shared(httpClient)) - defer { - XCTAssertNoThrow(try awsServer.stop()) - XCTAssertNoThrow(try client.syncShutdown()) - XCTAssertNoThrow(try httpClient.syncShutdown()) - } - let payload = AWSHTTPBody(asyncSequence: ByteBuffer().asyncSequence(chunkSize: 16), length: nil) - let input = Input(payload: payload) - async let responseTask: Void = client.execute( - operation: "test", - path: "/", - httpMethod: .POST, - serviceConfig: config, - input: input, - logger: TestEnvironment.logger - ) - try awsServer.processRaw { _ in - return .error(.accessDenied, continueProcessing: false) - } - - try await responseTask - } catch let error as AWSClientError where error == .accessDenied { - } catch { - XCTFail("Unexpected error: \(error)") - } - } - func testClientResponseEventLoop() async { do { let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 5) diff --git a/Tests/SotoCoreTests/AWSRequestTests.swift b/Tests/SotoCoreTests/AWSRequestTests.swift index e4f269823..f13f752a6 100644 --- a/Tests/SotoCoreTests/AWSRequestTests.swift +++ b/Tests/SotoCoreTests/AWSRequestTests.swift @@ -53,8 +53,8 @@ class AWSRequestTests: XCTestCase { XCTAssertEqual(config.region, .euwest1) - var request: AWSRequest? - XCTAssertNoThrow(request = try AWSRequest(operation: "test", path: "/", httpMethod: .GET, configuration: config)) + var request: AWSHTTPRequest? + XCTAssertNoThrow(request = try AWSHTTPRequest(operation: "test", path: "/", method: .GET, configuration: config)) XCTAssertEqual(request?.url.absoluteString, "https://service.aws.amazon.com/") } @@ -67,9 +67,9 @@ class AWSRequestTests: XCTestCase { } let config = createServiceConfig() let request = KeywordRequest(repeat: "Repeat") - var awsRequest: AWSRequest? - XCTAssertNoThrow(awsRequest = try AWSRequest(operation: "Keyword", path: "/", httpMethod: .POST, input: request, configuration: config)) - XCTAssertEqual(awsRequest?.httpHeaders["repeat"].first, "Repeat") + var awsRequest: AWSHTTPRequest? + XCTAssertNoThrow(awsRequest = try AWSHTTPRequest(operation: "Keyword", path: "/", method: .POST, input: request, configuration: config)) + XCTAssertEqual(awsRequest?.headers["repeat"].first, "Repeat") } func testCreateAwsRequestWithKeywordInQuery() { @@ -82,8 +82,8 @@ class AWSRequestTests: XCTestCase { let config = createServiceConfig(region: .cacentral1, service: "s3") let request = KeywordRequest(throw: "KeywordRequest") - var awsRequest: AWSRequest? - XCTAssertNoThrow(awsRequest = try AWSRequest(operation: "Keyword", path: "/", httpMethod: .POST, input: request, configuration: config)) + var awsRequest: AWSHTTPRequest? + XCTAssertNoThrow(awsRequest = try AWSHTTPRequest(operation: "Keyword", path: "/", method: .POST, input: request, configuration: config)) XCTAssertEqual(awsRequest?.url, URL(string: "https://s3.ca-central-1.amazonaws.com/?throw=KeywordRequest")!) } @@ -92,11 +92,11 @@ class AWSRequestTests: XCTestCase { let config = createServiceConfig(region: .useast1, service: "kinesis", serviceProtocol: .json(version: "1.1")) - var awsRequest: AWSRequest? - XCTAssertNoThrow(awsRequest = try AWSRequest( + var awsRequest: AWSHTTPRequest? + XCTAssertNoThrow(awsRequest = try AWSHTTPRequest( operation: "PutRecord", path: "/", - httpMethod: .POST, + method: .POST, input: input2, configuration: config ) @@ -108,22 +108,22 @@ class AWSRequestTests: XCTestCase { region: config.region.rawValue ) - let signedRequest = awsRequest?.createHTTPRequest(signer: signer, serviceConfig: config) - XCTAssertNotNil(signedRequest) - XCTAssertEqual(signedRequest?.method, HTTPMethod.POST) - XCTAssertEqual(signedRequest?.headers["Host"].first, "kinesis.us-east-1.amazonaws.com") - XCTAssertEqual(signedRequest?.headers["Content-Type"].first, "application/x-amz-json-1.1") + awsRequest?.signHeaders(signer: signer, serviceConfig: config) + XCTAssertNotNil(awsRequest) + XCTAssertEqual(awsRequest?.method, HTTPMethod.POST) + XCTAssertEqual(awsRequest?.headers["Host"].first, "kinesis.us-east-1.amazonaws.com") + XCTAssertEqual(awsRequest?.headers["Content-Type"].first, "application/x-amz-json-1.1") } func testUnsignedClient() { let input = E() let config = createServiceConfig() - var awsRequest: AWSRequest? - XCTAssertNoThrow(awsRequest = try AWSRequest( + var awsRequest: AWSHTTPRequest? + XCTAssertNoThrow(awsRequest = try AWSHTTPRequest( operation: "CopyObject", path: "/", - httpMethod: .PUT, + method: .PUT, input: input, configuration: config )) @@ -134,8 +134,8 @@ class AWSRequestTests: XCTestCase { region: config.region.rawValue ) - let request = awsRequest?.createHTTPRequest(signer: signer, serviceConfig: config) - XCTAssertNil(request?.headers["Authorization"].first) + awsRequest?.signHeaders(signer: signer, serviceConfig: config) + XCTAssertNil(awsRequest?.headers["Authorization"].first) } func testSignedClient() { @@ -149,18 +149,18 @@ class AWSRequestTests: XCTestCase { ) for httpMethod in [HTTPMethod.GET, .HEAD, .PUT, .DELETE, .POST, .PATCH] { - var awsRequest: AWSRequest? + var awsRequest: AWSHTTPRequest? - XCTAssertNoThrow(awsRequest = try AWSRequest( + XCTAssertNoThrow(awsRequest = try AWSHTTPRequest( operation: "Test", path: "/", - httpMethod: httpMethod, + method: httpMethod, input: input, configuration: config )) - let request = awsRequest?.createHTTPRequest(signer: signer, serviceConfig: config) - XCTAssertNotNil(request?.headers["Authorization"].first) + awsRequest?.signHeaders(signer: signer, serviceConfig: config) + XCTAssertNotNil(awsRequest?.headers["Authorization"].first) } } @@ -177,32 +177,32 @@ class AWSRequestTests: XCTestCase { let object2 = Object2(payload: .init(string: "Payload")) let config = createServiceConfig(serviceProtocol: .json(version: "1.1")) - var request: AWSRequest? - XCTAssertNoThrow(request = try AWSRequest(operation: "test", path: "/", httpMethod: .POST, input: object, configuration: config)) - XCTAssertEqual(request?.httpHeaders["content-type"].first, "application/x-amz-json-1.1") + var request: AWSHTTPRequest? + XCTAssertNoThrow(request = try AWSHTTPRequest(operation: "test", path: "/", method: .POST, input: object, configuration: config)) + XCTAssertEqual(request?.headers["content-type"].first, "application/x-amz-json-1.1") let config2 = createServiceConfig(serviceProtocol: .restjson) - var request2: AWSRequest? - XCTAssertNoThrow(request2 = try AWSRequest(operation: "test", path: "/", httpMethod: .POST, input: object, configuration: config2)) - XCTAssertEqual(request2?.httpHeaders["content-type"].first, "application/json") - var rawRequest2: AWSRequest? - XCTAssertNoThrow(rawRequest2 = try AWSRequest(operation: "test", path: "/", httpMethod: .POST, input: object2, configuration: config2)) - XCTAssertEqual(rawRequest2?.httpHeaders["content-type"].first, "binary/octet-stream") + var request2: AWSHTTPRequest? + XCTAssertNoThrow(request2 = try AWSHTTPRequest(operation: "test", path: "/", method: .POST, input: object, configuration: config2)) + XCTAssertEqual(request2?.headers["content-type"].first, "application/json") + var rawRequest2: AWSHTTPRequest? + XCTAssertNoThrow(rawRequest2 = try AWSHTTPRequest(operation: "test", path: "/", method: .POST, input: object2, configuration: config2)) + XCTAssertEqual(rawRequest2?.headers["content-type"].first, "binary/octet-stream") let config3 = createServiceConfig(serviceProtocol: .query) - var request3: AWSRequest? - XCTAssertNoThrow(request3 = try AWSRequest(operation: "test", path: "/", httpMethod: .POST, input: object, configuration: config3)) - XCTAssertEqual(request3?.httpHeaders["content-type"].first, "application/x-www-form-urlencoded; charset=utf-8") + var request3: AWSHTTPRequest? + XCTAssertNoThrow(request3 = try AWSHTTPRequest(operation: "test", path: "/", method: .POST, input: object, configuration: config3)) + XCTAssertEqual(request3?.headers["content-type"].first, "application/x-www-form-urlencoded; charset=utf-8") let config4 = createServiceConfig(serviceProtocol: .ec2) - var request4: AWSRequest? - XCTAssertNoThrow(request4 = try AWSRequest(operation: "test", path: "/", httpMethod: .POST, input: object, configuration: config4)) - XCTAssertEqual(request4?.httpHeaders["content-type"].first, "application/x-www-form-urlencoded; charset=utf-8") + var request4: AWSHTTPRequest? + XCTAssertNoThrow(request4 = try AWSHTTPRequest(operation: "test", path: "/", method: .POST, input: object, configuration: config4)) + XCTAssertEqual(request4?.headers["content-type"].first, "application/x-www-form-urlencoded; charset=utf-8") let config5 = createServiceConfig(serviceProtocol: .restxml) - var request5: AWSRequest? - XCTAssertNoThrow(request5 = try AWSRequest(operation: "test", path: "/", httpMethod: .POST, input: object, configuration: config5)) - XCTAssertEqual(request5?.httpHeaders["content-type"].first, "application/octet-stream") + var request5: AWSHTTPRequest? + XCTAssertNoThrow(request5 = try AWSHTTPRequest(operation: "test", path: "/", method: .POST, input: object, configuration: config5)) + XCTAssertEqual(request5?.headers["content-type"].first, "application/octet-stream") } func testHeaderEncoding() { @@ -212,9 +212,9 @@ class AWSRequestTests: XCTestCase { } let input = Input(h: "TestHeader") let config = createServiceConfig() - var request: AWSRequest? - XCTAssertNoThrow(request = try AWSRequest(operation: "Test", path: "/", httpMethod: .GET, input: input, configuration: config)) - XCTAssertEqual(request?.httpHeaders["header-member"].first, "TestHeader") + var request: AWSHTTPRequest? + XCTAssertNoThrow(request = try AWSHTTPRequest(operation: "Test", path: "/", method: .GET, input: input, configuration: config)) + XCTAssertEqual(request?.headers["header-member"].first, "TestHeader") } func testQueryEncoding() { @@ -224,8 +224,8 @@ class AWSRequestTests: XCTestCase { } let input = Input(q: "=3+5897^sdfjh&") let config = createServiceConfig(region: .useast1) - var request: AWSRequest? - XCTAssertNoThrow(request = try AWSRequest(operation: "Test", path: "/", httpMethod: .GET, input: input, configuration: config)) + var request: AWSHTTPRequest? + XCTAssertNoThrow(request = try AWSHTTPRequest(operation: "Test", path: "/", method: .GET, input: input, configuration: config)) XCTAssertEqual(request?.url.absoluteString, "https://test.us-east-1.amazonaws.com/?query=%3D3%2B5897%5Esdfjh%26") } @@ -237,8 +237,8 @@ class AWSRequestTests: XCTestCase { let input = Input(q: ["=3+5897^sdfjh&", "test"]) let config = createServiceConfig(region: .useast1) - var request: AWSRequest? - XCTAssertNoThrow(request = try AWSRequest(operation: "Test", path: "/", httpMethod: .GET, input: input, configuration: config)) + var request: AWSHTTPRequest? + XCTAssertNoThrow(request = try AWSHTTPRequest(operation: "Test", path: "/", method: .GET, input: input, configuration: config)) XCTAssertEqual(request?.url.absoluteString, "https://test.us-east-1.amazonaws.com/?query=%3D3%2B5897%5Esdfjh%26&query=test") } @@ -249,15 +249,15 @@ class AWSRequestTests: XCTestCase { } let input = Input(q: ["one": 1, "two": 2]) let config = createServiceConfig(region: .useast2, service: "myservice") - var request: AWSRequest? - XCTAssertNoThrow(request = try AWSRequest(operation: "Test", path: "/", httpMethod: .GET, input: input, configuration: config)) + var request: AWSHTTPRequest? + XCTAssertNoThrow(request = try AWSHTTPRequest(operation: "Test", path: "/", method: .GET, input: input, configuration: config)) XCTAssertEqual(request?.url.absoluteString, "https://myservice.us-east-2.amazonaws.com/?one=1&two=2") } func testQueryProtocolEmptyRequest() { let config = createServiceConfig(region: .useast2, service: "myservice", serviceProtocol: .query) - var request: AWSRequest? - XCTAssertNoThrow(request = try AWSRequest(operation: "Test", path: "/", httpMethod: .GET, configuration: config)) + var request: AWSHTTPRequest? + XCTAssertNoThrow(request = try AWSHTTPRequest(operation: "Test", path: "/", method: .GET, configuration: config)) XCTAssertEqual(request?.body.asString(), "Action=Test&Version=01-01-2001") } @@ -268,8 +268,8 @@ class AWSRequestTests: XCTestCase { } let input = Input(u: "MyKey") let config = createServiceConfig(region: .cacentral1, service: "s3") - var request: AWSRequest? - XCTAssertNoThrow(request = try AWSRequest(operation: "Test", path: "/{key}", httpMethod: .GET, input: input, configuration: config)) + var request: AWSHTTPRequest? + XCTAssertNoThrow(request = try AWSHTTPRequest(operation: "Test", path: "/{key}", method: .GET, input: input, configuration: config)) XCTAssertEqual(request?.url.absoluteString, "https://s3.ca-central-1.amazonaws.com/MyKey") } @@ -280,8 +280,8 @@ class AWSRequestTests: XCTestCase { } let input = Input(number: 5) let xmlConfig = createServiceConfig(serviceProtocol: .restxml) - var request: AWSRequest? - XCTAssertNoThrow(request = try AWSRequest(operation: "Test", path: "/", httpMethod: .GET, input: input, configuration: xmlConfig)) + var request: AWSHTTPRequest? + XCTAssertNoThrow(request = try AWSHTTPRequest(operation: "Test", path: "/", method: .GET, input: input, configuration: xmlConfig)) guard case .byteBuffer(let buffer) = request?.body.storage else { return XCTFail("Shouldn't get here") } @@ -295,8 +295,8 @@ class AWSRequestTests: XCTestCase { } let input = Input(number: 5) let xmlConfig = createServiceConfig(serviceProtocol: .restxml, xmlNamespace: "https://test.amazonaws.com/doc/2020-03-11/") - var request: AWSRequest? - XCTAssertNoThrow(request = try AWSRequest(operation: "Test", path: "/", httpMethod: .GET, input: input, configuration: xmlConfig)) + var request: AWSHTTPRequest? + XCTAssertNoThrow(request = try AWSHTTPRequest(operation: "Test", path: "/", method: .GET, input: input, configuration: xmlConfig)) guard case .byteBuffer(let buffer) = request?.body.storage else { return XCTFail("Shouldn't get here") } @@ -315,8 +315,8 @@ class AWSRequestTests: XCTestCase { } let input = Input(payload: Payload(number: 5)) let xmlConfig = createServiceConfig(serviceProtocol: .restxml) - var request: AWSRequest? - XCTAssertNoThrow(request = try AWSRequest(operation: "Test", path: "/", httpMethod: .GET, input: input, configuration: xmlConfig)) + var request: AWSHTTPRequest? + XCTAssertNoThrow(request = try AWSHTTPRequest(operation: "Test", path: "/", method: .GET, input: input, configuration: xmlConfig)) guard case .byteBuffer(let buffer) = request?.body.storage else { return XCTFail("Shouldn't get here") } @@ -334,7 +334,7 @@ class AWSRequestTests: XCTestCase { } let input = J(dataContainer: DataContainer(data: Data("test data".utf8))) let jsonConfig = createServiceConfig(serviceProtocol: .json(version: "1.1")) - XCTAssertNoThrow(try AWSRequest(operation: "PutRecord", path: "/", httpMethod: .POST, input: input, configuration: jsonConfig)) + XCTAssertNoThrow(try AWSHTTPRequest(operation: "PutRecord", path: "/", method: .POST, input: input, configuration: jsonConfig)) } func testEC2ClientRequest() { @@ -343,8 +343,8 @@ class AWSRequestTests: XCTestCase { } let input = Input(array: ["entry1", "entry2"]) let config = createServiceConfig(serviceProtocol: .ec2, apiVersion: "2013-12-02") - var request: AWSRequest? - XCTAssertNoThrow(request = try AWSRequest(operation: "Test", path: "/", httpMethod: .GET, input: input, configuration: config)) + var request: AWSHTTPRequest? + XCTAssertNoThrow(request = try AWSHTTPRequest(operation: "Test", path: "/", method: .GET, input: input, configuration: config)) XCTAssertEqual(request?.body.asString(), "Action=Test&Array.1=entry1&Array.2=entry2&Version=2013-12-02") } @@ -355,10 +355,10 @@ class AWSRequestTests: XCTestCase { } let input = Input(path: "Test me/once+") let config = createServiceConfig(endpoint: "https://test.com") - var request: AWSRequest? - XCTAssertNoThrow(request = try AWSRequest(operation: "Test", path: "/{path+}", httpMethod: .GET, input: input, configuration: config)) + var request: AWSHTTPRequest? + XCTAssertNoThrow(request = try AWSHTTPRequest(operation: "Test", path: "/{path+}", method: .GET, input: input, configuration: config)) XCTAssertEqual(request?.url, URL(string: "https://test.com/Test%20me/once%2B")!) - XCTAssertNoThrow(request = try AWSRequest(operation: "Test", path: "/{path}", httpMethod: .GET, input: input, configuration: config)) + XCTAssertNoThrow(request = try AWSHTTPRequest(operation: "Test", path: "/{path}", method: .GET, input: input, configuration: config)) XCTAssertEqual(request?.url, URL(string: "https://test.com/Test%20me%2Fonce%2B")!) } @@ -369,8 +369,8 @@ class AWSRequestTests: XCTestCase { } let input = Input(items: ["orange", "apple"]) let config = createServiceConfig(endpoint: "https://test.com") - var request: AWSRequest? - XCTAssertNoThrow(request = try AWSRequest(operation: "Test", path: "/", httpMethod: .GET, input: input, configuration: config)) + var request: AWSHTTPRequest? + XCTAssertNoThrow(request = try AWSHTTPRequest(operation: "Test", path: "/", method: .GET, input: input, configuration: config)) XCTAssertEqual(request?.url, URL(string: "https://test.com/?item=apple&item=orange")!) } @@ -387,8 +387,8 @@ class AWSRequestTests: XCTestCase { } let input = Input(date: Date(timeIntervalSince1970: 10_000_000), values: [1]) let config = createServiceConfig(endpoint: "https://test.com") - var request: AWSRequest? - XCTAssertNoThrow(request = try AWSRequest(operation: "Test", path: "/", httpMethod: .GET, input: input, configuration: config)) + var request: AWSHTTPRequest? + XCTAssertNoThrow(request = try AWSHTTPRequest(operation: "Test", path: "/", method: .GET, input: input, configuration: config)) XCTAssertEqual(request?.url, URL(string: "https://test.com/?date=Sun%2C%2026%20Apr%201970%2017%3A46%3A40%20GMT")!) } @@ -397,8 +397,8 @@ class AWSRequestTests: XCTestCase { struct Input: AWSEncodableShape {} let input = Input() let config = createServiceConfig(serviceProtocol: .json(version: "1.0"), endpoint: "https://test.com") - var request: AWSRequest? - XCTAssertNoThrow(request = try AWSRequest(operation: "Test", path: "/", httpMethod: .POST, input: input, configuration: config)) + var request: AWSHTTPRequest? + XCTAssertNoThrow(request = try AWSHTTPRequest(operation: "Test", path: "/", method: .POST, input: input, configuration: config)) XCTAssertEqual(request?.body.asString(), "{}") } @@ -407,11 +407,11 @@ class AWSRequestTests: XCTestCase { struct Input: AWSEncodableShape {} let input = Input() let config = createServiceConfig(serviceProtocol: .json(version: "1.0"), endpoint: "https://test.com") - var request: AWSRequest? - XCTAssertNoThrow(request = try AWSRequest( + var request: AWSHTTPRequest? + XCTAssertNoThrow(request = try AWSHTTPRequest( operation: "Test", path: "/", - httpMethod: .POST, + method: .POST, input: input, hostPrefix: "foo.", configuration: config @@ -429,11 +429,11 @@ class AWSRequestTests: XCTestCase { } let input = Input(accountId: "12345678") let config = createServiceConfig(serviceProtocol: .json(version: "1.0"), endpoint: "https://test.com") - var request: AWSRequest? - XCTAssertNoThrow(request = try AWSRequest( + var request: AWSHTTPRequest? + XCTAssertNoThrow(request = try AWSHTTPRequest( operation: "Test", path: "/", - httpMethod: .POST, + method: .POST, input: input, hostPrefix: "{AccountId}.", configuration: config @@ -462,11 +462,11 @@ class AWSRequestTests: XCTestCase { let buffer = ByteBuffer(string: "This is a test") let stream = AWSHTTPBody(asyncSequence: buffer.asyncSequence(chunkSize: 16), length: buffer.readableBytes) let input = Input(payload: stream, member: "test") - var optionalAWSRequest: AWSRequest? - XCTAssertNoThrow(optionalAWSRequest = try AWSRequest(operation: "Test", path: "/", httpMethod: .POST, input: input, configuration: config)) - let awsRequest = try XCTUnwrap(optionalAWSRequest) - let request = awsRequest.toHTTPRequestWithSignedHeader(signer: signer, serviceConfig: config) - XCTAssertNil(request.headers["x-amz-decoded-content-length"].first) + var optionalAWSRequest: AWSHTTPRequest? + XCTAssertNoThrow(optionalAWSRequest = try AWSHTTPRequest(operation: "Test", path: "/", method: .POST, input: input, configuration: config)) + var awsRequest = try XCTUnwrap(optionalAWSRequest) + awsRequest.signHeaders(signer: signer, serviceConfig: config) + XCTAssertNil(awsRequest.headers["x-amz-decoded-content-length"].first) } func testRequiredMD5Checksum() { @@ -476,9 +476,9 @@ class AWSRequestTests: XCTestCase { } let input = Input(q: ["one", "two", "three", "four"]) let config = createServiceConfig(region: .useast2, service: "myservice") - var request: AWSRequest? - XCTAssertNoThrow(request = try AWSRequest(operation: "Test", path: "/", httpMethod: .GET, input: input, configuration: config)) - XCTAssertEqual(request?.httpHeaders["Content-MD5"].first, "3W1MVcXgkODdv+m6VeZqdQ==") + var request: AWSHTTPRequest? + XCTAssertNoThrow(request = try AWSHTTPRequest(operation: "Test", path: "/", method: .GET, input: input, configuration: config)) + XCTAssertEqual(request?.headers["Content-MD5"].first, "3W1MVcXgkODdv+m6VeZqdQ==") } func testMD5ChecksumHeader() { @@ -488,14 +488,14 @@ class AWSRequestTests: XCTestCase { } let input = Input(q: ["one", "two", "three", "four"]) let config = createServiceConfig(region: .useast2, service: "myservice", options: .calculateMD5) - var request: AWSRequest? - XCTAssertNoThrow(request = try AWSRequest(operation: "Test", path: "/", httpMethod: .GET, input: input, configuration: config)) - XCTAssertEqual(request?.httpHeaders["Content-MD5"].first, "3W1MVcXgkODdv+m6VeZqdQ==") + var request: AWSHTTPRequest? + XCTAssertNoThrow(request = try AWSHTTPRequest(operation: "Test", path: "/", method: .GET, input: input, configuration: config)) + XCTAssertEqual(request?.headers["Content-MD5"].first, "3W1MVcXgkODdv+m6VeZqdQ==") let config2 = createServiceConfig(region: .useast2, service: "myservice") - var request2: AWSRequest? - XCTAssertNoThrow(request2 = try AWSRequest(operation: "Test", path: "/", httpMethod: .GET, input: input, configuration: config2)) - XCTAssertNil(request2?.httpHeaders["Content-MD5"].first) + var request2: AWSHTTPRequest? + XCTAssertNoThrow(request2 = try AWSHTTPRequest(operation: "Test", path: "/", method: .GET, input: input, configuration: config2)) + XCTAssertNil(request2?.headers["Content-MD5"].first) } func testMD5ChecksumSetAlready() { @@ -509,9 +509,9 @@ class AWSRequestTests: XCTestCase { } let input = Input(checksum: "Set already", q: ["one": 1, "two": 2]) let config = createServiceConfig(region: .useast2, service: "myservice") - var request: AWSRequest? - XCTAssertNoThrow(request = try AWSRequest(operation: "Test", path: "/", httpMethod: .GET, input: input, configuration: config)) - XCTAssertEqual(request?.httpHeaders["Content-MD5"].first, "Set already") + var request: AWSHTTPRequest? + XCTAssertNoThrow(request = try AWSHTTPRequest(operation: "Test", path: "/", method: .GET, input: input, configuration: config)) + XCTAssertEqual(request?.headers["Content-MD5"].first, "Set already") } func testSHA1Checksum() { @@ -525,9 +525,9 @@ class AWSRequestTests: XCTestCase { } let input = Input(q: ["one", "two", "three", "four"], checksum: "SHA1") let config = createServiceConfig(region: .useast2, service: "myservice", serviceProtocol: .restxml) - var request: AWSRequest? - XCTAssertNoThrow(request = try AWSRequest(operation: "Test", path: "/", httpMethod: .GET, input: input, configuration: config)) - XCTAssertEqual(request?.httpHeaders["x-amz-checksum-sha1"].first, "SJuck2AdC0YGJSnr5S/2+5uL1FA=") + var request: AWSHTTPRequest? + XCTAssertNoThrow(request = try AWSHTTPRequest(operation: "Test", path: "/", method: .GET, input: input, configuration: config)) + XCTAssertEqual(request?.headers["x-amz-checksum-sha1"].first, "SJuck2AdC0YGJSnr5S/2+5uL1FA=") } func testCRC32Checksum() { @@ -541,9 +541,9 @@ class AWSRequestTests: XCTestCase { } let input = Input(q: ["one", "two", "three", "four"], checksum: "CRC32") let config = createServiceConfig(region: .useast2, service: "myservice", serviceProtocol: .restxml) - var request: AWSRequest? - XCTAssertNoThrow(request = try AWSRequest(operation: "Test", path: "/", httpMethod: .GET, input: input, configuration: config)) - XCTAssertEqual(request?.httpHeaders["x-amz-checksum-crc32"].first, "wvjEqA==") + var request: AWSHTTPRequest? + XCTAssertNoThrow(request = try AWSHTTPRequest(operation: "Test", path: "/", method: .GET, input: input, configuration: config)) + XCTAssertEqual(request?.headers["x-amz-checksum-crc32"].first, "wvjEqA==") } func testCRC32CChecksum() { @@ -557,9 +557,9 @@ class AWSRequestTests: XCTestCase { } let input = Input(q: ["one", "two", "three", "four"], checksum: "CRC32C") let config = createServiceConfig(region: .useast2, service: "myservice", serviceProtocol: .restxml) - var request: AWSRequest? - XCTAssertNoThrow(request = try AWSRequest(operation: "Test", path: "/", httpMethod: .GET, input: input, configuration: config)) - XCTAssertEqual(request?.httpHeaders["x-amz-checksum-crc32c"].first, "JMPW1A==") + var request: AWSHTTPRequest? + XCTAssertNoThrow(request = try AWSHTTPRequest(operation: "Test", path: "/", method: .GET, input: input, configuration: config)) + XCTAssertEqual(request?.headers["x-amz-checksum-crc32c"].first, "JMPW1A==") } func testSHA256Checksum() { @@ -573,9 +573,9 @@ class AWSRequestTests: XCTestCase { } let input = Input(q: ["one", "two", "three", "four"], checksum: "SHA256") let config = createServiceConfig(region: .useast2, service: "myservice", serviceProtocol: .restxml) - var request: AWSRequest? - XCTAssertNoThrow(request = try AWSRequest(operation: "Test", path: "/", httpMethod: .GET, input: input, configuration: config)) - XCTAssertEqual(request?.httpHeaders["x-amz-checksum-sha256"].first, "HTYjCbmfsJd3Dek0xIJJk3VKfQDLtOqX3GYDOaRJjRs=") + var request: AWSHTTPRequest? + XCTAssertNoThrow(request = try AWSHTTPRequest(operation: "Test", path: "/", method: .GET, input: input, configuration: config)) + XCTAssertEqual(request?.headers["x-amz-checksum-sha256"].first, "HTYjCbmfsJd3Dek0xIJJk3VKfQDLtOqX3GYDOaRJjRs=") } func testHeaderPrefix() { @@ -587,9 +587,9 @@ class AWSRequestTests: XCTestCase { } let input = Input(content: ["one": "first", "two": "second"]) let config = createServiceConfig(region: .useast2, service: "myservice", serviceProtocol: .restxml) - var request: AWSRequest? - XCTAssertNoThrow(request = try AWSRequest(operation: "Test", path: "/", httpMethod: .GET, input: input, configuration: config)) - XCTAssertEqual(request?.httpHeaders["x-aws-metadata-one"].first, "first") - XCTAssertEqual(request?.httpHeaders["x-aws-metadata-two"].first, "second") + var request: AWSHTTPRequest? + XCTAssertNoThrow(request = try AWSHTTPRequest(operation: "Test", path: "/", method: .GET, input: input, configuration: config)) + XCTAssertEqual(request?.headers["x-aws-metadata-one"].first, "first") + XCTAssertEqual(request?.headers["x-aws-metadata-two"].first, "second") } } diff --git a/Tests/SotoCoreTests/AWSResponseTests.swift b/Tests/SotoCoreTests/AWSResponseTests.swift index 7d4527c19..6c8d851a9 100644 --- a/Tests/SotoCoreTests/AWSResponseTests.swift +++ b/Tests/SotoCoreTests/AWSResponseTests.swift @@ -35,14 +35,12 @@ class AWSResponseTests: XCTestCase { // XML var xmlResult: Output? - let awsXMLResponse = try await AWSResponse(from: response, streaming: false) - XCTAssertNoThrow(xmlResult = try awsXMLResponse.generateOutputShape(operation: "Test", serviceProtocol: .query)) + XCTAssertNoThrow(xmlResult = try response.generateOutputShape(operation: "Test", serviceProtocol: .query)) XCTAssertEqual(xmlResult?.h, "test-header") // JSON var jsonResult: Output? - let awsJSONResponse = try await AWSResponse(from: response, streaming: false) - XCTAssertNoThrow(jsonResult = try awsJSONResponse.generateOutputShape(operation: "Test", serviceProtocol: .restjson)) + XCTAssertNoThrow(jsonResult = try response.generateOutputShape(operation: "Test", serviceProtocol: .restjson)) XCTAssertEqual(jsonResult?.h, "test-header") } @@ -74,10 +72,9 @@ class AWSResponseTests: XCTestCase { ] ) - // JSON var awsJSONResponse: awsResponse + // JSON var awsJSONResponse: response var jsonResult: Output? - let awsJSONResponse = try await AWSResponse(from: response, streaming: false) - XCTAssertNoThrow(jsonResult = try awsJSONResponse.generateOutputShape(operation: "Test", serviceProtocol: .restjson)) + XCTAssertNoThrow(jsonResult = try response.generateOutputShape(operation: "Test", serviceProtocol: .restjson)) XCTAssertEqual(jsonResult?.string, "test-header") XCTAssertEqual(jsonResult?.string2, "23") XCTAssertEqual(jsonResult?.double, 3.14) @@ -101,14 +98,12 @@ class AWSResponseTests: XCTestCase { // XML var xmlResult: Output? - let awsXMLResponse = try await AWSResponse(from: response, streaming: false) - XCTAssertNoThrow(xmlResult = try awsXMLResponse.generateOutputShape(operation: "Test", serviceProtocol: .query)) + XCTAssertNoThrow(xmlResult = try response.generateOutputShape(operation: "Test", serviceProtocol: .query)) XCTAssertEqual(xmlResult?.status, 200) // JSON var jsonResult: Output? - let awsJSONResponse = try await AWSResponse(from: response, streaming: false) - XCTAssertNoThrow(jsonResult = try awsJSONResponse.generateOutputShape(operation: "Test", serviceProtocol: .restjson)) + XCTAssertNoThrow(jsonResult = try response.generateOutputShape(operation: "Test", serviceProtocol: .restjson)) XCTAssertEqual(jsonResult?.status, 200) } @@ -126,8 +121,7 @@ class AWSResponseTests: XCTestCase { ) var output: Output? - let awsResponse = try await AWSResponse(from: response, streaming: false) - XCTAssertNoThrow(output = try awsResponse.generateOutputShape(operation: "Test", serviceProtocol: .restxml)) + XCTAssertNoThrow(output = try response.generateOutputShape(operation: "Test", serviceProtocol: .restxml)) XCTAssertEqual(output?.name, "hello") } @@ -150,8 +144,7 @@ class AWSResponseTests: XCTestCase { ) var output: Output? - let awsResponse = try await AWSResponse(from: response, streaming: false) - XCTAssertNoThrow(output = try awsResponse.generateOutputShape(operation: "Test", serviceProtocol: .restxml)) + XCTAssertNoThrow(output = try response.generateOutputShape(operation: "Test", serviceProtocol: .restxml)) XCTAssertEqual(output?.name, "hello") XCTAssertEqual(output?.contentType, "application/xml") } @@ -175,8 +168,7 @@ class AWSResponseTests: XCTestCase { ) var _output: Output? - let awsResponse = try await AWSResponse(from: response, streaming: true) - XCTAssertNoThrow(_output = try awsResponse.generateOutputShape(operation: "Test", serviceProtocol: .restxml)) + XCTAssertNoThrow(_output = try response.generateOutputShape(operation: "Test", serviceProtocol: .restxml)) let output = try XCTUnwrap(_output) let responsePayload = try await String(buffer: output.body.collect(upTo: .max)) XCTAssertEqual(responsePayload, "{\"name\":\"hello\"}") @@ -195,8 +187,7 @@ class AWSResponseTests: XCTestCase { ) var output: Output? - let awsResponse = try await AWSResponse(from: response, streaming: false) - XCTAssertNoThrow(output = try awsResponse.generateOutputShape(operation: "Test", serviceProtocol: .json(version: "1.1"))) + XCTAssertNoThrow(output = try response.generateOutputShape(operation: "Test", serviceProtocol: .json(version: "1.1"))) XCTAssertEqual(output?.name, "hello") } @@ -219,8 +210,7 @@ class AWSResponseTests: XCTestCase { ) var output: Output? - let awsResponse = try await AWSResponse(from: response, streaming: false) - XCTAssertNoThrow(output = try awsResponse.generateOutputShape(operation: "Test", serviceProtocol: .json(version: "1.1"))) + XCTAssertNoThrow(output = try response.generateOutputShape(operation: "Test", serviceProtocol: .json(version: "1.1"))) XCTAssertEqual(output?.output2.name, "hello") } @@ -242,8 +232,7 @@ class AWSResponseTests: XCTestCase { ) var _output: Output? - let awsResponse = try await AWSResponse(from: response, streaming: true) - XCTAssertNoThrow(_output = try awsResponse.generateOutputShape(operation: "Test", serviceProtocol: .json(version: "1.1"))) + XCTAssertNoThrow(_output = try response.generateOutputShape(operation: "Test", serviceProtocol: .json(version: "1.1"))) let output = try XCTUnwrap(_output) let responsePayload = try await String(buffer: output.body.collect(upTo: .max)) XCTAssertEqual(responsePayload, "{\"name\":\"hello\"}") @@ -259,8 +248,7 @@ class AWSResponseTests: XCTestCase { ) let service = createServiceConfig(serviceProtocol: .json(version: "1.1"), errorType: ServiceErrorType.self) - let awsResponse = try await AWSResponse(from: response, streaming: false) - let error = awsResponse.generateError(serviceConfig: service, logger: TestEnvironment.logger) as? ServiceErrorType + let error = response.generateError(serviceConfig: service, logger: TestEnvironment.logger) as? ServiceErrorType XCTAssertEqual(error, ServiceErrorType.resourceNotFoundException) XCTAssertEqual(error?.message, "Donald Where's Your Troosers?") XCTAssertEqual(error?.context?.responseCode, .notFound) @@ -276,8 +264,7 @@ class AWSResponseTests: XCTestCase { ) let service = createServiceConfig(serviceProtocol: .json(version: "1.1"), errorType: ServiceErrorType.self) - let awsResponse = try await AWSResponse(from: response, streaming: false) - let error = awsResponse.generateError(serviceConfig: service, logger: TestEnvironment.logger) as? ServiceErrorType + let error = response.generateError(serviceConfig: service, logger: TestEnvironment.logger) as? ServiceErrorType XCTAssertEqual(error, ServiceErrorType.resourceNotFoundException) XCTAssertEqual(error?.message, "Donald Where's Your Troosers?") XCTAssertEqual(error?.context?.responseCode, .notFound) @@ -292,8 +279,7 @@ class AWSResponseTests: XCTestCase { ) let service = createServiceConfig(serviceProtocol: .restjson, errorType: ServiceErrorType.self) - let awsResponse = try await AWSResponse(from: response, streaming: false) - let error = awsResponse.generateError(serviceConfig: service, logger: TestEnvironment.logger) as? ServiceErrorType + let error = response.generateError(serviceConfig: service, logger: TestEnvironment.logger) as? ServiceErrorType XCTAssertEqual(error, ServiceErrorType.resourceNotFoundException) XCTAssertEqual(error?.message, "Donald Where's Your Troosers?") XCTAssertEqual(error?.context?.responseCode, .notFound) @@ -309,8 +295,7 @@ class AWSResponseTests: XCTestCase { ) let service = createServiceConfig(serviceProtocol: .restjson, errorType: ServiceErrorType.self) - let awsResponse = try await AWSResponse(from: response, streaming: false) - let error = awsResponse.generateError(serviceConfig: service, logger: TestEnvironment.logger) as? ServiceErrorType + let error = response.generateError(serviceConfig: service, logger: TestEnvironment.logger) as? ServiceErrorType XCTAssertEqual(error, ServiceErrorType.resourceNotFoundException) XCTAssertEqual(error?.message, "Donald Where's Your Troosers?") XCTAssertEqual(error?.context?.responseCode, .notFound) @@ -324,8 +309,7 @@ class AWSResponseTests: XCTestCase { ) let service = createServiceConfig(serviceProtocol: .restxml, errorType: ServiceErrorType.self) - let awsResponse = try await AWSResponse(from: response, streaming: false) - let error = awsResponse.generateError(serviceConfig: service, logger: TestEnvironment.logger) as? ServiceErrorType + let error = response.generateError(serviceConfig: service, logger: TestEnvironment.logger) as? ServiceErrorType XCTAssertEqual(error, ServiceErrorType.noSuchKey) XCTAssertEqual(error?.message, "It doesn't exist") XCTAssertEqual(error?.context?.responseCode, .notFound) @@ -340,8 +324,7 @@ class AWSResponseTests: XCTestCase { ) let queryService = createServiceConfig(serviceProtocol: .query, errorType: ServiceErrorType.self) - let awsResponse = try await AWSResponse(from: response, streaming: false) - let error = awsResponse.generateError(serviceConfig: queryService, logger: TestEnvironment.logger) as? ServiceErrorType + let error = response.generateError(serviceConfig: queryService, logger: TestEnvironment.logger) as? ServiceErrorType XCTAssertEqual(error, ServiceErrorType.messageRejected) XCTAssertEqual(error?.message, "Don't like it") XCTAssertEqual(error?.context?.responseCode, .notFound) @@ -356,8 +339,7 @@ class AWSResponseTests: XCTestCase { ) let service = createServiceConfig(serviceProtocol: .ec2) - let awsResponse = try await AWSResponse(from: response, streaming: false) - let error = awsResponse.generateError(serviceConfig: service, logger: TestEnvironment.logger) as? AWSResponseError + let error = response.generateError(serviceConfig: service, logger: TestEnvironment.logger) as? AWSResponseError XCTAssertEqual(error?.errorCode, "NoSuchKey") XCTAssertEqual(error?.message, "It doesn't exist") XCTAssertEqual(error?.context?.responseCode, .notFound) @@ -372,8 +354,7 @@ class AWSResponseTests: XCTestCase { ) let service = createServiceConfig(serviceProtocol: .restxml) - let awsResponse = try await AWSResponse(from: response, streaming: false) - let error = awsResponse.generateError(serviceConfig: service, logger: TestEnvironment.logger) as? AWSResponseError + let error = response.generateError(serviceConfig: service, logger: TestEnvironment.logger) as? AWSResponseError XCTAssertEqual(error?.context?.additionalFields["fault"], "client") } @@ -394,8 +375,7 @@ class AWSResponseTests: XCTestCase { headers: ["prefix-one": "first", "prefix-two": "second"] ) var output: Output? - let awsResponse = try await AWSResponse(from: response, streaming: false) - XCTAssertNoThrow(output = try awsResponse.generateOutputShape(operation: "Test", serviceProtocol: .restxml)) + XCTAssertNoThrow(output = try response.generateOutputShape(operation: "Test", serviceProtocol: .restxml)) XCTAssertEqual(output?.content?["one"], "first") XCTAssertEqual(output?.content?["two"], "second") } @@ -422,8 +402,7 @@ class AWSResponseTests: XCTestCase { body: .init(string: "Hello") ) var output: Output? - let awsResponse = try await AWSResponse(from: response, streaming: false) - XCTAssertNoThrow(output = try awsResponse.generateOutputShape(operation: "Test", serviceProtocol: .restxml)) + XCTAssertNoThrow(output = try response.generateOutputShape(operation: "Test", serviceProtocol: .restxml)) XCTAssertEqual(output?.content?["one"], "first") XCTAssertEqual(output?.content?["two"], "second") } @@ -447,8 +426,7 @@ class AWSResponseTests: XCTestCase { ) var output: Output2? - let awsResponse = try await AWSResponse(from: response, streaming: false) - XCTAssertNoThrow(output = try awsResponse.generateOutputShape(operation: "Test", serviceProtocol: .json(version: "1.1"))) + XCTAssertNoThrow(output = try response.generateOutputShape(operation: "Test", serviceProtocol: .json(version: "1.1"))) XCTAssertEqual(output?.a.count, 2) XCTAssertEqual(output?.d, 3.14) XCTAssertEqual(output?.a[1].s, "Hello2") diff --git a/Tests/SotoCoreTests/MiddlewareTests.swift b/Tests/SotoCoreTests/MiddlewareTests.swift index b74fd9060..6dc2b8bfd 100644 --- a/Tests/SotoCoreTests/MiddlewareTests.swift +++ b/Tests/SotoCoreTests/MiddlewareTests.swift @@ -18,11 +18,11 @@ import XCTest class MiddlewareTests: XCTestCase { struct CatchRequestError: Error { - let request: AWSRequest + let request: AWSHTTPRequest } struct CatchRequestMiddleware: AWSServiceMiddleware { - func chain(request: AWSRequest, context: AWSMiddlewareContext) throws -> AWSRequest { + func chain(request: AWSHTTPRequest, context: AWSMiddlewareContext) throws -> AWSHTTPRequest { throw CatchRequestError(request: request) } } @@ -32,7 +32,7 @@ class MiddlewareTests: XCTestCase { serviceName: String = "service", serviceOptions: AWSServiceConfig.Options = [], uri: String = "/", - test: (AWSRequest) -> Void + test: (AWSHTTPRequest) -> Void ) async throws { let client = createAWSClient(credentialProvider: .empty) let config = createServiceConfig( @@ -53,7 +53,7 @@ class MiddlewareTests: XCTestCase { func testMiddlewareAppliedOnce() async throws { struct URLAppendMiddleware: AWSServiceMiddleware { - func chain(request: AWSRequest, context: AWSMiddlewareContext) throws -> AWSRequest { + func chain(request: AWSHTTPRequest, context: AWSMiddlewareContext) throws -> AWSHTTPRequest { var request = request request.url.appendPathComponent("test") return request @@ -85,8 +85,8 @@ class MiddlewareTests: XCTestCase { .add(name: "user-agent", value: "testEditHeaderMiddleware") ) try await self.testMiddleware(middleware) { request in - XCTAssertEqual(request.httpHeaders["testAdd"].first, "testValue") - XCTAssertEqual(request.httpHeaders["user-agent"].joined(separator: ","), "Soto/6.0,testEditHeaderMiddleware") + XCTAssertEqual(request.headers["testAdd"].first, "testValue") + XCTAssertEqual(request.headers["user-agent"].joined(separator: ","), "Soto/6.0,testEditHeaderMiddleware") } } @@ -96,7 +96,7 @@ class MiddlewareTests: XCTestCase { .replace(name: "user-agent", value: "testEditHeaderMiddleware") ) try await self.testMiddleware(middleware) { request in - XCTAssertEqual(request.httpHeaders["user-agent"].first, "testEditHeaderMiddleware") + XCTAssertEqual(request.headers["user-agent"].first, "testEditHeaderMiddleware") } } diff --git a/Tests/SotoCoreTests/TimeStampTests.swift b/Tests/SotoCoreTests/TimeStampTests.swift index bdc0ccf56..332bbefcc 100644 --- a/Tests/SotoCoreTests/TimeStampTests.swift +++ b/Tests/SotoCoreTests/TimeStampTests.swift @@ -43,8 +43,7 @@ class TimeStampTests: XCTestCase { } let byteBuffer = ByteBuffer(string: "{\"date\": 234876345}") let response = AWSHTTPResponse(status: .ok, headers: [:], body: .init(buffer: byteBuffer)) - let awsResponse = try await AWSResponse(from: response, streaming: false) - let a: A = try awsResponse.generateOutputShape(operation: "TestOperation", serviceProtocol: .json(version: "1.1")) + let a: A = try response.generateOutputShape(operation: "TestOperation", serviceProtocol: .json(version: "1.1")) XCTAssertEqual(a.date.timeIntervalSince1970, 234_876_345) } catch { XCTFail("\(error)") @@ -56,8 +55,8 @@ class TimeStampTests: XCTestCase { var date: Date } let a = A(date: Date(timeIntervalSince1970: 23_984_978_378)) - var request: AWSRequest? - XCTAssertNoThrow(request = try AWSRequest(operation: "test", path: "/", httpMethod: .GET, input: a, configuration: createServiceConfig())) + var request: AWSHTTPRequest? + XCTAssertNoThrow(request = try AWSHTTPRequest(operation: "test", path: "/", method: .GET, input: a, configuration: createServiceConfig())) #if os(Linux) && compiler(>=5.5) XCTAssertEqual(request?.body.asString(), "{\"date\":23984978378.0}") #else @@ -73,8 +72,7 @@ class TimeStampTests: XCTestCase { } let byteBuffer = ByteBuffer(string: "2017-01-01T00:01:00.000Z2017-01-01T00:02:00Z") let response = AWSHTTPResponse(status: .ok, headers: [:], body: .init(buffer: byteBuffer)) - let awsResponse = try await AWSResponse(from: response, streaming: false) - let a: A = try awsResponse.generateOutputShape(operation: "TestOperation", serviceProtocol: .restxml) + let a: A = try response.generateOutputShape(operation: "TestOperation", serviceProtocol: .restxml) XCTAssertEqual(self.dateFormatter.string(from: a.date), "2017-01-01T00:01:00.000Z") XCTAssertEqual(self.dateFormatter.string(from: a.date2), "2017-01-01T00:02:00.000Z") } catch { @@ -87,8 +85,8 @@ class TimeStampTests: XCTestCase { var date: Date } let a = A(date: dateFormatter.date(from: "2017-11-01T00:15:00.000Z")!) - var request: AWSRequest? - XCTAssertNoThrow(request = try AWSRequest(operation: "test", path: "/", httpMethod: .GET, input: a, configuration: createServiceConfig(serviceProtocol: .restxml))) + var request: AWSHTTPRequest? + XCTAssertNoThrow(request = try AWSHTTPRequest(operation: "test", path: "/", method: .GET, input: a, configuration: createServiceConfig(serviceProtocol: .restxml))) XCTAssertEqual(request?.body.asString(), "2017-11-01T00:15:00.000Z") } @@ -97,8 +95,8 @@ class TimeStampTests: XCTestCase { var date: Date } let a = A(date: dateFormatter.date(from: "2017-11-01T00:15:00.000Z")!) - var request: AWSRequest? - XCTAssertNoThrow(request = try AWSRequest(operation: "test", path: "/", httpMethod: .GET, input: a, configuration: createServiceConfig(serviceProtocol: .query))) + var request: AWSHTTPRequest? + XCTAssertNoThrow(request = try AWSHTTPRequest(operation: "test", path: "/", method: .GET, input: a, configuration: createServiceConfig(serviceProtocol: .query))) XCTAssertEqual(request?.body.asString(), "Action=test&Version=01-01-2001&date=2017-11-01T00%3A15%3A00.000Z") } @@ -113,8 +111,7 @@ class TimeStampTests: XCTestCase { } } let response = AWSHTTPResponse(status: .ok, headers: ["Date": "Tue, 15 Nov 1994 12:45:27 GMT"]) - let awsResponse = try await AWSResponse(from: response, streaming: false) - let a: A = try awsResponse.generateOutputShape(operation: "TestOperation", serviceProtocol: .restxml) + let a: A = try response.generateOutputShape(operation: "TestOperation", serviceProtocol: .restxml) XCTAssertEqual(self.dateFormatter.string(from: a.date), "1994-11-15T12:45:27.000Z") } catch { XCTFail("\(error)") @@ -128,8 +125,7 @@ class TimeStampTests: XCTestCase { } let byteBuffer = ByteBuffer(string: "2017-01-01T00:01:00.000Z") let response = AWSHTTPResponse(status: .ok, headers: [:], body: .init(buffer: byteBuffer)) - let awsResponse = try await AWSResponse(from: response, streaming: false) - let a: A = try awsResponse.generateOutputShape(operation: "TestOperation", serviceProtocol: .restxml) + let a: A = try response.generateOutputShape(operation: "TestOperation", serviceProtocol: .restxml) XCTAssertEqual(self.dateFormatter.string(from: a.date), "2017-01-01T00:01:00.000Z") } catch { XCTFail("\(error)") @@ -143,8 +139,7 @@ class TimeStampTests: XCTestCase { } let byteBuffer = ByteBuffer(string: "2017-01-01T00:01:00Z") let response = AWSHTTPResponse(status: .ok, headers: [:], body: .init(buffer: byteBuffer)) - let awsResponse = try await AWSResponse(from: response, streaming: false) - let a: A = try awsResponse.generateOutputShape(operation: "TestOperation", serviceProtocol: .restxml) + let a: A = try response.generateOutputShape(operation: "TestOperation", serviceProtocol: .restxml) XCTAssertEqual(self.dateFormatter.string(from: a.date), "2017-01-01T00:01:00.000Z") } catch { XCTFail("\(error)") @@ -159,8 +154,7 @@ class TimeStampTests: XCTestCase { let xml = "Tue, 15 Nov 1994 12:45:26 GMT" let byteBuffer = ByteBuffer(string: xml) let response = AWSHTTPResponse(status: .ok, headers: [:], body: .init(buffer: byteBuffer)) - let awsResponse = try await AWSResponse(from: response, streaming: false) - let a: A = try awsResponse.generateOutputShape(operation: "TestOperation", serviceProtocol: .restxml) + let a: A = try response.generateOutputShape(operation: "TestOperation", serviceProtocol: .restxml) XCTAssertEqual(self.dateFormatter.string(from: a.date), "1994-11-15T12:45:26.000Z") } catch { XCTFail("\(error)") @@ -175,8 +169,7 @@ class TimeStampTests: XCTestCase { let xml = "1221382800" let byteBuffer = ByteBuffer(string: xml) let response = AWSHTTPResponse(status: .ok, headers: [:], body: .init(buffer: byteBuffer)) - let awsResponse = try await AWSResponse(from: response, streaming: false) - let a: A = try awsResponse.generateOutputShape(operation: "TestOperation", serviceProtocol: .restxml) + let a: A = try response.generateOutputShape(operation: "TestOperation", serviceProtocol: .restxml) XCTAssertEqual(self.dateFormatter.string(from: a.date), "2008-09-14T09:00:00.000Z") } catch { XCTFail("\(error)") @@ -188,8 +181,8 @@ class TimeStampTests: XCTestCase { @CustomCoding var date: Date } let a = A(date: dateFormatter.date(from: "2019-05-01T00:00:00.001Z")!) - var request: AWSRequest? - XCTAssertNoThrow(request = try AWSRequest(operation: "test", path: "/", httpMethod: .GET, input: a, configuration: createServiceConfig(serviceProtocol: .restxml))) + var request: AWSHTTPRequest? + XCTAssertNoThrow(request = try AWSHTTPRequest(operation: "test", path: "/", method: .GET, input: a, configuration: createServiceConfig(serviceProtocol: .restxml))) XCTAssertEqual(request?.body.asString(), "2019-05-01T00:00:00.001Z") } @@ -198,8 +191,8 @@ class TimeStampTests: XCTestCase { @CustomCoding var date: Date } let a = A(date: dateFormatter.date(from: "2019-05-01T00:00:00.001Z")!) - var request: AWSRequest? - XCTAssertNoThrow(request = try AWSRequest(operation: "test", path: "/", httpMethod: .GET, input: a, configuration: createServiceConfig())) + var request: AWSHTTPRequest? + XCTAssertNoThrow(request = try AWSHTTPRequest(operation: "test", path: "/", method: .GET, input: a, configuration: createServiceConfig())) XCTAssertEqual(request?.body.asString(), "{\"date\":\"Wed, 1 May 2019 00:00:00 GMT\"}") } @@ -208,8 +201,8 @@ class TimeStampTests: XCTestCase { @CustomCoding var date: Date } let a = A(date: Date(timeIntervalSince1970: 23_983_978_378)) - var request: AWSRequest? - XCTAssertNoThrow(request = try AWSRequest(operation: "test", path: "/", httpMethod: .GET, input: a, configuration: createServiceConfig())) + var request: AWSHTTPRequest? + XCTAssertNoThrow(request = try AWSHTTPRequest(operation: "test", path: "/", method: .GET, input: a, configuration: createServiceConfig())) XCTAssertEqual(request?.body.asString(), "{\"date\":23983978378}") } }