From 6c0f032f004536cc5234dfdc9513583576b2d437 Mon Sep 17 00:00:00 2001 From: Simon Whitty Date: Tue, 11 Feb 2025 09:21:58 +1100 Subject: [PATCH] buffer requests with complete data --- FlyingFox/Sources/HTTPClient.swift | 2 +- FlyingFox/Sources/HTTPDecoder.swift | 24 ++++++-- FlyingFox/Sources/HTTPRoute.swift | 10 +++- .../Sources/HTTPServer+Configuration.swift | 4 +- FlyingFox/Sources/HTTPServer.swift | 2 +- FlyingFox/Tests/HTTPConnectionTests.swift | 2 +- FlyingFox/Tests/HTTPDecoderTests.swift | 54 +++++++++--------- FlyingFox/Tests/HTTPRequest+Mock.swift | 11 +++- FlyingFox/XCTests/HTTPConnectionTests.swift | 2 +- FlyingFox/XCTests/HTTPDecoderTests.swift | 55 +++++++++---------- FlyingFox/XCTests/HTTPRequest+Mock.swift | 11 +++- 11 files changed, 106 insertions(+), 71 deletions(-) diff --git a/FlyingFox/Sources/HTTPClient.swift b/FlyingFox/Sources/HTTPClient.swift index 21eafa70..7895241d 100644 --- a/FlyingFox/Sources/HTTPClient.swift +++ b/FlyingFox/Sources/HTTPClient.swift @@ -53,7 +53,7 @@ package extension AsyncSocket { } func readResponse() async throws -> HTTPResponse { - try await HTTPDecoder(sharedRequestReplaySize: 102_400).decodeResponse(from: bytes) + try await HTTPDecoder(sharedRequestBufferSize: 4096, sharedRequestReplaySize: 102_400).decodeResponse(from: bytes) } func writeFrame(_ frame: WSFrame) async throws { diff --git a/FlyingFox/Sources/HTTPDecoder.swift b/FlyingFox/Sources/HTTPDecoder.swift index 3e0649f0..0e466c9a 100644 --- a/FlyingFox/Sources/HTTPDecoder.swift +++ b/FlyingFox/Sources/HTTPDecoder.swift @@ -34,6 +34,7 @@ import Foundation struct HTTPDecoder { + var sharedRequestBufferSize: Int var sharedRequestReplaySize: Int func decodeRequest(from bytes: some AsyncBufferedSequence) async throws -> HTTPRequest { @@ -115,16 +116,27 @@ struct HTTPDecoder { } func readBody(from bytes: some AsyncBufferedSequence, length: String?) async throws -> HTTPBodySequence { - guard let length = length.flatMap(Int.init) else { - return HTTPBodySequence(data: Data()) + let length = length.flatMap(Int.init) ?? 0 + guard sharedRequestBufferSize > 0 else { + throw SocketError.disconnected } - - if length <= sharedRequestReplaySize { - return HTTPBodySequence(shared: bytes, count: length, suggestedBufferSize: 4096) + if length <= sharedRequestBufferSize { + return try await HTTPBodySequence(data: readData(from: bytes, length: length), suggestedBufferSize: length) + } else if length <= sharedRequestReplaySize { + return HTTPBodySequence(shared: bytes, count: length, suggestedBufferSize: sharedRequestBufferSize) } else { let prefix = AsyncBufferedPrefixSequence(base: bytes, count: length) - return HTTPBodySequence(from: prefix, count: length, suggestedBufferSize: 4096) + return HTTPBodySequence(from: prefix, count: length, suggestedBufferSize: sharedRequestBufferSize) + } + } + + private func readData(from bytes: some AsyncBufferedSequence, length: Int) async throws -> Data { + var iterator = bytes.makeAsyncIterator() + guard let buffer = try await iterator.nextBuffer(count: length), + buffer.count == length else { + throw SocketError.disconnected } + return Data(buffer) } } diff --git a/FlyingFox/Sources/HTTPRoute.swift b/FlyingFox/Sources/HTTPRoute.swift index a30bd968..703b1167 100644 --- a/FlyingFox/Sources/HTTPRoute.swift +++ b/FlyingFox/Sources/HTTPRoute.swift @@ -313,11 +313,11 @@ private extension HTTPRoute { static func readComponents(from path: String) -> (path: String, query: [HTTPRequest.QueryItem]) { guard path.removingPercentEncoding == path else { - return HTTPDecoder(sharedRequestReplaySize: 0).readComponents(from: path) + return HTTPDecoder().readComponents(from: path) } let escaped = path.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) - return HTTPDecoder(sharedRequestReplaySize: 0).readComponents(from: escaped ?? path) + return HTTPDecoder().readComponents(from: escaped ?? path) } } @@ -379,3 +379,9 @@ public extension Array where Element == HTTPRoute.Parameter { } } } + +private extension HTTPDecoder { + init() { + self.init(sharedRequestBufferSize: 128, sharedRequestReplaySize: 1024) + } +} diff --git a/FlyingFox/Sources/HTTPServer+Configuration.swift b/FlyingFox/Sources/HTTPServer+Configuration.swift index 0a3742a9..5a9a5fd2 100644 --- a/FlyingFox/Sources/HTTPServer+Configuration.swift +++ b/FlyingFox/Sources/HTTPServer+Configuration.swift @@ -37,17 +37,20 @@ public extension HTTPServer { struct Configuration: Sendable { public var address: any SocketAddress public var timeout: TimeInterval + public var sharedRequestBufferSize: Int public var sharedRequestReplaySize: Int public var pool: any AsyncSocketPool public var logger: any Logging public init(address: some SocketAddress, timeout: TimeInterval = 15, + sharedRequestBufferSize: Int = 4_096, sharedRequestReplaySize: Int = 2_097_152, pool: any AsyncSocketPool = HTTPServer.defaultPool(), logger: any Logging = HTTPServer.defaultLogger()) { self.address = address self.timeout = timeout + self.sharedRequestBufferSize = sharedRequestBufferSize self.sharedRequestReplaySize = sharedRequestReplaySize self.pool = pool self.logger = logger @@ -55,7 +58,6 @@ public extension HTTPServer { } } - extension HTTPServer.Configuration { init(port: UInt16, diff --git a/FlyingFox/Sources/HTTPServer.swift b/FlyingFox/Sources/HTTPServer.swift index c92869e1..82142a1d 100644 --- a/FlyingFox/Sources/HTTPServer.swift +++ b/FlyingFox/Sources/HTTPServer.swift @@ -208,7 +208,7 @@ public final actor HTTPServer { private func makeConnection(socket: AsyncSocket) -> HTTPConnection { HTTPConnection( socket: socket, - decoder: HTTPDecoder(sharedRequestReplaySize: config.sharedRequestReplaySize), + decoder: HTTPDecoder(sharedRequestBufferSize: config.sharedRequestBufferSize, sharedRequestReplaySize: config.sharedRequestReplaySize), logger: config.logger ) } diff --git a/FlyingFox/Tests/HTTPConnectionTests.swift b/FlyingFox/Tests/HTTPConnectionTests.swift index 650293c3..071f41e9 100644 --- a/FlyingFox/Tests/HTTPConnectionTests.swift +++ b/FlyingFox/Tests/HTTPConnectionTests.swift @@ -149,7 +149,7 @@ private extension HTTPConnection { init(socket: AsyncSocket) { self.init( socket: socket, - decoder: HTTPDecoder(sharedRequestReplaySize: 1024), + decoder: HTTPDecoder.make(), logger: .disabled ) } diff --git a/FlyingFox/Tests/HTTPDecoderTests.swift b/FlyingFox/Tests/HTTPDecoderTests.swift index a7f65a54..bc5873ef 100644 --- a/FlyingFox/Tests/HTTPDecoderTests.swift +++ b/FlyingFox/Tests/HTTPDecoderTests.swift @@ -38,7 +38,7 @@ struct HTTPDecoderTests { @Test func GETMethod_IsParsed() async throws { - let request = try await HTTPDecoder().decodeRequestFromString( + let request = try await HTTPDecoder.make().decodeRequestFromString( """ GET /hello HTTP/1.1\r \r @@ -52,7 +52,7 @@ struct HTTPDecoderTests { @Test func POSTMethod_IsParsed() async throws { - let request = try await HTTPDecoder().decodeRequestFromString( + let request = try await HTTPDecoder.make().decodeRequestFromString( """ POST /hello HTTP/1.1\r \r @@ -66,7 +66,7 @@ struct HTTPDecoderTests { @Test func CUSTOMMethod_IsParsed() async throws { - let request = try await HTTPDecoder().decodeRequestFromString( + let request = try await HTTPDecoder.make().decodeRequestFromString( """ FISH /hello HTTP/1.1\r \r @@ -80,7 +80,7 @@ struct HTTPDecoderTests { @Test func path_IsParsed() async throws { - let request = try await HTTPDecoder().decodeRequestFromString( + let request = try await HTTPDecoder.make().decodeRequestFromString( """ GET /hello/world?fish=Chips&with=Mushy%20Peas HTTP/1.1\r \r @@ -101,7 +101,7 @@ struct HTTPDecoderTests { @Test func naughtyPath_IsParsed() async throws { - let request = try await HTTPDecoder().decodeRequestFromString( + let request = try await HTTPDecoder.make().decodeRequestFromString( """ GET /../a/b/../c/./d.html?fish=Chips&with=Mushy%20Peas HTTP/1.1\r \r @@ -128,7 +128,7 @@ struct HTTPDecoderTests { @Test func headers_AreParsed() async throws { - let request = try await HTTPDecoder().decodeRequestFromString( + let request = try await HTTPDecoder.make().decodeRequestFromString( """ GET /hello HTTP/1.1\r Fish: Chips\r @@ -149,7 +149,7 @@ struct HTTPDecoderTests { @Test func body_IsNotParsed_WhenContentLength_IsNotProvided() async throws { - let request = try await HTTPDecoder().decodeRequestFromString( + let request = try await HTTPDecoder.make().decodeRequestFromString( """ GET /hello HTTP/1.1\r \r @@ -164,7 +164,7 @@ struct HTTPDecoderTests { @Test func body_IsParsed_WhenContentLength_IsProvided() async throws { - let request = try await HTTPDecoder().decodeRequestFromString( + let request = try await HTTPDecoder.make().decodeRequestFromString( """ GET /hello HTTP/1.1\r Content-Length: 5\r @@ -181,7 +181,7 @@ struct HTTPDecoderTests { @Test func invalidStatusLine_ThrowsError() async { await #expect(throws: HTTPDecoder.Error.self) { - try await HTTPDecoder().decodeRequestFromString( + try await HTTPDecoder.make().decodeRequestFromString( """ GET/hello HTTP/1.1\r \r @@ -193,27 +193,32 @@ struct HTTPDecoderTests { @Test func body_ThrowsError_WhenSequenceEnds() async throws { await #expect(throws: SocketError.self) { - try await HTTPDecoder().readBody(from: AsyncBufferedEmptySequence(completeImmediately: true), length: "100").get() + try await HTTPDecoder.make(sharedRequestReplaySize: 1024).readBody(from: AsyncBufferedEmptySequence(completeImmediately: true), length: "100").get() + } + await #expect(throws: SocketError.self) { + try await HTTPDecoder.make(sharedRequestBufferSize: 1024).readBody(from: AsyncBufferedEmptySequence(completeImmediately: true), length: "100").get() } } @Test func bodySequence_CanReplay_WhenSizeIsLessThanMax() async throws { - let sequence = try await HTTPDecoder(sharedRequestReplaySize: 100).readBodyFromString("Fish & Chips") + let decoder = HTTPDecoder.make(sharedRequestBufferSize: 1, sharedRequestReplaySize: 100) + let sequence = try await decoder.readBodyFromString("Fish & Chips") #expect(sequence.count == 12) #expect(sequence.canReplay) } @Test func bodySequence_CanNotReplay_WhenSizeIsGreaterThanMax() async throws { - let sequence = try await HTTPDecoder(sharedRequestReplaySize: 2).readBodyFromString("Fish & Chips") + let decoder = HTTPDecoder.make(sharedRequestBufferSize: 1, sharedRequestReplaySize: 2) + let sequence = try await decoder.readBodyFromString("Fish & Chips") #expect(sequence.count == 12) #expect(!sequence.canReplay) } @Test func invalidPathDecodes() { - let comps = HTTPDecoder().makeComponents(from: nil) + let comps = HTTPDecoder.make().makeComponents(from: nil) #expect(comps.path == "") #expect(comps.query == []) } @@ -221,22 +226,22 @@ struct HTTPDecoderTests { @Test func percentEncodedPathDecodes() { #expect( - HTTPDecoder().readComponents(from: "/fish%20chips").path == "/fish chips" + HTTPDecoder.make().readComponents(from: "/fish%20chips").path == "/fish chips" ) #expect( - HTTPDecoder().readComponents(from: "/ocean/fish%20and%20chips").path == "/ocean/fish and chips" + HTTPDecoder.make().readComponents(from: "/ocean/fish%20and%20chips").path == "/ocean/fish and chips" ) } @Test func percentQueryStringDecodes() { #expect( - HTTPDecoder().readComponents(from: "/?fish=%F0%9F%90%9F").query == [ + HTTPDecoder.make().readComponents(from: "/?fish=%F0%9F%90%9F").query == [ .init(name: "fish", value: "🐟") ] ) #expect( - HTTPDecoder().readComponents(from: "?%F0%9F%90%A1=chips").query == [ + HTTPDecoder.make().readComponents(from: "?%F0%9F%90%A1=chips").query == [ .init(name: "🐡", value: "chips") ] ) @@ -248,7 +253,7 @@ struct HTTPDecoderTests { urlComps.queryItems = [.init(name: "name", value: nil)] #expect( - HTTPDecoder().makeComponents(from: urlComps).query == [ + HTTPDecoder.make().makeComponents(from: urlComps).query == [ .init(name: "name", value: "") ] ) @@ -257,7 +262,7 @@ struct HTTPDecoderTests { @Test func responseInvalidStatusLine_ThrowsErrorM() async throws { await #expect(throws: HTTPDecoder.Error.self) { - try await HTTPDecoder().decodeRequestFromString( + try await HTTPDecoder.make().decodeRequestFromString( """ HTTP/1.1\r \r @@ -268,7 +273,7 @@ struct HTTPDecoderTests { @Test func responseBody_IsNotParsed_WhenContentLength_IsNotProvided() async throws { - let response = try await HTTPDecoder().decodeResponseFromString( + let response = try await HTTPDecoder.make().decodeResponseFromString( """ HTTP/1.1 202 OK \r \r @@ -283,7 +288,7 @@ struct HTTPDecoderTests { @Test func responseBody_IsParsed_WhenContentLength_IsProvided() async throws { - let response = try await HTTPDecoder().decodeResponseFromString( + let response = try await HTTPDecoder.make().decodeResponseFromString( """ HTTP/1.1 202 OK \r Content-Length: 5\r @@ -316,10 +321,3 @@ private extension HTTPDecoder { ) } } - -private extension HTTPDecoder { - - init() { - self.init(sharedRequestReplaySize: 1024) - } -} diff --git a/FlyingFox/Tests/HTTPRequest+Mock.swift b/FlyingFox/Tests/HTTPRequest+Mock.swift index dd6bd535..5ee97d97 100644 --- a/FlyingFox/Tests/HTTPRequest+Mock.swift +++ b/FlyingFox/Tests/HTTPRequest+Mock.swift @@ -50,7 +50,7 @@ extension HTTPRequest { } static func make(method: HTTPMethod = .GET, _ url: String, headers: [HTTPHeader: String] = [:]) -> Self { - let (path, query) = HTTPDecoder(sharedRequestReplaySize: 0).readComponents(from: url.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!) + let (path, query) = HTTPDecoder.make().readComponents(from: url.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!) return HTTPRequest.make( method: method, path: path, @@ -65,3 +65,12 @@ extension HTTPRequest { } } } + +extension HTTPDecoder { + static func make(sharedRequestBufferSize: Int = 128, sharedRequestReplaySize: Int = 1024) -> HTTPDecoder { + HTTPDecoder( + sharedRequestBufferSize: sharedRequestBufferSize, + sharedRequestReplaySize: sharedRequestReplaySize + ) + } +} diff --git a/FlyingFox/XCTests/HTTPConnectionTests.swift b/FlyingFox/XCTests/HTTPConnectionTests.swift index f9a5ab9e..e8b95c05 100644 --- a/FlyingFox/XCTests/HTTPConnectionTests.swift +++ b/FlyingFox/XCTests/HTTPConnectionTests.swift @@ -147,7 +147,7 @@ private extension HTTPConnection { init(socket: AsyncSocket) { self.init( socket: socket, - decoder: HTTPDecoder(sharedRequestReplaySize: 1024), + decoder: HTTPDecoder.make(sharedRequestReplaySize: 1024), logger: .disabled ) } diff --git a/FlyingFox/XCTests/HTTPDecoderTests.swift b/FlyingFox/XCTests/HTTPDecoderTests.swift index 4d795dba..d95eec15 100644 --- a/FlyingFox/XCTests/HTTPDecoderTests.swift +++ b/FlyingFox/XCTests/HTTPDecoderTests.swift @@ -37,7 +37,7 @@ import XCTest final class HTTPDecoderTests: XCTestCase { func testGETMethod_IsParsed() async throws { - let request = try await HTTPDecoder().decodeRequestFromString( + let request = try await HTTPDecoder.make().decodeRequestFromString( """ GET /hello HTTP/1.1\r \r @@ -51,7 +51,7 @@ final class HTTPDecoderTests: XCTestCase { } func testPOSTMethod_IsParsed() async throws { - let request = try await HTTPDecoder().decodeRequestFromString( + let request = try await HTTPDecoder.make().decodeRequestFromString( """ POST /hello HTTP/1.1\r \r @@ -65,7 +65,7 @@ final class HTTPDecoderTests: XCTestCase { } func testCUSTOMMethod_IsParsed() async throws { - let request = try await HTTPDecoder().decodeRequestFromString( + let request = try await HTTPDecoder.make().decodeRequestFromString( """ FISH /hello HTTP/1.1\r \r @@ -79,7 +79,7 @@ final class HTTPDecoderTests: XCTestCase { } func testPath_IsParsed() async throws { - let request = try await HTTPDecoder().decodeRequestFromString( + let request = try await HTTPDecoder.make().decodeRequestFromString( """ GET /hello/world?fish=Chips&with=Mushy%20Peas HTTP/1.1\r \r @@ -99,7 +99,7 @@ final class HTTPDecoderTests: XCTestCase { } func testNaughtyPath_IsParsed() async throws { - let request = try await HTTPDecoder().decodeRequestFromString( + let request = try await HTTPDecoder.make().decodeRequestFromString( """ GET /../a/b/../c/./d.html?fish=Chips&with=Mushy%20Peas HTTP/1.1\r \r @@ -126,7 +126,7 @@ final class HTTPDecoderTests: XCTestCase { } func testHeaders_AreParsed() async throws { - let request = try await HTTPDecoder().decodeRequestFromString( + let request = try await HTTPDecoder.make().decodeRequestFromString( """ GET /hello HTTP/1.1\r Fish: Chips\r @@ -145,7 +145,7 @@ final class HTTPDecoderTests: XCTestCase { } func testBody_IsNotParsed_WhenContentLength_IsNotProvided() async throws { - let request = try await HTTPDecoder().decodeRequestFromString( + let request = try await HTTPDecoder.make().decodeRequestFromString( """ GET /hello HTTP/1.1\r \r @@ -160,7 +160,7 @@ final class HTTPDecoderTests: XCTestCase { } func testBody_IsParsed_WhenContentLength_IsProvided() async throws { - let request = try await HTTPDecoder().decodeRequestFromString( + let request = try await HTTPDecoder.make().decodeRequestFromString( """ GET /hello HTTP/1.1\r Content-Length: 5\r @@ -177,7 +177,7 @@ final class HTTPDecoderTests: XCTestCase { func testInvalidStatusLine_ThrowsErrorM() async throws { do { - _ = try await HTTPDecoder().decodeRequestFromString( + _ = try await HTTPDecoder.make().decodeRequestFromString( """ GET/hello HTTP/1.1\r \r @@ -191,25 +191,31 @@ final class HTTPDecoderTests: XCTestCase { func testBody_ThrowsError_WhenSequenceEnds() async throws { await AsyncAssertThrowsError( - _ = try await HTTPDecoder().readBody(from: AsyncBufferedEmptySequence(completeImmediately: true), length: "100").get(), + _ = try await HTTPDecoder.make(sharedRequestReplaySize: 1024).readBody(from: AsyncBufferedEmptySequence(completeImmediately: true), length: "100").get(), + of: SocketError.self + ) + await AsyncAssertThrowsError( + _ = try await HTTPDecoder.make(sharedRequestReplaySize: 1024).readBody(from: AsyncBufferedEmptySequence(completeImmediately: true), length: "100").get(), of: SocketError.self ) } func testBodySequence_CanReplay_WhenSizeIsLessThanMax() async throws { - let sequence = try await HTTPDecoder(sharedRequestReplaySize: 100).readBodyFromString("Fish & Chips") + let decoder = HTTPDecoder.make(sharedRequestBufferSize: 1, sharedRequestReplaySize: 100) + let sequence = try await decoder.readBodyFromString("Fish & Chips") XCTAssertEqual(sequence.count, 12) XCTAssertTrue(sequence.canReplay) } func testBodySequence_CanNotReplay_WhenSizeIsGreaterThanMax() async throws { - let sequence = try await HTTPDecoder(sharedRequestReplaySize: 2).readBodyFromString("Fish & Chips") + let decoder = HTTPDecoder.make(sharedRequestBufferSize: 1, sharedRequestReplaySize: 2) + let sequence = try await decoder.readBodyFromString("Fish & Chips") XCTAssertEqual(sequence.count, 12) XCTAssertFalse(sequence.canReplay) } func testInvalidPathDecodes() { - let comps = HTTPDecoder().makeComponents(from: nil) + let comps = HTTPDecoder.make().makeComponents(from: nil) XCTAssertEqual( comps.path, "" ) @@ -220,22 +226,22 @@ final class HTTPDecoderTests: XCTestCase { func testPercentEncodedPathDecodes() { XCTAssertEqual( - HTTPDecoder().readComponents(from: "/fish%20chips").path, + HTTPDecoder.make().readComponents(from: "/fish%20chips").path, "/fish chips" ) XCTAssertEqual( - HTTPDecoder().readComponents(from: "/ocean/fish%20and%20chips").path, + HTTPDecoder.make().readComponents(from: "/ocean/fish%20and%20chips").path, "/ocean/fish and chips" ) } func testPercentQueryStringDecodes() { XCTAssertEqual( - HTTPDecoder().readComponents(from: "/?fish=%F0%9F%90%9F").query, + HTTPDecoder.make().readComponents(from: "/?fish=%F0%9F%90%9F").query, [.init(name: "fish", value: "🐟")] ) XCTAssertEqual( - HTTPDecoder().readComponents(from: "?%F0%9F%90%A1=chips").query, + HTTPDecoder.make().readComponents(from: "?%F0%9F%90%A1=chips").query, [.init(name: "🐡", value: "chips")] ) } @@ -245,14 +251,14 @@ final class HTTPDecoderTests: XCTestCase { urlComps.queryItems = [.init(name: "name", value: nil)] XCTAssertEqual( - HTTPDecoder().makeComponents(from: urlComps).query, + HTTPDecoder.make().makeComponents(from: urlComps).query, [.init(name: "name", value: "")] ) } func testResponseInvalidStatusLine_ThrowsErrorM() async throws { do { - _ = try await HTTPDecoder().decodeResponseFromString( + _ = try await HTTPDecoder.make().decodeResponseFromString( """ HTTP/1.1\r \r @@ -265,7 +271,7 @@ final class HTTPDecoderTests: XCTestCase { } func testResponseBody_IsNotParsed_WhenContentLength_IsNotProvided() async throws { - let response = try await HTTPDecoder().decodeResponseFromString( + let response = try await HTTPDecoder.make().decodeResponseFromString( """ HTTP/1.1 202 OK \r \r @@ -280,7 +286,7 @@ final class HTTPDecoderTests: XCTestCase { } func testResponseBody_IsParsed_WhenContentLength_IsProvided() async throws { - let response = try await HTTPDecoder().decodeResponseFromString( + let response = try await HTTPDecoder.make().decodeResponseFromString( """ HTTP/1.1 202 OK \r Content-Length: 5\r @@ -314,10 +320,3 @@ private extension HTTPDecoder { ) } } - -private extension HTTPDecoder { - - init() { - self.init(sharedRequestReplaySize: 1024) - } -} diff --git a/FlyingFox/XCTests/HTTPRequest+Mock.swift b/FlyingFox/XCTests/HTTPRequest+Mock.swift index 324d640f..69b80a00 100644 --- a/FlyingFox/XCTests/HTTPRequest+Mock.swift +++ b/FlyingFox/XCTests/HTTPRequest+Mock.swift @@ -50,7 +50,7 @@ extension HTTPRequest { } static func make(method: HTTPMethod = .GET, _ url: String, headers: [HTTPHeader: String] = [:]) -> Self { - let (path, query) = HTTPDecoder(sharedRequestReplaySize: 0).readComponents(from: url.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!) + let (path, query) = HTTPDecoder.make().readComponents(from: url.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!) return HTTPRequest.make( method: method, path: path, @@ -59,3 +59,12 @@ extension HTTPRequest { ) } } + +extension HTTPDecoder { + static func make(sharedRequestBufferSize: Int = 128, sharedRequestReplaySize: Int = 1024) -> HTTPDecoder { + HTTPDecoder( + sharedRequestBufferSize: sharedRequestBufferSize, + sharedRequestReplaySize: sharedRequestReplaySize + ) + } +}