@@ -27,6 +27,13 @@ import Dispatch
27
27
typealias SOCKET = Int32
28
28
#endif
29
29
30
+ private let serverDebug = ( ProcessInfo . processInfo. environment [ " SCLF_HTTP_SERVER_DEBUG " ] == " YES " )
31
+
32
+ private func debugLog( _ msg: String ) {
33
+ if serverDebug {
34
+ NSLog ( msg)
35
+ }
36
+ }
30
37
31
38
public let globalDispatchQueue = DispatchQueue . global ( )
32
39
public let dispatchQueueMake : ( String ) -> DispatchQueue = { DispatchQueue . init ( label: $0) }
@@ -47,7 +54,7 @@ extension UInt16 {
47
54
}
48
55
49
56
// _TCPSocket wraps one socket that is used either to listen()/accept() new connections, or for the client connection itself.
50
- class _TCPSocket {
57
+ class _TCPSocket : CustomStringConvertible {
51
58
#if !os(Windows)
52
59
#if os(Linux) || os(Android) || os(FreeBSD)
53
60
private let sendFlags = CInt ( MSG_NOSIGNAL)
@@ -56,6 +63,10 @@ class _TCPSocket {
56
63
#endif
57
64
#endif
58
65
66
+ var description : String {
67
+ return " _TCPSocket @ 0x " + String( unsafeBitCast ( self , to: UInt . self) , radix: 16 )
68
+ }
69
+
59
70
let listening : Bool
60
71
private var _socket : SOCKET !
61
72
private var socketAddress = UnsafeMutablePointer< sockaddr_in> . allocate( capacity: 1 )
@@ -139,7 +150,7 @@ class _TCPSocket {
139
150
#endif
140
151
}
141
152
142
- func acceptConnection( notify : ServerSemaphore ) throws -> _TCPSocket {
153
+ func acceptConnection( ) throws -> _TCPSocket {
143
154
guard listening else { fatalError ( " Trying to listen on a client connection socket " ) }
144
155
let connection : SOCKET = try socketAddress. withMemoryRebound ( to: sockaddr. self, capacity: MemoryLayout< sockaddr> . size, {
145
156
let addr = UnsafeMutablePointer < sockaddr > ( $0)
@@ -157,6 +168,7 @@ class _TCPSocket {
157
168
throw ServerError . init ( operation: " setsockopt " , errno: errno, file: #file, line: #line)
158
169
}
159
170
#endif
171
+ debugLog ( " \( self ) acceptConnection: accepted: \( connectionSocket) " )
160
172
return connectionSocket
161
173
} )
162
174
return _TCPSocket ( socket: connection)
@@ -187,7 +199,6 @@ class _TCPSocket {
187
199
guard let connectionSocket = _socket else {
188
200
throw InternalServerError . socketAlreadyClosed
189
201
}
190
-
191
202
#if os(Windows)
192
203
_ = try data. withUnsafeBytes {
193
204
var dwNumberOfBytesSent : DWORD = 0
@@ -196,47 +207,16 @@ class _TCPSocket {
196
207
}
197
208
#else
198
209
_ = try data. withUnsafeBytes { ptr in
199
- try attempt ( " send " , valid: isNotNegative, CInt ( send ( connectionSocket, ptr. baseAddress!, data. count, sendFlags) ) )
200
- }
201
- #endif
202
- }
203
-
204
- private func _send( _ bytes: [ UInt8 ] ) throws -> Int {
205
- guard let connectionSocket = _socket else {
206
- throw InternalServerError . socketAlreadyClosed
207
- }
208
-
209
- #if os(Windows)
210
- return try bytes. withUnsafeBytes {
211
- var dwNumberOfBytesSent : DWORD = 0
212
- var wsaBuffer : WSABUF = WSABUF ( len: ULONG ( bytes. count) , buf: UnsafeMutablePointer < CHAR > ( mutating: $0. bindMemory ( to: CHAR . self) . baseAddress) )
213
- return try Int ( attempt ( " WSASend " , valid: { $0 != SOCKET_ERROR } , WSASend ( connectionSocket, & wsaBuffer, 1 , & dwNumberOfBytesSent, 0 , nil , nil ) ) )
214
- }
215
- #else
216
- return try bytes. withUnsafeBufferPointer {
217
- try attempt ( " send " , valid: { $0 >= 0 } , send ( connectionSocket, $0. baseAddress, $0. count, sendFlags) )
210
+ try attempt ( " send " , valid: { $0 == data. count } , CInt ( send ( connectionSocket, ptr. baseAddress!, data. count, sendFlags) ) )
218
211
}
219
212
#endif
213
+ debugLog ( " wrote \( data. count) bytes " )
220
214
}
221
215
222
- func writeData( header: String , bodyData: Data , sendDelay: TimeInterval ? = nil , bodyChunks: Int ? = nil ) throws {
223
- _ = try _send ( Array ( header. utf8) )
224
-
225
- if let sendDelay = sendDelay, let bodyChunks = bodyChunks {
226
- let count = max ( 1 , Int ( Double ( bodyData. count) / Double( bodyChunks) ) )
227
- for startIndex in stride ( from: 0 , to: bodyData. count, by: count) {
228
- Thread . sleep ( forTimeInterval: sendDelay)
229
- let endIndex = min ( startIndex + count, bodyData. count)
230
- try bodyData. withUnsafeBytes { ( ptr: UnsafeRawBufferPointer ) -> Void in
231
- let chunk = UnsafeRawBufferPointer ( rebasing: ptr [ startIndex..< endIndex] )
232
- _ = try _send ( Array ( chunk. bindMemory ( to: UInt8 . self) ) )
233
- }
234
- }
235
- } else {
236
- try bodyData. withUnsafeBytes { ( ptr: UnsafeRawBufferPointer ) -> Void in
237
- _ = try _send ( Array ( ptr. bindMemory ( to: UInt8 . self) ) )
238
- }
239
- }
216
+ func writeData( header: String , bodyData: Data ) throws {
217
+ var totalData = Data ( header. utf8)
218
+ totalData. append ( bodyData)
219
+ try writeRawData ( totalData)
240
220
}
241
221
242
222
func closeSocket( ) throws {
@@ -252,11 +232,17 @@ class _TCPSocket {
252
232
}
253
233
254
234
deinit {
235
+ debugLog ( " \( self ) closing socket " )
255
236
try ? closeSocket ( )
256
237
}
257
238
}
258
239
259
- class _HTTPServer {
240
+
241
+ class _HTTPServer : CustomStringConvertible {
242
+
243
+ var description : String {
244
+ return " _HTTPServer @ 0x " + String( unsafeBitCast ( self , to: UInt . self) , radix: 16 )
245
+ }
260
246
261
247
// Provide Data() blocks from the socket either separated by a given separator or of a requested block size.
262
248
struct _SocketDataReader {
@@ -271,6 +257,7 @@ class _HTTPServer {
271
257
var range = buffer. range ( of: separatorData)
272
258
while range == nil {
273
259
guard let data = try tcpSocket. readData ( ) else { break }
260
+ debugLog ( " read \( data. count) bytes " )
274
261
buffer. append ( data)
275
262
range = buffer. range ( of: separatorData)
276
263
}
@@ -284,6 +271,7 @@ class _HTTPServer {
284
271
mutating func readBytes( count: Int ) throws -> Data {
285
272
while buffer. count < count {
286
273
guard let data = try tcpSocket. readData ( ) else { break }
274
+ debugLog ( " read \( data. count) bytes " )
287
275
buffer. append ( data)
288
276
}
289
277
guard buffer. count >= count else {
@@ -296,6 +284,10 @@ class _HTTPServer {
296
284
}
297
285
}
298
286
287
+ deinit {
288
+ debugLog ( " _HTTPServer \( self ) stopping " )
289
+ }
290
+
299
291
let tcpSocket : _TCPSocket
300
292
var port : UInt16 { tcpSocket. port }
301
293
@@ -311,8 +303,9 @@ class _HTTPServer {
311
303
return try _HTTPServer ( port: port)
312
304
}
313
305
314
- public func listen( notify: ServerSemaphore ) throws -> _HTTPServer {
315
- let connection = try tcpSocket. acceptConnection ( notify: notify)
306
+ public func listen( ) throws -> _HTTPServer {
307
+ let connection = try tcpSocket. acceptConnection ( )
308
+ debugLog ( " \( self ) accepted: \( connection) " )
316
309
return _HTTPServer ( socket: connection)
317
310
}
318
311
@@ -381,14 +374,8 @@ class _HTTPServer {
381
374
return request
382
375
}
383
376
384
- public func respond( with response: _HTTPResponse , startDelay: TimeInterval ? = nil , sendDelay: TimeInterval ? = nil , bodyChunks: Int ? = nil ) throws {
385
- if let delay = startDelay {
386
- Thread . sleep ( forTimeInterval: delay)
387
- }
388
- do {
389
- try tcpSocket. writeData ( header: response. header, bodyData: response. bodyData, sendDelay: sendDelay, bodyChunks: bodyChunks)
390
- } catch {
391
- }
377
+ public func respond( with response: _HTTPResponse ) throws {
378
+ try tcpSocket. writeData ( header: response. header, bodyData: response. bodyData)
392
379
}
393
380
394
381
func respondWithBrokenResponses( uri: String ) throws {
@@ -490,7 +477,7 @@ class _HTTPServer {
490
477
}
491
478
}
492
479
493
- struct _HTTPRequest {
480
+ struct _HTTPRequest : CustomStringConvertible {
494
481
enum Method : String {
495
482
case HEAD
496
483
case GET
@@ -511,6 +498,9 @@ struct _HTTPRequest {
511
498
private( set) var parameters : [ String : String ] = [ : ]
512
499
var messageBody : String ?
513
500
var messageData : Data ?
501
+ var description : String {
502
+ return " \( method. rawValue) \( uri) "
503
+ }
514
504
515
505
516
506
public init ( header: String ) throws {
@@ -644,7 +634,12 @@ struct _HTTPResponse {
644
634
}
645
635
}
646
636
647
- public class TestURLSessionServer {
637
+ public class TestURLSessionServer : CustomStringConvertible {
638
+
639
+ public var description : String {
640
+ return " TestURLSessionServer @ 0x " + String( unsafeBitCast ( self , to: UInt . self) , radix: 16 )
641
+ }
642
+
648
643
let capitals : [ String : String ] = [ " Nepal " : " Kathmandu " ,
649
644
" Peru " : " Lima " ,
650
645
" Italy " : " Rome " ,
@@ -654,19 +649,15 @@ public class TestURLSessionServer {
654
649
" UK " : " London " ,
655
650
" country.txt " : " A country is a region that is identified as a distinct national entity in political geography " ]
656
651
let httpServer : _HTTPServer
657
- let startDelay : TimeInterval ?
658
- let sendDelay : TimeInterval ?
659
- let bodyChunks : Int ?
660
652
661
653
internal init ( httpServer: _HTTPServer ) {
662
654
self . httpServer = httpServer
663
- self . startDelay = nil
664
- self . sendDelay = nil
665
- self . bodyChunks = nil
655
+ debugLog ( " \( self ) - server \( httpServer) " )
666
656
}
667
657
668
658
public func readAndRespond( ) throws {
669
659
let req = try httpServer. request ( )
660
+ debugLog ( " request: \( req) " )
670
661
if let value = req. getHeader ( for: " x-pause " ) {
671
662
if let wait = Double ( value) , wait > 0 {
672
663
Thread . sleep ( forTimeInterval: wait)
@@ -691,7 +682,9 @@ public class TestURLSessionServer {
691
682
} else if req. uri. hasPrefix ( " /unauthorized " ) {
692
683
try httpServer. respondWithUnauthorizedHeader ( )
693
684
} else {
694
- try httpServer. respond ( with: getResponse ( request: req) )
685
+ let response = try getResponse ( request: req)
686
+ try httpServer. respond ( with: response)
687
+ debugLog ( " response: \( response) " )
695
688
}
696
689
}
697
690
@@ -918,23 +911,11 @@ enum InternalServerError : Error {
918
911
case badBody
919
912
}
920
913
921
- public class ServerSemaphore {
922
- let dispatchSemaphore = DispatchSemaphore ( value: 0 )
923
-
924
- public func wait( timeout: DispatchTime ) -> DispatchTimeoutResult {
925
- return dispatchSemaphore. wait ( timeout: timeout)
926
- }
927
-
928
- public func signal( ) {
929
- dispatchSemaphore. signal ( )
930
- }
931
- }
932
914
933
915
class LoopbackServerTest : XCTestCase {
934
916
private static let staticSyncQ = DispatchQueue ( label: " org.swift.TestFoundation.HTTPServer.StaticSyncQ " )
935
917
936
918
private static var _serverPort : Int = - 1
937
- private static let serverReady = ServerSemaphore ( )
938
919
private static var _serverActive = false
939
920
private static var testServer : _HTTPServer ? = nil
940
921
@@ -955,18 +936,26 @@ class LoopbackServerTest : XCTestCase {
955
936
956
937
override class func setUp( ) {
957
938
super. setUp ( )
958
- func runServer( with condition: ServerSemaphore ) throws {
939
+
940
+ var _serverPort = 0
941
+ let dispatchGroup = DispatchGroup ( )
942
+
943
+ func runServer( ) throws {
959
944
testServer = try _HTTPServer ( port: nil )
960
- serverPort = Int ( testServer!. port)
961
- serverReady. signal ( )
945
+ _serverPort = Int ( testServer!. port)
962
946
serverActive = true
947
+ dispatchGroup. leave ( )
963
948
964
949
while serverActive {
965
950
do {
966
- let httpServer = try testServer!. listen ( notify : condition )
951
+ let httpServer = try testServer!. listen ( )
967
952
globalDispatchQueue. async {
968
953
let subServer = TestURLSessionServer ( httpServer: httpServer)
969
- try ? subServer. readAndRespond ( )
954
+ do {
955
+ try subServer. readAndRespond ( )
956
+ } catch {
957
+ NSLog ( " reandAndRespond: \( error) " )
958
+ }
970
959
}
971
960
} catch {
972
961
if ( serverActive) { // Ignore errors thrown on shutdown
@@ -977,20 +966,22 @@ class LoopbackServerTest : XCTestCase {
977
966
serverPort = - 2
978
967
}
979
968
969
+ dispatchGroup. enter ( )
970
+
980
971
globalDispatchQueue. async {
981
972
do {
982
- try runServer ( with : serverReady )
973
+ try runServer ( )
983
974
} catch {
975
+ NSLog ( " runServer: \( error) " )
984
976
}
985
977
}
986
978
987
979
let timeout = DispatchTime ( uptimeNanoseconds: DispatchTime . now ( ) . uptimeNanoseconds + 2_000_000_000 )
988
980
989
- while serverPort == - 1 {
990
- guard serverReady. wait ( timeout: timeout) == . success else {
991
- fatalError ( " Timedout waiting for server to be ready " )
992
- }
981
+ guard dispatchGroup. wait ( timeout: timeout) == . success, _serverPort > 0 else {
982
+ fatalError ( " Timedout waiting for server to be ready " )
993
983
}
984
+ serverPort = _serverPort
994
985
}
995
986
996
987
override class func tearDown( ) {
0 commit comments