Skip to content

Commit c172d4f

Browse files
committed
Fixed HTTPServer read
1 parent 6eb1666 commit c172d4f

File tree

2 files changed

+81
-18
lines changed

2 files changed

+81
-18
lines changed

Sources/HTTP/Server.swift

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public final class HTTPServer {
1616

1717
internal let response: (IPAddress, HTTPRequest) async -> (HTTPResponse)
1818

19-
internal let log: (String) -> ()
19+
internal let log: ((String) -> ())?
2020

2121
internal let socket: Socket
2222

@@ -35,19 +35,19 @@ public final class HTTPServer {
3535
log: ((String) -> ())? = nil,
3636
response: ((IPAddress, HTTPRequest) async -> HTTPResponse)? = nil
3737
) async throws {
38+
#if DEBUG
3839
let log = log ?? {
39-
#if DEBUG
40-
print("HTTPServer: \($0)")
41-
#endif
40+
NSLog("HTTPServer: \($0)")
4241
}
42+
#endif
4343
self.configuration = configuration
44+
self.log = log
4445
self.response = response ?? { (address, request) in
4546
#if DEBUG
4647
log("[\(address)] \(request.method) \(request.uri)")
4748
#endif
4849
return .init(code: .ok)
4950
}
50-
self.log = log
5151
// create listening socket
5252
self.socket = try await Socket(.tcp, bind: IPv4SocketAddress(address: .any, port: configuration.port))
5353
try socket.fileDescriptor.listen(backlog: configuration.backlog)
@@ -61,24 +61,23 @@ public final class HTTPServer {
6161
assert(task == nil)
6262
// listening run loop
6363
self.task = Task.detached(priority: .high) { [weak self] in
64-
self?.log("Started HTTP Server")
64+
self?.log?("Started HTTP Server")
6565
do {
6666
while let socket = self?.socket {
6767
// wait for incoming sockets
6868
let newSocket = try await Socket(fileDescriptor: socket.fileDescriptor.accept())
6969
// read remote address
7070
let address = try newSocket.fileDescriptor.peerAddress(IPv4SocketAddress.self).address // TODO: Support IPv6
7171
if let self = self {
72-
// create connection actor
72+
self.log?("[\(address)] New connection")
7373
let connection = await Connection(address: .v4(address), socket: newSocket, server: self)
7474
await self.storage.newConnection(connection)
75-
self.log("[\(address)] New connection")
7675
}
7776
}
7877
}
7978
catch _ as CancellationError { }
8079
catch {
81-
self?.log("Error waiting for new connection: \(error)")
80+
self?.log?("Error waiting for new connection: \(error)")
8281
}
8382
}
8483
}
@@ -89,7 +88,7 @@ public final class HTTPServer {
8988
let storage = self.storage
9089
self.task?.cancel()
9190
self.task = nil
92-
self.log("Stopped GATT Server")
91+
self.log?("Stopped GATT Server")
9392
Task {
9493
await storage.removeAllConnections()
9594
await socket.close()
@@ -103,7 +102,7 @@ internal extension HTTPServer {
103102
// remove connection cache
104103
await storage.removeConnection(address)
105104
// log
106-
log("[\(address)]: " + "Did disconnect. \(error?.localizedDescription ?? "")")
105+
log?("[\(address)]: " + "Did disconnect. \(error?.localizedDescription ?? "")")
107106
}
108107
}
109108

@@ -125,7 +124,7 @@ public extension HTTPServer {
125124
port: UInt16 = 8080,
126125
backlog: Int = 10_000,
127126
headerMaxSize: Int = 4096,
128-
bodyMaxSize: Int = 1024 * 1024 * 5
127+
bodyMaxSize: Int = 1024 * 1024 * 10
129128
) {
130129
self.port = port
131130
self.backlog = backlog
@@ -223,14 +222,22 @@ internal extension HTTPServer {
223222
}
224223

225224
private func read(_ length: Int) async throws {
226-
let data = try await socket.read(length)
227-
self.server.log("[\(address)] Read \(data.count) bytes")
228-
self.readData.append(data)
225+
let chunkSize = 536 // The default TCP Maximum Segment Size is 536
226+
var readLength = 0
227+
var readMore = true
228+
while readMore {
229+
let chunk = try await socket.read(chunkSize)
230+
readLength += chunk.count
231+
self.readData.append(chunk)
232+
readMore = readLength < length && chunk.count == chunkSize // need more data and read max
233+
}
234+
self.server.log?("[\(address)] Read \(readLength) bytes")
229235
}
230236

231237
private func respond(_ response: HTTPResponse) async throws {
238+
let chunkSize = 536 // The default TCP Maximum Segment Size is 536
232239
let data = response.data
233-
self.server.log("[\(address)] Response \(response.code.rawValue) \(response.status) \(response.body.count) bytes")
240+
self.server.log?("[\(address)] Response \(response.code.rawValue) \(response.status) \(response.body.count) bytes")
234241
try await socket.write(data)
235242
await socket.close()
236243
}
@@ -276,12 +283,12 @@ internal extension HTTPServer {
276283
} else {
277284
request.body = Data()
278285
}
279-
self.server.log("[\(address)] \(request.method) \(request.uri) \(request.body.count) bytes")
286+
self.server.log?("[\(address)] \(request.method) \(request.uri) \(request.body.count) bytes")
280287
// respond
281288
let response = await self.server.response(address, request)
282289
try await respond(response)
283290
} catch {
284-
self.server.log("[\(address)] \(error.localizedDescription)")
291+
self.server.log?("[\(address)] \(error.localizedDescription)")
285292
await self.socket.close()
286293
}
287294
}

Tests/HTTPTests/HTTPTests.swift

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ final class HTTPTests: XCTestCase {
146146
func testServerGetBlob() async throws {
147147
let port = UInt16.random(in: 8080 ..< 9000)
148148
let blob = Data(repeating: .random(in: .min ... .max), count: 1024 * .random(in: 1 ... 10))
149+
print("Blob:", blob.count)
149150
var server: HTTPServer? = try await HTTPServer(configuration: .init(port: port), response: { (address, request) in
150151
if request.uri == "/blob", request.method == .get {
151152
return request.body.isEmpty ? .init(code: .ok, body: blob) : .init(code: .badRequest)
@@ -169,6 +170,61 @@ final class HTTPTests: XCTestCase {
169170
func testServerPostBlob() async throws {
170171
let port = UInt16.random(in: 8080 ..< 9000)
171172
let blob = Data(repeating: .random(in: .min ... .max), count: 1024 * .random(in: 1 ... 10))
173+
print("Blob:", blob.count)
174+
var server: HTTPServer? = try await HTTPServer(configuration: .init(port: port), response: { (address, request) in
175+
if request.uri == "/blob", request.method == .post {
176+
XCTAssertEqual(request.headers[.contentLength], blob.count.description)
177+
XCTAssertEqual(request.body.count, blob.count)
178+
XCTAssertEqual(request.body, blob)
179+
return .init(code: request.body == blob ? .ok : .badRequest)
180+
} else {
181+
return .init(code: 404)
182+
}
183+
})
184+
assert(server != nil)
185+
let client = URLSession(configuration: .ephemeral)
186+
let serverURL = URL(string: "http://localhost:\(port)")!
187+
188+
var request = URLRequest(url: serverURL.appendingPathComponent("blob"))
189+
request.httpMethod = HTTPMethod.post.rawValue
190+
request.httpBody = blob
191+
let (data, urlResponse) = try await client.data(for: request)
192+
XCTAssertEqual((urlResponse as! HTTPURLResponse).statusCode, 200)
193+
XCTAssert(data.isEmpty)
194+
195+
//
196+
server = nil
197+
try await Task.sleep(nanoseconds: 100_000)
198+
}
199+
200+
func testServerGetLargeBlob() async throws {
201+
let port = UInt16.random(in: 8080 ..< 9000)
202+
let blob = Data(repeating: .random(in: .min ... .max), count: 1024 * 1024 * .random(in: 2 ... 4))
203+
print("Blob:", blob.count)
204+
var server: HTTPServer? = try await HTTPServer(configuration: .init(port: port), response: { (address, request) in
205+
if request.uri == "/blob", request.method == .get {
206+
return request.body.isEmpty ? .init(code: .ok, body: blob) : .init(code: .badRequest)
207+
} else {
208+
return .init(code: 404)
209+
}
210+
})
211+
assert(server != nil)
212+
let client = URLSession(configuration: .ephemeral)
213+
let serverURL = URL(string: "http://localhost:\(port)")!
214+
215+
let (data, urlResponse) = try await client.data(for: URLRequest(url: serverURL.appendingPathComponent("blob")))
216+
XCTAssertEqual((urlResponse as! HTTPURLResponse).statusCode, 200)
217+
XCTAssertEqual(data, blob)
218+
219+
//
220+
server = nil
221+
try await Task.sleep(nanoseconds: 100_000)
222+
}
223+
224+
func testServerPostLargeBlob() async throws {
225+
let port = UInt16.random(in: 8080 ..< 9000)
226+
let blob = Data(repeating: .random(in: .min ... .max), count: 1024 * 1024 * .random(in: 2 ... 4))
227+
print("Blob:", blob.count)
172228
var server: HTTPServer? = try await HTTPServer(configuration: .init(port: port), response: { (address, request) in
173229
if request.uri == "/blob", request.method == .post {
174230
XCTAssertEqual(request.headers[.contentLength], blob.count.description)

0 commit comments

Comments
 (0)