Skip to content

Commit 47c7a7b

Browse files
committed
Extract HTTPBinForUncleanShutdown
1 parent 170fd53 commit 47c7a7b

File tree

2 files changed

+131
-97
lines changed

2 files changed

+131
-97
lines changed

Diff for: Tests/AsyncHTTPClientTests/HTTPClientTestUtils.swift

-97
Original file line numberDiff line numberDiff line change
@@ -931,103 +931,6 @@ final class ConnectionsCountHandler: ChannelInboundHandler {
931931
}
932932
}
933933

934-
internal class HttpBinForSSLUncleanShutdown {
935-
let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
936-
let serverChannel: Channel
937-
938-
var port: Int {
939-
return Int(self.serverChannel.localAddress!.port!)
940-
}
941-
942-
init(channelPromise: EventLoopPromise<Channel>? = nil) {
943-
self.serverChannel = try! ServerBootstrap(group: self.group)
944-
.serverChannelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: 1)
945-
.childChannelOption(ChannelOptions.socket(IPPROTO_TCP, TCP_NODELAY), value: 1)
946-
.childChannelInitializer { channel in
947-
let requestDecoder = HTTPRequestDecoder()
948-
return channel.pipeline.addHandler(ByteToMessageHandler(requestDecoder)).flatMap {
949-
let configuration = TLSConfiguration.makeServerConfiguration(certificateChain: [.certificate(try! NIOSSLCertificate(bytes: Array(cert.utf8), format: .pem))],
950-
privateKey: .privateKey(try! NIOSSLPrivateKey(bytes: Array(key.utf8), format: .pem)))
951-
let context = try! NIOSSLContext(configuration: configuration)
952-
return channel.pipeline.addHandler(NIOSSLServerHandler(context: context), name: "NIOSSLServerHandler", position: .first).flatMap {
953-
channel.pipeline.addHandler(HttpBinForSSLUncleanShutdownHandler(channelPromise: channelPromise))
954-
}
955-
}
956-
}.bind(host: "127.0.0.1", port: 0).wait()
957-
}
958-
959-
func shutdown() {
960-
try! self.group.syncShutdownGracefully()
961-
}
962-
}
963-
964-
internal final class HttpBinForSSLUncleanShutdownHandler: ChannelInboundHandler {
965-
typealias InboundIn = HTTPServerRequestPart
966-
typealias OutboundOut = ByteBuffer
967-
968-
let channelPromise: EventLoopPromise<Channel>?
969-
970-
init(channelPromise: EventLoopPromise<Channel>? = nil) {
971-
self.channelPromise = channelPromise
972-
}
973-
974-
func channelRead(context: ChannelHandlerContext, data: NIOAny) {
975-
switch self.unwrapInboundIn(data) {
976-
case .head(let req):
977-
self.channelPromise?.succeed(context.channel)
978-
979-
let response: String?
980-
switch req.uri {
981-
case "/nocontentlength":
982-
response = """
983-
HTTP/1.1 200 OK\r\n\
984-
Connection: close\r\n\
985-
\r\n\
986-
foo
987-
"""
988-
case "/nocontent":
989-
response = """
990-
HTTP/1.1 204 OK\r\n\
991-
Connection: close\r\n\
992-
\r\n
993-
"""
994-
case "/noresponse":
995-
response = nil
996-
case "/wrongcontentlength":
997-
response = """
998-
HTTP/1.1 200 OK\r\n\
999-
Connection: close\r\n\
1000-
Content-Length: 6\r\n\
1001-
\r\n\
1002-
foo
1003-
"""
1004-
default:
1005-
response = """
1006-
HTTP/1.1 404 OK\r\n\
1007-
Connection: close\r\n\
1008-
Content-Length: 9\r\n\
1009-
\r\n\
1010-
Not Found
1011-
"""
1012-
}
1013-
1014-
if let response = response {
1015-
var buffer = context.channel.allocator.buffer(capacity: response.count)
1016-
buffer.writeString(response)
1017-
context.writeAndFlush(self.wrapOutboundOut(buffer), promise: nil)
1018-
}
1019-
1020-
context.channel.pipeline.removeHandler(name: "NIOSSLServerHandler").whenSuccess {
1021-
context.close(promise: nil)
1022-
}
1023-
case .body:
1024-
()
1025-
case .end:
1026-
()
1027-
}
1028-
}
1029-
}
1030-
1031934
internal final class CloseWithoutClosingServerHandler: ChannelInboundHandler {
1032935
typealias InboundIn = HTTPServerRequestPart
1033936
typealias OutboundOut = HTTPServerResponsePart
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the AsyncHTTPClient open source project
4+
//
5+
// Copyright (c) 2021 Apple Inc. and the AsyncHTTPClient project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of AsyncHTTPClient project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
import AsyncHTTPClient
16+
import Logging
17+
import XCTest
18+
import NIOSSL
19+
import NIOCore
20+
import NIOPosix
21+
import NIOHTTP1
22+
23+
final class HTTPClientUncleanShutdownTests: XCTestCase {
24+
25+
}
26+
27+
final class HttpBinForSSLUncleanShutdown {
28+
let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
29+
let serverChannel: Channel
30+
31+
var port: Int {
32+
return Int(self.serverChannel.localAddress!.port!)
33+
}
34+
35+
init(channelPromise: EventLoopPromise<Channel>? = nil) {
36+
37+
let configuration = TLSConfiguration.makeServerConfiguration(
38+
certificateChain: [.certificate(TestTLS.certificate)],
39+
privateKey: .privateKey(TestTLS.privateKey)
40+
)
41+
let context = try! NIOSSLContext(configuration: configuration)
42+
43+
self.serverChannel = try! ServerBootstrap(group: self.group)
44+
.serverChannelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: 1)
45+
.childChannelOption(ChannelOptions.socket(IPPROTO_TCP, TCP_NODELAY), value: 1)
46+
.childChannelInitializer { channel in
47+
do {
48+
let requestDecoder = HTTPRequestDecoder()
49+
let sync = channel.pipeline.syncOperations
50+
51+
try sync.addHandler(NIOSSLServerHandler(context: context))
52+
try sync.addHandler(ByteToMessageHandler(requestDecoder))
53+
try sync.addHandler(HttpBinForSSLUncleanShutdownHandler(channelPromise: channelPromise))
54+
return channel.eventLoop.makeSucceededVoidFuture()
55+
} catch {
56+
return channel.eventLoop.makeFailedFuture(error)
57+
}
58+
}.bind(host: "127.0.0.1", port: 0).wait()
59+
}
60+
61+
func shutdown() {
62+
try! self.group.syncShutdownGracefully()
63+
}
64+
}
65+
66+
final class HttpBinForSSLUncleanShutdownHandler: ChannelInboundHandler {
67+
typealias InboundIn = HTTPServerRequestPart
68+
typealias OutboundOut = ByteBuffer
69+
70+
let channelPromise: EventLoopPromise<Channel>?
71+
72+
init(channelPromise: EventLoopPromise<Channel>? = nil) {
73+
self.channelPromise = channelPromise
74+
}
75+
76+
func channelRead(context: ChannelHandlerContext, data: NIOAny) {
77+
switch self.unwrapInboundIn(data) {
78+
case .head(let req):
79+
self.channelPromise?.succeed(context.channel)
80+
81+
let response: String?
82+
switch req.uri {
83+
case "/nocontentlength":
84+
response = """
85+
HTTP/1.1 200 OK\r\n\
86+
Connection: close\r\n\
87+
\r\n\
88+
foo
89+
"""
90+
case "/nocontent":
91+
response = """
92+
HTTP/1.1 204 OK\r\n\
93+
Connection: close\r\n\
94+
\r\n
95+
"""
96+
case "/noresponse":
97+
response = nil
98+
case "/wrongcontentlength":
99+
response = """
100+
HTTP/1.1 200 OK\r\n\
101+
Connection: close\r\n\
102+
Content-Length: 6\r\n\
103+
\r\n\
104+
foo
105+
"""
106+
default:
107+
response = """
108+
HTTP/1.1 404 OK\r\n\
109+
Connection: close\r\n\
110+
Content-Length: 9\r\n\
111+
\r\n\
112+
Not Found
113+
"""
114+
}
115+
116+
if let response = response {
117+
var buffer = context.channel.allocator.buffer(capacity: response.count)
118+
buffer.writeString(response)
119+
context.writeAndFlush(self.wrapOutboundOut(buffer), promise: nil)
120+
}
121+
122+
context.channel.pipeline.removeHandler(name: "NIOSSLServerHandler").whenSuccess {
123+
context.close(promise: nil)
124+
}
125+
case .body:
126+
()
127+
case .end:
128+
()
129+
}
130+
}
131+
}

0 commit comments

Comments
 (0)