From 29b0dded74beec4cff7330a2ca3199b573aa5cb6 Mon Sep 17 00:00:00 2001 From: RudraniW Date: Tue, 8 Oct 2019 20:07:10 +0530 Subject: [PATCH] feat: Ability to limit request size and connection count (#221) --- Package.swift | 2 +- .../KituraNet/HTTP/HTTPRequestHandler.swift | 55 +++++++- Sources/KituraNet/HTTP/HTTPServer.swift | 16 ++- Sources/KituraNet/HTTP/ServerOptions.swift | 120 ++++++++++++++++++ Tests/KituraNetTests/ClientE2ETests.swift | 27 ++++ .../KituraNetTests/ConnectionLimitTests.swift | 93 ++++++++++++++ Tests/KituraNetTests/KituraNIOTest.swift | 28 ++-- .../KituraNetWebSocketUpgrade.swift | 10 +- 8 files changed, 328 insertions(+), 23 deletions(-) create mode 100644 Sources/KituraNet/HTTP/ServerOptions.swift create mode 100644 Tests/KituraNetTests/ConnectionLimitTests.swift diff --git a/Package.swift b/Package.swift index e39496a2..c6c8627f 100644 --- a/Package.swift +++ b/Package.swift @@ -42,7 +42,7 @@ let package = Package( dependencies: []), .target( name: "KituraNet", - dependencies: ["NIO", "NIOFoundationCompat", "NIOHTTP1", "NIOSSL", "SSLService", "LoggerAPI", "NIOWebSocket", "CLinuxHelpers", "NIOExtras"]), + dependencies: ["NIO", "NIOFoundationCompat", "NIOHTTP1", "NIOSSL", "SSLService", "LoggerAPI", "NIOWebSocket", "CLinuxHelpers", "NIOConcurrencyHelpers", "NIOExtras"]), .testTarget( name: "KituraNetTests", dependencies: ["KituraNet"]) diff --git a/Sources/KituraNet/HTTP/HTTPRequestHandler.swift b/Sources/KituraNet/HTTP/HTTPRequestHandler.swift index b1317840..42b71683 100644 --- a/Sources/KituraNet/HTTP/HTTPRequestHandler.swift +++ b/Sources/KituraNet/HTTP/HTTPRequestHandler.swift @@ -26,6 +26,8 @@ internal class HTTPRequestHandler: ChannelInboundHandler, RemovableChannelHandle /// The HTTPServer instance on which this handler is installed var server: HTTPServer + var requestSize: Int = 0 + /// The serverRequest related to this handler instance var serverRequest: HTTPServerRequest? @@ -66,7 +68,6 @@ internal class HTTPRequestHandler: ChannelInboundHandler, RemovableChannelHandle self.enableSSLVerification = true } } - public typealias InboundIn = HTTPServerRequestPart public typealias OutboundOut = HTTPServerResponsePart @@ -76,12 +77,42 @@ internal class HTTPRequestHandler: ChannelInboundHandler, RemovableChannelHandle // If an upgrade to WebSocket fails, both `errorCaught` and `channelRead` are triggered. // We'd want to return the error via `errorCaught`. if errorResponseSent { return } - switch request { case .head(let header): + serverRequest = HTTPServerRequest(channel: context.channel, requestHead: header, enableSSL: enableSSLVerification) + if let requestSizeLimit = server.options.requestSizeLimit, + let contentLength = header.headers["Content-Length"].first, + let contentLengthValue = Int(contentLength) { + if contentLengthValue > requestSizeLimit { + do { + if let (httpStatus, response) = server.options.requestSizeResponseGenerator(requestSizeLimit, serverRequest?.remoteAddress ?? "") { + serverResponse = HTTPServerResponse(channel: context.channel, handler: self) + errorResponseSent = true + try serverResponse?.end(with: httpStatus, message: response) + } + } catch { + Log.error("Failed to send error response") + } + context.close() + } + } serverRequest = HTTPServerRequest(channel: context.channel, requestHead: header, enableSSL: enableSSLVerification) self.clientRequestedKeepAlive = header.isKeepAlive case .body(var buffer): + requestSize += buffer.readableBytes + if let requestSizeLimit = server.options.requestSizeLimit { + if requestSize > requestSizeLimit { + do { + if let (httpStatus, response) = server.options.requestSizeResponseGenerator(requestSizeLimit,serverRequest?.remoteAddress ?? "") { + serverResponse = HTTPServerResponse(channel: context.channel, handler: self) + errorResponseSent = true + try serverResponse?.end(with: httpStatus, message: response) + } + } catch { + Log.error("Failed to send error response") + } + } + } guard let serverRequest = serverRequest else { Log.error("No ServerRequest available") return @@ -91,7 +122,23 @@ internal class HTTPRequestHandler: ChannelInboundHandler, RemovableChannelHandle } else { serverRequest.buffer!.byteBuffer.writeBuffer(&buffer) } + case .end: + requestSize = 0 + server.connectionCount.add(1) + if let connectionLimit = server.options.connectionLimit { + if server.connectionCount.load() > connectionLimit { + do { + if let (httpStatus, response) = server.options.connectionResponseGenerator(connectionLimit,serverRequest?.remoteAddress ?? "") { + serverResponse = HTTPServerResponse(channel: context.channel, handler: self) + errorResponseSent = true + try serverResponse?.end(with: httpStatus, message: response) + } + } catch { + Log.error("Failed to send error response") + } + } + } serverResponse = HTTPServerResponse(channel: context.channel, handler: self) //Make sure we use the latest delegate registered with the server DispatchQueue.global().async { @@ -152,4 +199,8 @@ internal class HTTPRequestHandler: ChannelInboundHandler, RemovableChannelHandle func updateKeepAliveState() { keepAliveState.decrement() } + + func channelInactive(context: ChannelHandlerContext, httpServer: HTTPServer) { + httpServer.connectionCount.sub(1) + } } diff --git a/Sources/KituraNet/HTTP/HTTPServer.swift b/Sources/KituraNet/HTTP/HTTPServer.swift index b919b96a..a50840ef 100644 --- a/Sources/KituraNet/HTTP/HTTPServer.swift +++ b/Sources/KituraNet/HTTP/HTTPServer.swift @@ -22,7 +22,9 @@ import SSLService import LoggerAPI import NIOWebSocket import CLinuxHelpers +import Foundation import NIOExtras +import NIOConcurrencyHelpers #if os(Linux) import Glibc @@ -127,22 +129,30 @@ public class HTTPServer: Server { var quiescingHelper: ServerQuiescingHelper? + /// server configuration + public var options: ServerOptions = ServerOptions() + + //counter for no of connections + var connectionCount = Atomic(value: 0) + /** Creates an HTTP server object. ### Usage Example: ### ````swift - let server = HTTPServer() + let config =HTTPServerConfiguration(requestSize: 1000, coonectionLimit: 100) + let server = HTTPServer(serverconfig: config) server.listen(on: 8080) ```` */ - public init() { + public init(options: ServerOptions = ServerOptions()) { #if os(Linux) let numberOfCores = Int(linux_sched_getaffinity()) self.eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: numberOfCores > 0 ? numberOfCores : System.coreCount) #else self.eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount) #endif + self.options = options } /** @@ -309,7 +319,7 @@ public class HTTPServer: Server { } .childChannelInitializer { channel in let httpHandler = HTTPRequestHandler(for: self) - let config: NIOHTTPServerUpgradeConfiguration = (upgraders: upgraders, completionHandler: { _ in + let config: HTTPUpgradeConfiguration = (upgraders: upgraders, completionHandler: {_ in _ = channel.pipeline.removeHandler(httpHandler) }) return channel.pipeline.configureHTTPServerPipeline(withServerUpgrade: config, withErrorHandling: true).flatMap { diff --git a/Sources/KituraNet/HTTP/ServerOptions.swift b/Sources/KituraNet/HTTP/ServerOptions.swift new file mode 100644 index 00000000..33a645d2 --- /dev/null +++ b/Sources/KituraNet/HTTP/ServerOptions.swift @@ -0,0 +1,120 @@ +/* + * Copyright IBM Corporation 2019 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import Foundation +import LoggerAPI + +/** + ServerOptions allows customization of default server policies, including: + + - `requestSizeLimit`: Defines the maximum size for the body of an incoming request, in bytes. If a request body is larger than this limit, it will be rejected and the connection will be closed. A value of `nil` means no limit. + - `connectionLimit`: Defines the maximum number of concurrent connections that a server should accept. Clients attempting to connect when this limit has been reached will be rejected. A value of `nil` means no limit. + + The server can optionally respond to the client with a message in either of these cases. This message can be customized by defining `requestSizeResponseGenerator` and `connectionResponseGenerator`. + + Example usage: + ``` + let server = HTTP.createServer() + server.options = ServerOptions(requestSizeLimit: 1000, connectionLimit: 10) + ``` + */ +public struct ServerOptions { + + /// A default limit of 100mb on the size of the request body that a server should accept. + public static let defaultRequestSizeLimit = 104857600 + + /// A default limit of 10,000 on the number of concurrent connections that a server should accept. + public static let defaultConnectionLimit = 10000 + + /// Defines a default response to an over-sized request of HTTP 413: Request Too Long. A message is also + /// logged at debug level. + public static let defaultRequestSizeResponseGenerator: (Int, String) -> (HTTPStatusCode, String)? = { (limit, clientSource) in + Log.debug("Request from \(clientSource) exceeds size limit of \(limit) bytes. Connection will be closed.") + return (.requestTooLong, "") + } + + /// Defines a default response when refusing a new connection of HTTP 503: Service Unavailable. A message is + /// also logged at debug level. + public static let defaultConnectionResponseGenerator: (Int, String) -> (HTTPStatusCode, String)? = { (limit, clientSource) in + Log.debug("Rejected connection from \(clientSource): Maximum connection limit of \(limit) reached.") + return (.serviceUnavailable, "") + } + + /// Defines the maximum size for the body of an incoming request, in bytes. If a request body is larger + /// than this limit, it will be rejected and the connection will be closed. + /// + /// A value of `nil` means no limit. + public let requestSizeLimit: Int? + + /// Defines the maximum number of concurrent connections that a server should accept. Clients attempting + /// to connect when this limit has been reached will be rejected. + public let connectionLimit: Int? + + /** + Determines the response message and HTTP status code used to respond to clients whose request exceeds + the `requestSizeLimit`. The current limit and client's address are provided as parameters to enable a + message to be logged, and/or a response to be provided back to the client. + + The returned tuple indicates the HTTP status code and response body to send to the client. If `nil` is + returned, then no response will be sent. + + Example usage: + ``` + let oversizeResponse: (Int, String) -> (HTTPStatusCode, String)? = { (limit, client) in + Log.debug("Rejecting request from \(client): Exceeds limit of \(limit) bytes") + return (.requestTooLong, "Your request exceeds the limit of \(limit) bytes.\r\n") + } + ``` + */ + public let requestSizeResponseGenerator: (Int, String) -> (HTTPStatusCode, String)? + + /** + Determines the response message and HTTP status code used to respond to clients that attempt to connect + while the server is already servicing the maximum number of connections, as defined by `connectionLimit`. + The current limit and client's address are provided as parameters to enable a message to be logged, + and/or a response to be provided back to the client. + + The returned tuple indicates the HTTP status code and response body to send to the client. If `nil` is + returned, then no response will be sent. + + Example usage: + ``` + let connectionResponse: (Int, String) -> (HTTPStatusCode, String)? = { (limit, client) in + Log.debug("Rejecting request from \(client): Connection limit \(limit) reached") + return (.serviceUnavailable, "Service busy - please try again later.\r\n") + } + ``` + */ + public let connectionResponseGenerator: (Int, String) -> (HTTPStatusCode, String)? + + /// Create a `ServerOptions` to determine the behaviour of a `Server`. + /// + /// - parameter requestSizeLimit: The maximum size of an incoming request body. Defaults to `ServerOptions.defaultRequestSizeLimit`. + /// - parameter connectionLimit: The maximum number of concurrent connections. Defaults to `ServerOptions.defaultConnectionLimit`. + /// - parameter requestSizeResponseGenerator: A closure producing a response to send to a client when an over-sized request is rejected. Defaults to `ServerOptions.defaultRequestSizeResponseGenerator`. + /// - parameter defaultConnectionResponseGenerator: A closure producing a response to send to a client when a the server is busy and new connections are not being accepted. Defaults to `ServerOptions.defaultConnectionResponseGenerator`. + public init(requestSizeLimit: Int? = ServerOptions.defaultRequestSizeLimit, + connectionLimit: Int? = ServerOptions.defaultConnectionLimit, + requestSizeResponseGenerator: @escaping (Int, String) -> (HTTPStatusCode, String)? = ServerOptions.defaultRequestSizeResponseGenerator, + connectionResponseGenerator: @escaping (Int, String) -> (HTTPStatusCode, String)? = ServerOptions.defaultConnectionResponseGenerator) + { + self.requestSizeLimit = requestSizeLimit + self.connectionLimit = connectionLimit + self.requestSizeResponseGenerator = requestSizeResponseGenerator + self.connectionResponseGenerator = connectionResponseGenerator + } + +} diff --git a/Tests/KituraNetTests/ClientE2ETests.swift b/Tests/KituraNetTests/ClientE2ETests.swift index 87800b6e..8c721124 100644 --- a/Tests/KituraNetTests/ClientE2ETests.swift +++ b/Tests/KituraNetTests/ClientE2ETests.swift @@ -37,6 +37,7 @@ class ClientE2ETests: KituraNetTest { ("testQueryParameters", testQueryParameters), ("testRedirect", testRedirect), ("testPercentEncodedQuery", testPercentEncodedQuery), + ("testRequestSize",testRequestSize), ] } @@ -52,6 +53,32 @@ class ClientE2ETests: KituraNetTest { let delegate = TestServerDelegate() + func testRequestSize() { + performServerTest(serverConfig: ServerOptions(requestSizeLimit: 10000, connectionLimit: 100),delegate, useSSL: false, asyncTasks: { expectation in + let payload = "[" + contentTypesString + "," + contentTypesString + contentTypesString + "," + contentTypesString + "]" + self.performRequest("post", path: "/largepost", callback: {response in + XCTAssertEqual(response?.statusCode, HTTPStatusCode.requestTooLong) + do { + let expectedResult = "" + var data = Data() + let count = try response?.readAllData(into: &data) + XCTAssertEqual(count, expectedResult.count, "Result should have been \(expectedResult.count) bytes, was \(String(describing: count)) bytes") + let postValue = String(data: data, encoding: .utf8) + if let postValue = postValue { + XCTAssertEqual(postValue, expectedResult) + } else { + XCTFail("postValue's value wasn't an UTF8 string") + } + } catch { + XCTFail("Failed reading the body of the response") + } + expectation.fulfill() + }) {request in + request.write(from: payload) + } + }) + } + func testHeadRequests() { performServerTest(delegate) { expectation in self.performRequest("head", path: "/headtest", callback: {response in diff --git a/Tests/KituraNetTests/ConnectionLimitTests.swift b/Tests/KituraNetTests/ConnectionLimitTests.swift new file mode 100644 index 00000000..5ca68b93 --- /dev/null +++ b/Tests/KituraNetTests/ConnectionLimitTests.swift @@ -0,0 +1,93 @@ +import Foundation +import Dispatch +import NIO +import XCTest +import KituraNet +import NIOHTTP1 +import NIOWebSocket +import LoggerAPI + +class ConnectionLimitTests: KituraNetTest { + static var allTests: [(String, (ConnectionLimitTests) -> () throws -> Void)] { + return [ + ("testConnectionLimit", testConnectionLimit), + ] + } + + override func setUp() { + doSetUp() + } + + override func tearDown() { + doTearDown() + } + private func sendRequest(request: HTTPRequestHead, on channel: Channel) { + channel.write(NIOAny(HTTPClientRequestPart.head(request)), promise: nil) + try! channel.writeAndFlush(NIOAny(HTTPClientRequestPart.end(nil))).wait() + } + + func establishConnection(expectation: XCTestExpectation, responseHandler: HTTPResponseHandler) { + var channel: Channel + let group = MultiThreadedEventLoopGroup(numberOfThreads: 1) + let bootstrap = ClientBootstrap(group: group) + .channelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: 1) + .channelInitializer { channel in + channel.pipeline.addHTTPClientHandlers().flatMap {_ in + channel.pipeline.addHandler(responseHandler) + } + } + do { + try channel = bootstrap.connect(host: "localhost", port: self.port).wait() + let request = HTTPRequestHead(version: HTTPVersion(major: 1, minor: 1), method: .GET, uri: "/") + self.sendRequest(request: request, on: channel) + } catch _ { + XCTFail("Connection is not established.") + } + } + + func testConnectionLimit() { + let delegate = TestConnectionLimitDelegate() + performServerTest(serverConfig: ServerOptions(requestSizeLimit: 10000, connectionLimit: 1), delegate, socketType: .tcp, useSSL: false, asyncTasks: { expectation in + let payload = "Hello, World!" + var payloadBuffer = ByteBufferAllocator().buffer(capacity: 1024) + payloadBuffer.writeString(payload) + _ = self.establishConnection(expectation: expectation, responseHandler: HTTPResponseHandler(expectedStatus:HTTPResponseStatus.ok, expectation: expectation)) + }, { expectation in + let payload = "Hello, World!" + var payloadBuffer = ByteBufferAllocator().buffer(capacity: 1024) + payloadBuffer.writeString(payload) + _ = self.establishConnection(expectation: expectation, responseHandler: HTTPResponseHandler(expectedStatus:HTTPResponseStatus.serviceUnavailable, expectation: expectation)) + }) + } +} + +class TestConnectionLimitDelegate: ServerDelegate { + func handle(request: ServerRequest, response: ServerResponse) { + do { + try response.end() + } catch { + XCTFail("Error while writing response") + } + } +} + +class HTTPResponseHandler: ChannelInboundHandler { + let expectedStatus: HTTPResponseStatus + let expectation: XCTestExpectation + init(expectedStatus: HTTPResponseStatus, expectation: XCTestExpectation) { + self.expectedStatus = expectedStatus + self.expectation = expectation + } + typealias InboundIn = HTTPClientResponsePart + public func channelRead(context: ChannelHandlerContext, data: NIOAny) { + let response = self.unwrapInboundIn(data) + switch response { + case .head(let header): + let status = header.status + XCTAssertEqual(status, expectedStatus) + expectation.fulfill() + default: do { + } + } + } +} diff --git a/Tests/KituraNetTests/KituraNIOTest.swift b/Tests/KituraNetTests/KituraNIOTest.swift index 542935ea..6fbc6666 100644 --- a/Tests/KituraNetTests/KituraNIOTest.swift +++ b/Tests/KituraNetTests/KituraNIOTest.swift @@ -85,9 +85,10 @@ class KituraNetTest: XCTestCase { } } - func startServer(_ delegate: ServerDelegate?, unixDomainSocketPath: String? = nil, port: Int = portDefault, useSSL: Bool = useSSLDefault, allowPortReuse: Bool = portReuseDefault) throws -> HTTPServer { - + func startServer(_ delegate: ServerDelegate?, unixDomainSocketPath: String? = nil, port: Int = portDefault, useSSL: Bool = useSSLDefault, allowPortReuse: Bool = portReuseDefault, serverConfig: ServerOptions = ServerOptions()) throws -> HTTPServer { + let serverConfig = serverConfig let server = HTTP.createServer() + server.options = serverConfig server.delegate = delegate if useSSL { server.sslConfig = KituraNetTest.sslConfig @@ -103,8 +104,9 @@ class KituraNetTest: XCTestCase { /// Convenience function for starting an HTTPServer on an ephemeral port, /// returning the a tuple containing the server and the port it is listening on. - func startEphemeralServer(_ delegate: ServerDelegate?, useSSL: Bool = useSSLDefault, allowPortReuse: Bool = portReuseDefault) throws -> (server: HTTPServer, port: Int) { - let server = try startServer(delegate, port: 0, useSSL: useSSL, allowPortReuse: allowPortReuse) + func startEphemeralServer(_ delegate: ServerDelegate?, useSSL: Bool = useSSLDefault, allowPortReuse: Bool = portReuseDefault, serverConfig: ServerOptions = ServerOptions()) throws -> (server: HTTPServer, port: Int) { + let serverConfig = serverConfig + let server = try startServer(delegate, port: 0, useSSL: useSSL,allowPortReuse: allowPortReuse, serverConfig: serverConfig) guard let serverPort = server.port else { throw KituraNetTestError(message: "Server port was not initialized") } @@ -121,22 +123,24 @@ class KituraNetTest: XCTestCase { case both } - func performServerTest(_ delegate: ServerDelegate?, socketType: SocketType = .both, useSSL: Bool = useSSLDefault, allowPortReuse: Bool = portReuseDefault, line: Int = #line, asyncTasks: (XCTestExpectation) -> Void...) { + func performServerTest(serverConfig: ServerOptions = ServerOptions(), _ delegate: ServerDelegate?, socketType: SocketType = .both, useSSL: Bool = useSSLDefault, allowPortReuse: Bool = portReuseDefault, line: Int = #line, asyncTasks: (XCTestExpectation) -> Void...) { + let serverConfig = serverConfig self.socketType = socketType if socketType != .tcp { - performServerTestWithUnixSocket(delegate: delegate, useSSL: useSSL, allowPortReuse: allowPortReuse, line: line, asyncTasks: asyncTasks) + performServerTestWithUnixSocket(serverConfig: serverConfig, delegate: delegate, useSSL: useSSL, allowPortReuse: allowPortReuse, line: line, asyncTasks: asyncTasks) } if socketType != .unixDomainSocket { - performServerTestWithTCPPort(delegate: delegate, useSSL: useSSL, allowPortReuse: allowPortReuse, line: line, asyncTasks: asyncTasks) + performServerTestWithTCPPort(serverConfig: serverConfig ,delegate: delegate, useSSL: useSSL, allowPortReuse: allowPortReuse, line: line, asyncTasks: asyncTasks) } } - func performServerTestWithUnixSocket(delegate: ServerDelegate?, useSSL: Bool = useSSLDefault, allowPortReuse: Bool = portReuseDefault, line: Int = #line, asyncTasks: [(XCTestExpectation) -> Void]) { + func performServerTestWithUnixSocket(serverConfig: ServerOptions = ServerOptions(), delegate: ServerDelegate?, useSSL: Bool = useSSLDefault, allowPortReuse: Bool = portReuseDefault, line: Int = #line, asyncTasks: [(XCTestExpectation) -> Void]) { do { + var serverConfig = serverConfig var server: HTTPServer self.useSSL = useSSL self.unixDomainSocketPath = self.socketFilePath - server = try startServer(delegate, unixDomainSocketPath: self.unixDomainSocketPath, useSSL: useSSL, allowPortReuse: allowPortReuse) + server = try startServer(delegate, unixDomainSocketPath: self.unixDomainSocketPath, useSSL: useSSL, allowPortReuse: allowPortReuse, serverConfig: serverConfig) defer { server.stop() } @@ -158,18 +162,18 @@ class KituraNetTest: XCTestCase { } } - func performServerTestWithTCPPort(delegate: ServerDelegate?, useSSL: Bool = useSSLDefault, allowPortReuse: Bool = portReuseDefault, line: Int = #line, asyncTasks: [(XCTestExpectation) -> Void]) { + func performServerTestWithTCPPort(serverConfig: ServerOptions = ServerOptions(), delegate: ServerDelegate?, useSSL: Bool = useSSLDefault, allowPortReuse: Bool = portReuseDefault, line: Int = #line, asyncTasks: [(XCTestExpectation) -> Void]) { do { + var serverConfig = serverConfig var server: HTTPServer var ephemeralPort: Int = 0 self.useSSL = useSSL - (server, ephemeralPort) = try startEphemeralServer(delegate, useSSL: useSSL, allowPortReuse: allowPortReuse) + (server, ephemeralPort) = try startEphemeralServer(delegate, useSSL: useSSL, allowPortReuse: allowPortReuse,serverConfig: serverConfig) self.port = ephemeralPort self.unixDomainSocketPath = nil defer { server.stop() } - let requestQueue = DispatchQueue(label: "Request queue") for (index, asyncTask) in asyncTasks.enumerated() { let expectation = self.expectation(line: line, index: index) diff --git a/Tests/KituraNetTests/KituraNetWebSocketUpgrade.swift b/Tests/KituraNetTests/KituraNetWebSocketUpgrade.swift index 882fb657..4c146e5f 100644 --- a/Tests/KituraNetTests/KituraNetWebSocketUpgrade.swift +++ b/Tests/KituraNetTests/KituraNetWebSocketUpgrade.swift @@ -31,7 +31,7 @@ class KituraNetWebSocketUpgradeTest: KituraNetTest { ] } - var httpHandler: HTTPResponseHandler? + var httpHandler: HttpResponseHandler? func clientChannelInitializer(channel: Channel) -> EventLoopFuture { var httpRequestEncoder: HTTPRequestEncoder @@ -83,12 +83,12 @@ class KituraNetWebSocketUpgradeTest: KituraNetTest { } func sendUpgradeRequest(toPath: String, usingKey: String, wsVersion: String, semaphore: DispatchSemaphore, errorMessage: String? = nil) { - - self.httpHandler = HTTPResponseHandler(key: usingKey,semaphore: semaphore) + + self.httpHandler = HttpResponseHandler(key: usingKey,semaphore: semaphore) let clientBootstrap = ClientBootstrap(group: MultiThreadedEventLoopGroup(numberOfThreads: 1)) .channelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEPORT), value: 1) .channelInitializer(clientChannelInitializer) - + do { let channel = try clientBootstrap.connect(host: "localhost", port: self.port).wait() var request = HTTPRequestHead(version: HTTPVersion(major: 1, minor: 1), method: HTTPMethod(rawValue: "GET"), uri: toPath) @@ -106,7 +106,7 @@ class KituraNetWebSocketUpgradeTest: KituraNetTest { } } -class HTTPResponseHandler: ChannelInboundHandler { +class HttpResponseHandler: ChannelInboundHandler { public typealias InboundIn = HTTPClientResponsePart public var responseStatus : HTTPResponseStatus