mirror of
https://github.com/apple/swift-nio-extras.git
synced 2025-05-15 17:38:53 +08:00
Merge branch 'main' into enable_macos_ci_prs
This commit is contained in:
commit
aa55df982c
@ -50,7 +50,8 @@ var targets: [PackageDescription.Target] = [
|
|||||||
.product(name: "NIO", package: "swift-nio"),
|
.product(name: "NIO", package: "swift-nio"),
|
||||||
.product(name: "NIOCore", package: "swift-nio"),
|
.product(name: "NIOCore", package: "swift-nio"),
|
||||||
.product(name: "NIOHTTP1", package: "swift-nio"),
|
.product(name: "NIOHTTP1", package: "swift-nio"),
|
||||||
]
|
],
|
||||||
|
swiftSettings: strictConcurrencySettings
|
||||||
),
|
),
|
||||||
.executableTarget(
|
.executableTarget(
|
||||||
name: "HTTPServerWithQuiescingDemo",
|
name: "HTTPServerWithQuiescingDemo",
|
||||||
@ -68,7 +69,8 @@ var targets: [PackageDescription.Target] = [
|
|||||||
.product(name: "NIOCore", package: "swift-nio"),
|
.product(name: "NIOCore", package: "swift-nio"),
|
||||||
.product(name: "NIOPosix", package: "swift-nio"),
|
.product(name: "NIOPosix", package: "swift-nio"),
|
||||||
.product(name: "NIOHTTP1", package: "swift-nio"),
|
.product(name: "NIOHTTP1", package: "swift-nio"),
|
||||||
]
|
],
|
||||||
|
swiftSettings: strictConcurrencySettings
|
||||||
),
|
),
|
||||||
.executableTarget(
|
.executableTarget(
|
||||||
name: "NIOWritePartialPCAPDemo",
|
name: "NIOWritePartialPCAPDemo",
|
||||||
@ -77,7 +79,8 @@ var targets: [PackageDescription.Target] = [
|
|||||||
.product(name: "NIOCore", package: "swift-nio"),
|
.product(name: "NIOCore", package: "swift-nio"),
|
||||||
.product(name: "NIOPosix", package: "swift-nio"),
|
.product(name: "NIOPosix", package: "swift-nio"),
|
||||||
.product(name: "NIOHTTP1", package: "swift-nio"),
|
.product(name: "NIOHTTP1", package: "swift-nio"),
|
||||||
]
|
],
|
||||||
|
swiftSettings: strictConcurrencySettings
|
||||||
),
|
),
|
||||||
.executableTarget(
|
.executableTarget(
|
||||||
name: "NIOExtrasPerformanceTester",
|
name: "NIOExtrasPerformanceTester",
|
||||||
@ -94,7 +97,8 @@ var targets: [PackageDescription.Target] = [
|
|||||||
dependencies: [
|
dependencies: [
|
||||||
.product(name: "NIO", package: "swift-nio"),
|
.product(name: "NIO", package: "swift-nio"),
|
||||||
.product(name: "NIOCore", package: "swift-nio"),
|
.product(name: "NIOCore", package: "swift-nio"),
|
||||||
]
|
],
|
||||||
|
swiftSettings: strictConcurrencySettings
|
||||||
),
|
),
|
||||||
.executableTarget(
|
.executableTarget(
|
||||||
name: "NIOSOCKSClient",
|
name: "NIOSOCKSClient",
|
||||||
@ -102,7 +106,8 @@ var targets: [PackageDescription.Target] = [
|
|||||||
.product(name: "NIOCore", package: "swift-nio"),
|
.product(name: "NIOCore", package: "swift-nio"),
|
||||||
.product(name: "NIOPosix", package: "swift-nio"),
|
.product(name: "NIOPosix", package: "swift-nio"),
|
||||||
"NIOSOCKS",
|
"NIOSOCKS",
|
||||||
]
|
],
|
||||||
|
swiftSettings: strictConcurrencySettings
|
||||||
),
|
),
|
||||||
.target(
|
.target(
|
||||||
name: "CNIOExtrasZlib",
|
name: "CNIOExtrasZlib",
|
||||||
@ -132,7 +137,8 @@ var targets: [PackageDescription.Target] = [
|
|||||||
.product(name: "NIOEmbedded", package: "swift-nio"),
|
.product(name: "NIOEmbedded", package: "swift-nio"),
|
||||||
.product(name: "NIOHTTP1", package: "swift-nio"),
|
.product(name: "NIOHTTP1", package: "swift-nio"),
|
||||||
.product(name: "NIOConcurrencyHelpers", package: "swift-nio"),
|
.product(name: "NIOConcurrencyHelpers", package: "swift-nio"),
|
||||||
]
|
],
|
||||||
|
swiftSettings: strictConcurrencySettings
|
||||||
),
|
),
|
||||||
.testTarget(
|
.testTarget(
|
||||||
name: "NIOSOCKSTests",
|
name: "NIOSOCKSTests",
|
||||||
@ -140,7 +146,8 @@ var targets: [PackageDescription.Target] = [
|
|||||||
"NIOSOCKS",
|
"NIOSOCKS",
|
||||||
.product(name: "NIOCore", package: "swift-nio"),
|
.product(name: "NIOCore", package: "swift-nio"),
|
||||||
.product(name: "NIOEmbedded", package: "swift-nio"),
|
.product(name: "NIOEmbedded", package: "swift-nio"),
|
||||||
]
|
],
|
||||||
|
swiftSettings: strictConcurrencySettings
|
||||||
),
|
),
|
||||||
.target(
|
.target(
|
||||||
name: "NIONFS3",
|
name: "NIONFS3",
|
||||||
@ -162,33 +169,38 @@ var targets: [PackageDescription.Target] = [
|
|||||||
dependencies: [
|
dependencies: [
|
||||||
.product(name: "HTTPTypes", package: "swift-http-types"),
|
.product(name: "HTTPTypes", package: "swift-http-types"),
|
||||||
.product(name: "NIOCore", package: "swift-nio"),
|
.product(name: "NIOCore", package: "swift-nio"),
|
||||||
]
|
],
|
||||||
|
swiftSettings: strictConcurrencySettings
|
||||||
),
|
),
|
||||||
.target(
|
.target(
|
||||||
name: "NIOHTTPTypesHTTP1",
|
name: "NIOHTTPTypesHTTP1",
|
||||||
dependencies: [
|
dependencies: [
|
||||||
"NIOHTTPTypes",
|
"NIOHTTPTypes",
|
||||||
.product(name: "NIOHTTP1", package: "swift-nio"),
|
.product(name: "NIOHTTP1", package: "swift-nio"),
|
||||||
]
|
],
|
||||||
|
swiftSettings: strictConcurrencySettings
|
||||||
),
|
),
|
||||||
.target(
|
.target(
|
||||||
name: "NIOHTTPTypesHTTP2",
|
name: "NIOHTTPTypesHTTP2",
|
||||||
dependencies: [
|
dependencies: [
|
||||||
"NIOHTTPTypes",
|
"NIOHTTPTypes",
|
||||||
.product(name: "NIOHTTP2", package: "swift-nio-http2"),
|
.product(name: "NIOHTTP2", package: "swift-nio-http2"),
|
||||||
]
|
],
|
||||||
|
swiftSettings: strictConcurrencySettings
|
||||||
),
|
),
|
||||||
.testTarget(
|
.testTarget(
|
||||||
name: "NIOHTTPTypesHTTP1Tests",
|
name: "NIOHTTPTypesHTTP1Tests",
|
||||||
dependencies: [
|
dependencies: [
|
||||||
"NIOHTTPTypesHTTP1"
|
"NIOHTTPTypesHTTP1"
|
||||||
]
|
],
|
||||||
|
swiftSettings: strictConcurrencySettings
|
||||||
),
|
),
|
||||||
.testTarget(
|
.testTarget(
|
||||||
name: "NIOHTTPTypesHTTP2Tests",
|
name: "NIOHTTPTypesHTTP2Tests",
|
||||||
dependencies: [
|
dependencies: [
|
||||||
"NIOHTTPTypesHTTP2"
|
"NIOHTTPTypesHTTP2"
|
||||||
]
|
],
|
||||||
|
swiftSettings: strictConcurrencySettings
|
||||||
),
|
),
|
||||||
.target(
|
.target(
|
||||||
name: "NIOResumableUpload",
|
name: "NIOResumableUpload",
|
||||||
@ -225,9 +237,7 @@ var targets: [PackageDescription.Target] = [
|
|||||||
.product(name: "HTTPTypes", package: "swift-http-types"),
|
.product(name: "HTTPTypes", package: "swift-http-types"),
|
||||||
.product(name: "Algorithms", package: "swift-algorithms"),
|
.product(name: "Algorithms", package: "swift-algorithms"),
|
||||||
],
|
],
|
||||||
swiftSettings: [
|
swiftSettings: strictConcurrencySettings
|
||||||
.enableExperimentalFeature("StrictConcurrency")
|
|
||||||
]
|
|
||||||
),
|
),
|
||||||
.testTarget(
|
.testTarget(
|
||||||
name: "NIOHTTPResponsivenessTests",
|
name: "NIOHTTPResponsivenessTests",
|
||||||
@ -238,9 +248,7 @@ var targets: [PackageDescription.Target] = [
|
|||||||
.product(name: "NIOEmbedded", package: "swift-nio"),
|
.product(name: "NIOEmbedded", package: "swift-nio"),
|
||||||
.product(name: "HTTPTypes", package: "swift-http-types"),
|
.product(name: "HTTPTypes", package: "swift-http-types"),
|
||||||
],
|
],
|
||||||
swiftSettings: [
|
swiftSettings: strictConcurrencySettings
|
||||||
.enableExperimentalFeature("StrictConcurrency")
|
|
||||||
]
|
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ import CNIOExtrasZlib
|
|||||||
import NIOCore
|
import NIOCore
|
||||||
|
|
||||||
/// Namespace for compression code.
|
/// Namespace for compression code.
|
||||||
public enum NIOCompression {
|
public enum NIOCompression: Sendable {
|
||||||
|
|
||||||
/// Which algorithm should be used for compression.
|
/// Which algorithm should be used for compression.
|
||||||
public struct Algorithm: CustomStringConvertible, Equatable, Sendable {
|
public struct Algorithm: CustomStringConvertible, Equatable, Sendable {
|
||||||
|
@ -16,7 +16,7 @@ import CNIOExtrasZlib
|
|||||||
import NIOCore
|
import NIOCore
|
||||||
|
|
||||||
/// Namespace for decompression code.
|
/// Namespace for decompression code.
|
||||||
public enum NIOHTTPDecompression {
|
public enum NIOHTTPDecompression: Sendable {
|
||||||
/// Specifies how to limit decompression inflation.
|
/// Specifies how to limit decompression inflation.
|
||||||
public struct DecompressionLimit: Sendable {
|
public struct DecompressionLimit: Sendable {
|
||||||
private enum Limit {
|
private enum Limit {
|
||||||
|
@ -253,3 +253,6 @@ public final class HTTPDrippingDownloadHandler: ChannelDuplexHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@available(*, unavailable)
|
||||||
|
extension HTTPDrippingDownloadHandler: Sendable {}
|
||||||
|
@ -88,3 +88,6 @@ public final class HTTPReceiveDiscardHandler: ChannelInboundHandler {
|
|||||||
context.writeAndFlush(self.wrapOutboundOut(.end(nil)), promise: nil)
|
context.writeAndFlush(self.wrapOutboundOut(.end(nil)), promise: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@available(*, unavailable)
|
||||||
|
extension HTTPReceiveDiscardHandler: Sendable {}
|
||||||
|
@ -143,3 +143,6 @@ public final class SimpleResponsivenessRequestMux: ChannelInboundHandler {
|
|||||||
context.writeAndFlush(self.wrapOutboundOut(.end(nil)), promise: nil)
|
context.writeAndFlush(self.wrapOutboundOut(.end(nil)), promise: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@available(*, unavailable)
|
||||||
|
extension SimpleResponsivenessRequestMux: Sendable {}
|
||||||
|
@ -19,7 +19,7 @@ import NIOHTTPTypes
|
|||||||
|
|
||||||
/// A simple channel handler that translates HTTP/1 messages into shared HTTP types,
|
/// A simple channel handler that translates HTTP/1 messages into shared HTTP types,
|
||||||
/// and vice versa, for use on the client side.
|
/// and vice versa, for use on the client side.
|
||||||
public final class HTTP1ToHTTPClientCodec: ChannelDuplexHandler, RemovableChannelHandler {
|
public final class HTTP1ToHTTPClientCodec: ChannelDuplexHandler, RemovableChannelHandler, Sendable {
|
||||||
public typealias InboundIn = HTTPClientResponsePart
|
public typealias InboundIn = HTTPClientResponsePart
|
||||||
public typealias InboundOut = HTTPResponsePart
|
public typealias InboundOut = HTTPResponsePart
|
||||||
|
|
||||||
@ -66,7 +66,7 @@ public final class HTTP1ToHTTPClientCodec: ChannelDuplexHandler, RemovableChanne
|
|||||||
|
|
||||||
/// A simple channel handler that translates HTTP/1 messages into shared HTTP types,
|
/// A simple channel handler that translates HTTP/1 messages into shared HTTP types,
|
||||||
/// and vice versa, for use on the server side.
|
/// and vice versa, for use on the server side.
|
||||||
public final class HTTP1ToHTTPServerCodec: ChannelDuplexHandler, RemovableChannelHandler {
|
public final class HTTP1ToHTTPServerCodec: ChannelDuplexHandler, RemovableChannelHandler, Sendable {
|
||||||
public typealias InboundIn = HTTPServerRequestPart
|
public typealias InboundIn = HTTPServerRequestPart
|
||||||
public typealias InboundOut = HTTPRequestPart
|
public typealias InboundOut = HTTPRequestPart
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ import NIOHTTPTypes
|
|||||||
/// This is intended for compatibility purposes where a channel handler working with
|
/// This is intended for compatibility purposes where a channel handler working with
|
||||||
/// HTTP/1 messages needs to work on top of the new version-independent HTTP types
|
/// HTTP/1 messages needs to work on top of the new version-independent HTTP types
|
||||||
/// abstraction.
|
/// abstraction.
|
||||||
public final class HTTPToHTTP1ClientCodec: ChannelDuplexHandler, RemovableChannelHandler {
|
public final class HTTPToHTTP1ClientCodec: ChannelDuplexHandler, RemovableChannelHandler, Sendable {
|
||||||
public typealias InboundIn = HTTPResponsePart
|
public typealias InboundIn = HTTPResponsePart
|
||||||
public typealias InboundOut = HTTPClientResponsePart
|
public typealias InboundOut = HTTPClientResponsePart
|
||||||
|
|
||||||
@ -86,7 +86,7 @@ public final class HTTPToHTTP1ClientCodec: ChannelDuplexHandler, RemovableChanne
|
|||||||
/// This is intended for compatibility purposes where a channel handler working with
|
/// This is intended for compatibility purposes where a channel handler working with
|
||||||
/// HTTP/1 messages needs to work on top of the new version-independent HTTP types
|
/// HTTP/1 messages needs to work on top of the new version-independent HTTP types
|
||||||
/// abstraction.
|
/// abstraction.
|
||||||
public final class HTTPToHTTP1ServerCodec: ChannelDuplexHandler, RemovableChannelHandler {
|
public final class HTTPToHTTP1ServerCodec: ChannelDuplexHandler, RemovableChannelHandler, Sendable {
|
||||||
public typealias InboundIn = HTTPRequestPart
|
public typealias InboundIn = HTTPRequestPart
|
||||||
public typealias InboundOut = HTTPServerRequestPart
|
public typealias InboundOut = HTTPServerRequestPart
|
||||||
|
|
||||||
|
@ -162,6 +162,9 @@ public final class HTTP2FramePayloadToHTTPClientCodec: ChannelDuplexHandler, Rem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@available(*, unavailable)
|
||||||
|
extension HTTP2FramePayloadToHTTPClientCodec: Sendable {}
|
||||||
|
|
||||||
// MARK: - Server
|
// MARK: - Server
|
||||||
|
|
||||||
private struct BaseServerCodec {
|
private struct BaseServerCodec {
|
||||||
@ -280,6 +283,9 @@ public final class HTTP2FramePayloadToHTTPServerCodec: ChannelDuplexHandler, Rem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@available(*, unavailable)
|
||||||
|
extension HTTP2FramePayloadToHTTPServerCodec: Sendable {}
|
||||||
|
|
||||||
/// Events that can be sent by the application to be handled by the `HTTP2StreamChannel`
|
/// Events that can be sent by the application to be handled by the `HTTP2StreamChannel`
|
||||||
public struct NIOHTTP2FramePayloadToHTTPEvent: Hashable, Sendable {
|
public struct NIOHTTP2FramePayloadToHTTPEvent: Hashable, Sendable {
|
||||||
private enum Kind: Hashable, Sendable {
|
private enum Kind: Hashable, Sendable {
|
||||||
|
@ -101,9 +101,11 @@ if #available(macOS 10.15.4, iOS 13.4, watchOS 6.2, tvOS 13.4, *) {
|
|||||||
|
|
||||||
let group = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount)
|
let group = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount)
|
||||||
let server = try ServerBootstrap(group: group).childChannelInitializer { channel in
|
let server = try ServerBootstrap(group: group).childChannelInitializer { channel in
|
||||||
channel.pipeline.configureHTTPServerPipeline().flatMap {
|
channel.eventLoop.makeCompletedFuture {
|
||||||
channel.pipeline.addHandlers([
|
let sync = channel.pipeline.syncOperations
|
||||||
HTTP1ToHTTPServerCodec(secure: false),
|
try sync.configureHTTPServerPipeline()
|
||||||
|
try sync.addHandler(HTTP1ToHTTPServerCodec(secure: false))
|
||||||
|
try sync.addHandler(
|
||||||
HTTPResumableUploadHandler(
|
HTTPResumableUploadHandler(
|
||||||
context: uploadContext,
|
context: uploadContext,
|
||||||
handlers: [
|
handlers: [
|
||||||
@ -111,8 +113,8 @@ if #available(macOS 10.15.4, iOS 13.4, watchOS 6.2, tvOS 13.4, *) {
|
|||||||
directory: URL(fileURLWithPath: CommandLine.arguments[1], isDirectory: true)
|
directory: URL(fileURLWithPath: CommandLine.arguments[1], isDirectory: true)
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
),
|
)
|
||||||
])
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.bind(host: "0.0.0.0", port: 8080)
|
.bind(host: "0.0.0.0", port: 8080)
|
||||||
|
@ -12,8 +12,8 @@
|
|||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
/// Wrapper for SOCKS protcol error.
|
/// Wrapper for SOCKS protocol error.
|
||||||
public enum SOCKSError {
|
public enum SOCKSError: Sendable {
|
||||||
|
|
||||||
/// The SOCKS client was in a different state to that required.
|
/// The SOCKS client was in a different state to that required.
|
||||||
public struct InvalidClientState: Error, Hashable {
|
public struct InvalidClientState: Error, Hashable {
|
||||||
|
@ -40,7 +40,7 @@ private class PromiseOrderer {
|
|||||||
let thisPromiseIndex = promiseArray.count
|
let thisPromiseIndex = promiseArray.count
|
||||||
promiseArray.append(promise)
|
promiseArray.append(promise)
|
||||||
|
|
||||||
promise.futureResult.whenComplete { (_: Result<Void, Error>) in
|
promise.futureResult.hop(to: self.eventLoop).assumeIsolated().whenComplete { (_: Result<Void, Error>) in
|
||||||
let priorFutures = self.promiseArray[0..<thisPromiseIndex]
|
let priorFutures = self.promiseArray[0..<thisPromiseIndex]
|
||||||
let subsequentFutures = self.promiseArray[(thisPromiseIndex + 1)...]
|
let subsequentFutures = self.promiseArray[(thisPromiseIndex + 1)...]
|
||||||
let allPriorFuturesFired = priorFutures.map { $0.futureResult.isFulfilled }.allSatisfy { $0 }
|
let allPriorFuturesFired = priorFutures.map { $0.futureResult.isFulfilled }.allSatisfy { $0 }
|
||||||
@ -772,9 +772,11 @@ class HTTPResponseCompressorTest: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testConditionalCompressionEnabled() throws {
|
func testConditionalCompressionEnabled() throws {
|
||||||
let predicateWasCalled = expectation(description: "Predicate was called")
|
let loop = EmbeddedEventLoop()
|
||||||
|
defer { try! loop.syncShutdownGracefully() }
|
||||||
|
let predicateWasCalled = loop.makePromise(of: Void.self)
|
||||||
let compressor = HTTPResponseCompressor { responseHeaders, isCompressionSupported in
|
let compressor = HTTPResponseCompressor { responseHeaders, isCompressionSupported in
|
||||||
defer { predicateWasCalled.fulfill() }
|
defer { predicateWasCalled.succeed() }
|
||||||
XCTAssertEqual(responseHeaders.headers, ["Content-Type": "json"])
|
XCTAssertEqual(responseHeaders.headers, ["Content-Type": "json"])
|
||||||
XCTAssertEqual(isCompressionSupported, true)
|
XCTAssertEqual(isCompressionSupported, true)
|
||||||
return .compressIfPossible
|
return .compressIfPossible
|
||||||
@ -796,13 +798,15 @@ class HTTPResponseCompressorTest: XCTestCase {
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
waitForExpectations(timeout: 0)
|
try predicateWasCalled.futureResult.wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
func testUnsupportedRequestConditionalCompressionEnabled() throws {
|
func testUnsupportedRequestConditionalCompressionEnabled() throws {
|
||||||
let predicateWasCalled = expectation(description: "Predicate was called")
|
let loop = EmbeddedEventLoop()
|
||||||
|
defer { try! loop.syncShutdownGracefully() }
|
||||||
|
let predicateWasCalled = loop.makePromise(of: Void.self)
|
||||||
let compressor = HTTPResponseCompressor { responseHeaders, isCompressionSupported in
|
let compressor = HTTPResponseCompressor { responseHeaders, isCompressionSupported in
|
||||||
defer { predicateWasCalled.fulfill() }
|
defer { predicateWasCalled.succeed() }
|
||||||
XCTAssertEqual(responseHeaders.headers, ["Content-Type": "json"])
|
XCTAssertEqual(responseHeaders.headers, ["Content-Type": "json"])
|
||||||
XCTAssertEqual(isCompressionSupported, false)
|
XCTAssertEqual(isCompressionSupported, false)
|
||||||
return .compressIfPossible
|
return .compressIfPossible
|
||||||
@ -823,13 +827,15 @@ class HTTPResponseCompressorTest: XCTestCase {
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
waitForExpectations(timeout: 0)
|
try predicateWasCalled.futureResult.wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
func testUnsupportedStatusConditionalCompressionEnabled() throws {
|
func testUnsupportedStatusConditionalCompressionEnabled() throws {
|
||||||
let predicateWasCalled = expectation(description: "Predicate was called")
|
let loop = EmbeddedEventLoop()
|
||||||
|
defer { try! loop.syncShutdownGracefully() }
|
||||||
|
let predicateWasCalled = loop.makePromise(of: Void.self)
|
||||||
let compressor = HTTPResponseCompressor { responseHeaders, isCompressionSupported in
|
let compressor = HTTPResponseCompressor { responseHeaders, isCompressionSupported in
|
||||||
defer { predicateWasCalled.fulfill() }
|
defer { predicateWasCalled.succeed() }
|
||||||
XCTAssertEqual(responseHeaders.status, .notModified)
|
XCTAssertEqual(responseHeaders.status, .notModified)
|
||||||
XCTAssertEqual(responseHeaders.headers, ["Content-Type": "json"])
|
XCTAssertEqual(responseHeaders.headers, ["Content-Type": "json"])
|
||||||
XCTAssertEqual(isCompressionSupported, false)
|
XCTAssertEqual(isCompressionSupported, false)
|
||||||
@ -862,13 +868,15 @@ class HTTPResponseCompressorTest: XCTestCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
waitForExpectations(timeout: 0)
|
try predicateWasCalled.futureResult.wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
func testConditionalCompressionDisabled() throws {
|
func testConditionalCompressionDisabled() throws {
|
||||||
let predicateWasCalled = expectation(description: "Predicate was called")
|
let loop = EmbeddedEventLoop()
|
||||||
|
defer { try! loop.syncShutdownGracefully() }
|
||||||
|
let predicateWasCalled = loop.makePromise(of: Void.self)
|
||||||
let compressor = HTTPResponseCompressor { responseHeaders, isCompressionSupported in
|
let compressor = HTTPResponseCompressor { responseHeaders, isCompressionSupported in
|
||||||
defer { predicateWasCalled.fulfill() }
|
defer { predicateWasCalled.succeed() }
|
||||||
XCTAssertEqual(responseHeaders.headers, ["Content-Type": "json"])
|
XCTAssertEqual(responseHeaders.headers, ["Content-Type": "json"])
|
||||||
XCTAssertEqual(isCompressionSupported, true)
|
XCTAssertEqual(isCompressionSupported, true)
|
||||||
return .doNotCompress
|
return .doNotCompress
|
||||||
@ -889,13 +897,15 @@ class HTTPResponseCompressorTest: XCTestCase {
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
waitForExpectations(timeout: 0)
|
try predicateWasCalled.futureResult.wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
func testUnsupportedRequestConditionalCompressionDisabled() throws {
|
func testUnsupportedRequestConditionalCompressionDisabled() throws {
|
||||||
let predicateWasCalled = expectation(description: "Predicate was called")
|
let loop = EmbeddedEventLoop()
|
||||||
|
defer { try! loop.syncShutdownGracefully() }
|
||||||
|
let predicateWasCalled = loop.makePromise(of: Void.self)
|
||||||
let compressor = HTTPResponseCompressor { responseHeaders, isCompressionSupported in
|
let compressor = HTTPResponseCompressor { responseHeaders, isCompressionSupported in
|
||||||
defer { predicateWasCalled.fulfill() }
|
defer { predicateWasCalled.succeed() }
|
||||||
XCTAssertEqual(responseHeaders.headers, ["Content-Type": "json"])
|
XCTAssertEqual(responseHeaders.headers, ["Content-Type": "json"])
|
||||||
XCTAssertEqual(isCompressionSupported, false)
|
XCTAssertEqual(isCompressionSupported, false)
|
||||||
return .doNotCompress
|
return .doNotCompress
|
||||||
@ -916,13 +926,15 @@ class HTTPResponseCompressorTest: XCTestCase {
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
waitForExpectations(timeout: 0)
|
try predicateWasCalled.futureResult.wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
func testUnsupportedStatusConditionalCompressionDisabled() throws {
|
func testUnsupportedStatusConditionalCompressionDisabled() throws {
|
||||||
let predicateWasCalled = expectation(description: "Predicate was called")
|
let loop = EmbeddedEventLoop()
|
||||||
|
defer { try! loop.syncShutdownGracefully() }
|
||||||
|
let predicateWasCalled = loop.makePromise(of: Void.self)
|
||||||
let compressor = HTTPResponseCompressor { responseHeaders, isCompressionSupported in
|
let compressor = HTTPResponseCompressor { responseHeaders, isCompressionSupported in
|
||||||
defer { predicateWasCalled.fulfill() }
|
defer { predicateWasCalled.succeed() }
|
||||||
XCTAssertEqual(responseHeaders.status, .notModified)
|
XCTAssertEqual(responseHeaders.status, .notModified)
|
||||||
XCTAssertEqual(responseHeaders.headers, ["Content-Type": "json"])
|
XCTAssertEqual(responseHeaders.headers, ["Content-Type": "json"])
|
||||||
XCTAssertEqual(isCompressionSupported, false)
|
XCTAssertEqual(isCompressionSupported, false)
|
||||||
@ -955,14 +967,13 @@ class HTTPResponseCompressorTest: XCTestCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
waitForExpectations(timeout: 0)
|
try predicateWasCalled.futureResult.wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
func testConditionalCompressionModifiedHeaders() throws {
|
func testConditionalCompressionModifiedHeaders() throws {
|
||||||
let predicateWasCalled = expectation(description: "Predicate was called")
|
let counter = NIOLockedValueBox(0)
|
||||||
predicateWasCalled.expectedFulfillmentCount = 2
|
|
||||||
let compressor = HTTPResponseCompressor { responseHeaders, isCompressionSupported in
|
let compressor = HTTPResponseCompressor { responseHeaders, isCompressionSupported in
|
||||||
defer { predicateWasCalled.fulfill() }
|
defer { counter.withLockedValue { $0 += 1 } }
|
||||||
let isEnabled = responseHeaders.headers[canonicalForm: "x-compression"].first == "enable"
|
let isEnabled = responseHeaders.headers[canonicalForm: "x-compression"].first == "enable"
|
||||||
XCTAssertEqual(
|
XCTAssertEqual(
|
||||||
responseHeaders.headers,
|
responseHeaders.headers,
|
||||||
@ -999,7 +1010,7 @@ class HTTPResponseCompressorTest: XCTestCase {
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
waitForExpectations(timeout: 0)
|
XCTAssertEqual(counter.withLockedValue { $0 }, 2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1009,25 +1020,22 @@ extension EventLoopFuture {
|
|||||||
// Easy, we're on the EventLoop. Let's just use our knowledge that we run completed future callbacks
|
// Easy, we're on the EventLoop. Let's just use our knowledge that we run completed future callbacks
|
||||||
// immediately.
|
// immediately.
|
||||||
var fulfilled = false
|
var fulfilled = false
|
||||||
self.whenComplete { _ in
|
self.assumeIsolated().whenComplete { _ in
|
||||||
fulfilled = true
|
fulfilled = true
|
||||||
}
|
}
|
||||||
return fulfilled
|
return fulfilled
|
||||||
} else {
|
} else {
|
||||||
let lock = NIOLock()
|
|
||||||
let group = DispatchGroup()
|
let group = DispatchGroup()
|
||||||
var fulfilled = false // protected by lock
|
let fulfilled = NIOLockedValueBox(false)
|
||||||
|
|
||||||
group.enter()
|
group.enter()
|
||||||
self.eventLoop.execute {
|
self.eventLoop.execute {
|
||||||
let isFulfilled = self.isFulfilled // This will now enter the above branch.
|
let isFulfilled = self.isFulfilled // This will now enter the above branch.
|
||||||
lock.withLock {
|
fulfilled.withLockedValue { $0 = isFulfilled }
|
||||||
fulfilled = isFulfilled
|
|
||||||
}
|
|
||||||
group.leave()
|
group.leave()
|
||||||
}
|
}
|
||||||
group.wait() // this is very nasty but this is for tests only, so...
|
group.wait() // this is very nasty but this is for tests only, so...
|
||||||
return lock.withLock { fulfilled }
|
return fulfilled.withLockedValue { $0 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -115,7 +115,7 @@ final class NIOHTTPTypesHTTP1Tests: XCTestCase {
|
|||||||
func testClientHTTP1ToHTTP() throws {
|
func testClientHTTP1ToHTTP() throws {
|
||||||
let recorder = InboundRecorder<HTTPResponsePart>()
|
let recorder = InboundRecorder<HTTPResponsePart>()
|
||||||
|
|
||||||
try self.channel.pipeline.addHandlers(HTTP1ToHTTPClientCodec(), recorder).wait()
|
try self.channel.pipeline.syncOperations.addHandlers(HTTP1ToHTTPClientCodec(), recorder)
|
||||||
|
|
||||||
try self.channel.writeOutbound(HTTPRequestPart.head(Self.request))
|
try self.channel.writeOutbound(HTTPRequestPart.head(Self.request))
|
||||||
try self.channel.writeOutbound(HTTPRequestPart.end(Self.trailers))
|
try self.channel.writeOutbound(HTTPRequestPart.end(Self.trailers))
|
||||||
@ -135,7 +135,7 @@ final class NIOHTTPTypesHTTP1Tests: XCTestCase {
|
|||||||
func testServerHTTP1ToHTTP() throws {
|
func testServerHTTP1ToHTTP() throws {
|
||||||
let recorder = InboundRecorder<HTTPRequestPart>()
|
let recorder = InboundRecorder<HTTPRequestPart>()
|
||||||
|
|
||||||
try self.channel.pipeline.addHandlers(HTTP1ToHTTPServerCodec(secure: true), recorder).wait()
|
try self.channel.pipeline.syncOperations.addHandlers(HTTP1ToHTTPServerCodec(secure: true), recorder)
|
||||||
|
|
||||||
try self.channel.writeInbound(HTTPServerRequestPart.head(Self.oldRequest))
|
try self.channel.writeInbound(HTTPServerRequestPart.head(Self.oldRequest))
|
||||||
try self.channel.writeInbound(HTTPServerRequestPart.end(Self.oldTrailers))
|
try self.channel.writeInbound(HTTPServerRequestPart.end(Self.oldTrailers))
|
||||||
@ -155,7 +155,7 @@ final class NIOHTTPTypesHTTP1Tests: XCTestCase {
|
|||||||
func testClientHTTPToHTTP1() throws {
|
func testClientHTTPToHTTP1() throws {
|
||||||
let recorder = InboundRecorder<HTTPClientResponsePart>()
|
let recorder = InboundRecorder<HTTPClientResponsePart>()
|
||||||
|
|
||||||
try self.channel.pipeline.addHandlers(HTTPToHTTP1ClientCodec(secure: true), recorder).wait()
|
try self.channel.pipeline.syncOperations.addHandlers(HTTPToHTTP1ClientCodec(secure: true), recorder)
|
||||||
|
|
||||||
try self.channel.writeOutbound(HTTPClientRequestPart.head(Self.oldRequest))
|
try self.channel.writeOutbound(HTTPClientRequestPart.head(Self.oldRequest))
|
||||||
try self.channel.writeOutbound(HTTPClientRequestPart.end(Self.oldTrailers))
|
try self.channel.writeOutbound(HTTPClientRequestPart.end(Self.oldTrailers))
|
||||||
@ -175,7 +175,7 @@ final class NIOHTTPTypesHTTP1Tests: XCTestCase {
|
|||||||
func testServerHTTPToHTTP1() throws {
|
func testServerHTTPToHTTP1() throws {
|
||||||
let recorder = InboundRecorder<HTTPServerRequestPart>()
|
let recorder = InboundRecorder<HTTPServerRequestPart>()
|
||||||
|
|
||||||
try self.channel.pipeline.addHandlers(HTTPToHTTP1ServerCodec(), recorder).wait()
|
try self.channel.pipeline.syncOperations.addHandlers(HTTPToHTTP1ServerCodec(), recorder)
|
||||||
|
|
||||||
try self.channel.writeInbound(HTTPRequestPart.head(Self.request))
|
try self.channel.writeInbound(HTTPRequestPart.head(Self.request))
|
||||||
try self.channel.writeInbound(HTTPRequestPart.end(Self.trailers))
|
try self.channel.writeInbound(HTTPRequestPart.end(Self.trailers))
|
||||||
|
@ -112,7 +112,7 @@ final class NIOHTTPTypesHTTP2Tests: XCTestCase {
|
|||||||
func testClientHTTP2ToHTTP() throws {
|
func testClientHTTP2ToHTTP() throws {
|
||||||
let recorder = InboundRecorder<HTTPResponsePart>()
|
let recorder = InboundRecorder<HTTPResponsePart>()
|
||||||
|
|
||||||
try self.channel.pipeline.addHandlers(HTTP2FramePayloadToHTTPClientCodec(), recorder).wait()
|
try self.channel.pipeline.syncOperations.addHandlers(HTTP2FramePayloadToHTTPClientCodec(), recorder)
|
||||||
|
|
||||||
try self.channel.writeOutbound(HTTPRequestPart.head(Self.request))
|
try self.channel.writeOutbound(HTTPRequestPart.head(Self.request))
|
||||||
try self.channel.writeOutbound(HTTPRequestPart.end(Self.trailers))
|
try self.channel.writeOutbound(HTTPRequestPart.end(Self.trailers))
|
||||||
@ -139,7 +139,7 @@ final class NIOHTTPTypesHTTP2Tests: XCTestCase {
|
|||||||
func testServerHTTP2ToHTTP() throws {
|
func testServerHTTP2ToHTTP() throws {
|
||||||
let recorder = InboundRecorder<HTTPRequestPart>()
|
let recorder = InboundRecorder<HTTPRequestPart>()
|
||||||
|
|
||||||
try self.channel.pipeline.addHandlers(HTTP2FramePayloadToHTTPServerCodec(), recorder).wait()
|
try self.channel.pipeline.syncOperations.addHandlers(HTTP2FramePayloadToHTTPServerCodec(), recorder)
|
||||||
|
|
||||||
try self.channel.writeInbound(HTTP2Frame.FramePayload(headers: Self.oldRequest))
|
try self.channel.writeInbound(HTTP2Frame.FramePayload(headers: Self.oldRequest))
|
||||||
try self.channel.writeInbound(HTTP2Frame.FramePayload(headers: Self.oldTrailers))
|
try self.channel.writeInbound(HTTP2Frame.FramePayload(headers: Self.oldTrailers))
|
||||||
|
@ -139,7 +139,7 @@ class SOCKSServerHandlerTests: XCTestCase {
|
|||||||
expectedRequest: expectedRequest,
|
expectedRequest: expectedRequest,
|
||||||
expectedData: expectedData
|
expectedData: expectedData
|
||||||
)
|
)
|
||||||
XCTAssertNoThrow(try self.channel.pipeline.addHandler(testHandler).wait())
|
XCTAssertNoThrow(try self.channel.pipeline.syncOperations.addHandler(testHandler))
|
||||||
|
|
||||||
// wait for the greeting
|
// wait for the greeting
|
||||||
XCTAssertFalse(testHandler.hadGreeting)
|
XCTAssertFalse(testHandler.hadGreeting)
|
||||||
@ -184,7 +184,7 @@ class SOCKSServerHandlerTests: XCTestCase {
|
|||||||
expectedRequest: expectedRequest,
|
expectedRequest: expectedRequest,
|
||||||
expectedData: expectedData
|
expectedData: expectedData
|
||||||
)
|
)
|
||||||
XCTAssertNoThrow(try self.channel.pipeline.addHandler(testHandler).wait())
|
XCTAssertNoThrow(try self.channel.pipeline.syncOperations.addHandler(testHandler))
|
||||||
|
|
||||||
// wait for the greeting
|
// wait for the greeting
|
||||||
XCTAssertFalse(testHandler.hadGreeting)
|
XCTAssertFalse(testHandler.hadGreeting)
|
||||||
|
@ -173,7 +173,7 @@ class SocksClientHandlerTests: XCTestCase {
|
|||||||
|
|
||||||
// server requests an auth method we don't support
|
// server requests an auth method we don't support
|
||||||
let promise = self.channel.eventLoop.makePromise(of: Void.self)
|
let promise = self.channel.eventLoop.makePromise(of: Void.self)
|
||||||
try! self.channel.pipeline.addHandler(ErrorHandler(promise: promise), position: .last).wait()
|
try! self.channel.pipeline.syncOperations.addHandler(ErrorHandler(promise: promise), position: .last)
|
||||||
self.writeInbound([0x05, 0x01])
|
self.writeInbound([0x05, 0x01])
|
||||||
XCTAssertThrowsError(try promise.futureResult.wait()) { e in
|
XCTAssertThrowsError(try promise.futureResult.wait()) { e in
|
||||||
XCTAssertTrue(e is SOCKSError.InvalidAuthenticationSelection)
|
XCTAssertTrue(e is SOCKSError.InvalidAuthenticationSelection)
|
||||||
@ -204,7 +204,7 @@ class SocksClientHandlerTests: XCTestCase {
|
|||||||
|
|
||||||
// server replies with an error
|
// server replies with an error
|
||||||
let promise = self.channel.eventLoop.makePromise(of: Void.self)
|
let promise = self.channel.eventLoop.makePromise(of: Void.self)
|
||||||
try! self.channel.pipeline.addHandler(ErrorHandler(promise: promise), position: .last).wait()
|
try! self.channel.pipeline.syncOperations.addHandler(ErrorHandler(promise: promise), position: .last)
|
||||||
self.writeInbound([0x05, 0x01, 0x00, 0x01, 192, 168, 1, 1, 0x00, 0x50])
|
self.writeInbound([0x05, 0x01, 0x00, 0x01, 192, 168, 1, 1, 0x00, 0x50])
|
||||||
XCTAssertThrowsError(try promise.futureResult.wait()) { e in
|
XCTAssertThrowsError(try promise.futureResult.wait()) { e in
|
||||||
XCTAssertEqual(e as? SOCKSError.ConnectionFailed, .init(reply: .serverFailure))
|
XCTAssertEqual(e as? SOCKSError.ConnectionFailed, .init(reply: .serverFailure))
|
||||||
@ -262,12 +262,12 @@ class SocksClientHandlerTests: XCTestCase {
|
|||||||
|
|
||||||
let establishPromise = self.channel.eventLoop.makePromise(of: Void.self)
|
let establishPromise = self.channel.eventLoop.makePromise(of: Void.self)
|
||||||
let removalPromise = self.channel.eventLoop.makePromise(of: Void.self)
|
let removalPromise = self.channel.eventLoop.makePromise(of: Void.self)
|
||||||
establishPromise.futureResult.whenSuccess { _ in
|
establishPromise.futureResult.assumeIsolated().whenSuccess { _ in
|
||||||
self.channel.pipeline.syncOperations.removeHandler(self.handler).cascade(to: removalPromise)
|
self.channel.pipeline.syncOperations.removeHandler(self.handler).cascade(to: removalPromise)
|
||||||
}
|
}
|
||||||
|
|
||||||
XCTAssertNoThrow(
|
XCTAssertNoThrow(
|
||||||
try self.channel.pipeline.addHandler(SOCKSEventHandler(establishedPromise: establishPromise)).wait()
|
try self.channel.pipeline.syncOperations.addHandler(SOCKSEventHandler(establishedPromise: establishPromise))
|
||||||
)
|
)
|
||||||
|
|
||||||
self.connect()
|
self.connect()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user