appium-mac2-driver 4.2.0 → 4.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/WebDriverAgentMac/IntegrationTests/AMW3CActionsTests.m +7 -9
- package/WebDriverAgentMac/WebDriverAgentLib/Routing/AMHTTPServer.h +84 -0
- package/WebDriverAgentMac/WebDriverAgentLib/Routing/AMHTTPServer.m +493 -0
- package/WebDriverAgentMac/WebDriverAgentLib/Routing/AMTCPSocket.h +109 -0
- package/WebDriverAgentMac/WebDriverAgentLib/Routing/AMTCPSocket.m +235 -0
- package/WebDriverAgentMac/WebDriverAgentLib/Routing/FBWebServer.h +1 -1
- package/WebDriverAgentMac/WebDriverAgentLib/Routing/FBWebServer.m +9 -21
- package/WebDriverAgentMac/WebDriverAgentLib/Routing/RouteRequest.h +36 -0
- package/WebDriverAgentMac/WebDriverAgentLib/Routing/RouteRequest.m +33 -0
- package/WebDriverAgentMac/WebDriverAgentLib/Routing/RouteResponse.h +37 -0
- package/WebDriverAgentMac/WebDriverAgentLib/Routing/RouteResponse.m +62 -0
- package/WebDriverAgentMac/WebDriverAgentMac.xcodeproj/project.pbxproj +32 -176
- package/npm-shrinkwrap.json +107 -167
- package/package.json +3 -2
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaAsyncSocket/GCDAsyncSocket.h +0 -1226
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaAsyncSocket/GCDAsyncSocket.m +0 -8513
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaAsyncSocket/GCDAsyncUdpSocket.h +0 -1036
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaAsyncSocket/GCDAsyncUdpSocket.m +0 -5632
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/Categories/DDNumber.h +0 -12
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/Categories/DDNumber.m +0 -88
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/Categories/DDRange.h +0 -56
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/Categories/DDRange.m +0 -106
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPConnection.h +0 -107
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPConnection.m +0 -2238
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPLogging.h +0 -122
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPMessage.h +0 -48
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPMessage.m +0 -114
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPResponse.h +0 -149
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPServer.h +0 -200
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPServer.m +0 -720
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/Responses/HTTPDataResponse.h +0 -13
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/Responses/HTTPDataResponse.m +0 -83
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/Responses/HTTPErrorResponse.h +0 -9
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/Responses/HTTPErrorResponse.m +0 -40
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/RoutingHTTPServer/HTTPResponseProxy.h +0 -13
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/RoutingHTTPServer/HTTPResponseProxy.m +0 -84
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/RoutingHTTPServer/Route.h +0 -18
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/RoutingHTTPServer/Route.m +0 -11
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/RoutingHTTPServer/RouteRequest.h +0 -16
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/RoutingHTTPServer/RouteRequest.m +0 -50
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/RoutingHTTPServer/RouteResponse.h +0 -20
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/RoutingHTTPServer/RouteResponse.m +0 -66
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/RoutingHTTPServer/RoutingConnection.h +0 -5
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/RoutingHTTPServer/RoutingConnection.m +0 -142
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/RoutingHTTPServer/RoutingHTTPServer.h +0 -55
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/RoutingHTTPServer/RoutingHTTPServer.m +0 -288
|
@@ -1,720 +0,0 @@
|
|
|
1
|
-
#import "HTTPServer.h"
|
|
2
|
-
#import "HTTPConnection.h"
|
|
3
|
-
#import "HTTPLogging.h"
|
|
4
|
-
|
|
5
|
-
#import "GCDAsyncSocket.h"
|
|
6
|
-
|
|
7
|
-
#if ! __has_feature(objc_arc)
|
|
8
|
-
#warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
|
|
9
|
-
#endif
|
|
10
|
-
|
|
11
|
-
#pragma clang diagnostic ignored "-Wdirect-ivar-access"
|
|
12
|
-
#pragma clang diagnostic ignored "-Wimplicit-retain-self"
|
|
13
|
-
#pragma clang diagnostic ignored "-Wnullable-to-nonnull-conversion"
|
|
14
|
-
#pragma clang diagnostic ignored "-Wunused"
|
|
15
|
-
|
|
16
|
-
// Log levels: off, error, warn, info, verbose
|
|
17
|
-
// Other flags: trace
|
|
18
|
-
static const int httpLogLevel = HTTP_LOG_LEVEL_INFO; // | HTTP_LOG_FLAG_TRACE;
|
|
19
|
-
|
|
20
|
-
@interface HTTPServer (PrivateAPI)
|
|
21
|
-
|
|
22
|
-
- (void)unpublishBonjour;
|
|
23
|
-
- (void)publishBonjour;
|
|
24
|
-
|
|
25
|
-
+ (void)startBonjourThreadIfNeeded;
|
|
26
|
-
+ (void)performBonjourBlock:(dispatch_block_t)block;
|
|
27
|
-
|
|
28
|
-
@end
|
|
29
|
-
|
|
30
|
-
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
31
|
-
#pragma mark -
|
|
32
|
-
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
33
|
-
|
|
34
|
-
@implementation HTTPServer
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Standard Constructor.
|
|
38
|
-
* Instantiates an HTTP server, but does not start it.
|
|
39
|
-
**/
|
|
40
|
-
- (id)init
|
|
41
|
-
{
|
|
42
|
-
if ((self = [super init]))
|
|
43
|
-
{
|
|
44
|
-
HTTPLogTrace();
|
|
45
|
-
|
|
46
|
-
// Setup underlying dispatch queues
|
|
47
|
-
serverQueue = dispatch_queue_create("HTTPServer", NULL);
|
|
48
|
-
connectionQueue = dispatch_queue_create("HTTPConnection", NULL);
|
|
49
|
-
|
|
50
|
-
IsOnServerQueueKey = &IsOnServerQueueKey;
|
|
51
|
-
IsOnConnectionQueueKey = &IsOnConnectionQueueKey;
|
|
52
|
-
|
|
53
|
-
void *nonNullUnusedPointer = (__bridge void *)self; // Whatever, just not null
|
|
54
|
-
|
|
55
|
-
dispatch_queue_set_specific(serverQueue, IsOnServerQueueKey, nonNullUnusedPointer, NULL);
|
|
56
|
-
dispatch_queue_set_specific(connectionQueue, IsOnConnectionQueueKey, nonNullUnusedPointer, NULL);
|
|
57
|
-
|
|
58
|
-
// Initialize underlying GCD based tcp socket
|
|
59
|
-
asyncSocket = [[GCDAsyncSocket alloc] initWithDelegate:(id<GCDAsyncSocketDelegate>)self delegateQueue:serverQueue];
|
|
60
|
-
|
|
61
|
-
// Use default connection class of HTTPConnection
|
|
62
|
-
connectionClass = [HTTPConnection self];
|
|
63
|
-
|
|
64
|
-
// By default bind on all available interfaces, en1, wifi etc
|
|
65
|
-
interface = nil;
|
|
66
|
-
|
|
67
|
-
// Use a default port of 0
|
|
68
|
-
// This will allow the kernel to automatically pick an open port for us
|
|
69
|
-
port = 0;
|
|
70
|
-
|
|
71
|
-
// Configure default values for bonjour service
|
|
72
|
-
|
|
73
|
-
// Bonjour domain. Use the local domain by default
|
|
74
|
-
domain = @"local.";
|
|
75
|
-
|
|
76
|
-
// If using an empty string ("") for the service name when registering,
|
|
77
|
-
// the system will automatically use the "Computer Name".
|
|
78
|
-
// Passing in an empty string will also handle name conflicts
|
|
79
|
-
// by automatically appending a digit to the end of the name.
|
|
80
|
-
name = @"";
|
|
81
|
-
|
|
82
|
-
// Initialize arrays to hold all the HTTP connections
|
|
83
|
-
connections = [[NSMutableArray alloc] init];
|
|
84
|
-
|
|
85
|
-
connectionsLock = [[NSLock alloc] init];
|
|
86
|
-
|
|
87
|
-
// Register for notifications of closed connections
|
|
88
|
-
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
89
|
-
selector:@selector(connectionDidDie:)
|
|
90
|
-
name:HTTPConnectionDidDieNotification
|
|
91
|
-
object:nil];
|
|
92
|
-
|
|
93
|
-
isRunning = NO;
|
|
94
|
-
}
|
|
95
|
-
return self;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Standard Deconstructor.
|
|
100
|
-
* Stops the server, and clients, and releases any resources connected with this instance.
|
|
101
|
-
**/
|
|
102
|
-
- (void)dealloc
|
|
103
|
-
{
|
|
104
|
-
HTTPLogTrace();
|
|
105
|
-
|
|
106
|
-
// Remove notification observer
|
|
107
|
-
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
108
|
-
|
|
109
|
-
// Stop the server if it's running
|
|
110
|
-
[self stop];
|
|
111
|
-
|
|
112
|
-
// Release all instance variables
|
|
113
|
-
|
|
114
|
-
#if !OS_OBJECT_USE_OBJC
|
|
115
|
-
dispatch_release(serverQueue);
|
|
116
|
-
dispatch_release(connectionQueue);
|
|
117
|
-
#endif
|
|
118
|
-
|
|
119
|
-
[asyncSocket setDelegate:nil delegateQueue:NULL];
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
123
|
-
#pragma mark Server Configuration
|
|
124
|
-
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* The document root is filesystem root for the webserver.
|
|
128
|
-
* Thus requests for /index.html will be referencing the index.html file within the document root directory.
|
|
129
|
-
* All file requests are relative to this document root.
|
|
130
|
-
**/
|
|
131
|
-
- (NSString *)documentRoot
|
|
132
|
-
{
|
|
133
|
-
__block NSString *result;
|
|
134
|
-
|
|
135
|
-
dispatch_sync(serverQueue, ^{
|
|
136
|
-
result = documentRoot;
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
return result;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
- (void)setDocumentRoot:(NSString *)value
|
|
143
|
-
{
|
|
144
|
-
HTTPLogTrace();
|
|
145
|
-
|
|
146
|
-
// Document root used to be of type NSURL.
|
|
147
|
-
// Add type checking for early warning to developers upgrading from older versions.
|
|
148
|
-
|
|
149
|
-
if (value && ![value isKindOfClass:[NSString class]])
|
|
150
|
-
{
|
|
151
|
-
HTTPLogWarn(@"%@: %@ - Expecting NSString parameter, received %@ parameter",
|
|
152
|
-
THIS_FILE, THIS_METHOD, NSStringFromClass([value class]));
|
|
153
|
-
return;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
NSString *valueCopy = [value copy];
|
|
157
|
-
|
|
158
|
-
dispatch_async(serverQueue, ^{
|
|
159
|
-
documentRoot = valueCopy;
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* The connection class is the class that will be used to handle connections.
|
|
166
|
-
* That is, when a new connection is created, an instance of this class will be intialized.
|
|
167
|
-
* The default connection class is HTTPConnection.
|
|
168
|
-
* If you use a different connection class, it is assumed that the class extends HTTPConnection
|
|
169
|
-
**/
|
|
170
|
-
- (Class)connectionClass
|
|
171
|
-
{
|
|
172
|
-
__block Class result;
|
|
173
|
-
|
|
174
|
-
dispatch_sync(serverQueue, ^{
|
|
175
|
-
result = connectionClass;
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
return result;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
- (void)setConnectionClass:(Class)value
|
|
182
|
-
{
|
|
183
|
-
HTTPLogTrace();
|
|
184
|
-
|
|
185
|
-
dispatch_async(serverQueue, ^{
|
|
186
|
-
connectionClass = value;
|
|
187
|
-
});
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* What interface to bind the listening socket to.
|
|
192
|
-
**/
|
|
193
|
-
- (NSString *)interface
|
|
194
|
-
{
|
|
195
|
-
__block NSString *result;
|
|
196
|
-
|
|
197
|
-
dispatch_sync(serverQueue, ^{
|
|
198
|
-
result = interface;
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
return result;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
- (void)setInterface:(NSString *)value
|
|
205
|
-
{
|
|
206
|
-
NSString *valueCopy = [value copy];
|
|
207
|
-
|
|
208
|
-
dispatch_async(serverQueue, ^{
|
|
209
|
-
interface = valueCopy;
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
/**
|
|
215
|
-
* The port to listen for connections on.
|
|
216
|
-
* By default this port is initially set to zero, which allows the kernel to pick an available port for us.
|
|
217
|
-
* After the HTTP server has started, the port being used may be obtained by this method.
|
|
218
|
-
**/
|
|
219
|
-
- (UInt16)port
|
|
220
|
-
{
|
|
221
|
-
__block UInt16 result;
|
|
222
|
-
|
|
223
|
-
dispatch_sync(serverQueue, ^{
|
|
224
|
-
result = port;
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
return result;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
- (UInt16)listeningPort
|
|
231
|
-
{
|
|
232
|
-
__block UInt16 result;
|
|
233
|
-
|
|
234
|
-
dispatch_sync(serverQueue, ^{
|
|
235
|
-
if (isRunning)
|
|
236
|
-
result = [asyncSocket localPort];
|
|
237
|
-
else
|
|
238
|
-
result = 0;
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
return result;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
- (void)setPort:(UInt16)value
|
|
245
|
-
{
|
|
246
|
-
HTTPLogTrace();
|
|
247
|
-
|
|
248
|
-
dispatch_async(serverQueue, ^{
|
|
249
|
-
port = value;
|
|
250
|
-
});
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
/**
|
|
254
|
-
* Domain on which to broadcast this service via Bonjour.
|
|
255
|
-
* The default domain is @"local".
|
|
256
|
-
**/
|
|
257
|
-
- (NSString *)domain
|
|
258
|
-
{
|
|
259
|
-
__block NSString *result;
|
|
260
|
-
|
|
261
|
-
dispatch_sync(serverQueue, ^{
|
|
262
|
-
result = domain;
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
return result;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
- (void)setDomain:(NSString *)value
|
|
269
|
-
{
|
|
270
|
-
HTTPLogTrace();
|
|
271
|
-
|
|
272
|
-
NSString *valueCopy = [value copy];
|
|
273
|
-
|
|
274
|
-
dispatch_async(serverQueue, ^{
|
|
275
|
-
domain = valueCopy;
|
|
276
|
-
});
|
|
277
|
-
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
/**
|
|
281
|
-
* The name to use for this service via Bonjour.
|
|
282
|
-
* The default name is an empty string,
|
|
283
|
-
* which should result in the published name being the host name of the computer.
|
|
284
|
-
**/
|
|
285
|
-
- (NSString *)name
|
|
286
|
-
{
|
|
287
|
-
__block NSString *result;
|
|
288
|
-
|
|
289
|
-
dispatch_sync(serverQueue, ^{
|
|
290
|
-
result = name;
|
|
291
|
-
});
|
|
292
|
-
|
|
293
|
-
return result;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
- (NSString *)publishedName
|
|
297
|
-
{
|
|
298
|
-
__block NSString *result;
|
|
299
|
-
|
|
300
|
-
dispatch_sync(serverQueue, ^{
|
|
301
|
-
|
|
302
|
-
if (netService == nil)
|
|
303
|
-
{
|
|
304
|
-
result = nil;
|
|
305
|
-
}
|
|
306
|
-
else
|
|
307
|
-
{
|
|
308
|
-
|
|
309
|
-
dispatch_block_t bonjourBlock = ^{
|
|
310
|
-
result = [[netService name] copy];
|
|
311
|
-
};
|
|
312
|
-
|
|
313
|
-
[[self class] performBonjourBlock:bonjourBlock];
|
|
314
|
-
}
|
|
315
|
-
});
|
|
316
|
-
|
|
317
|
-
return result;
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
- (void)setName:(NSString *)value
|
|
321
|
-
{
|
|
322
|
-
NSString *valueCopy = [value copy];
|
|
323
|
-
|
|
324
|
-
dispatch_async(serverQueue, ^{
|
|
325
|
-
name = valueCopy;
|
|
326
|
-
});
|
|
327
|
-
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
/**
|
|
331
|
-
* The type of service to publish via Bonjour.
|
|
332
|
-
* No type is set by default, and one must be set in order for the service to be published.
|
|
333
|
-
**/
|
|
334
|
-
- (NSString *)type
|
|
335
|
-
{
|
|
336
|
-
__block NSString *result;
|
|
337
|
-
|
|
338
|
-
dispatch_sync(serverQueue, ^{
|
|
339
|
-
result = type;
|
|
340
|
-
});
|
|
341
|
-
|
|
342
|
-
return result;
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
- (void)setType:(NSString *)value
|
|
346
|
-
{
|
|
347
|
-
NSString *valueCopy = [value copy];
|
|
348
|
-
|
|
349
|
-
dispatch_async(serverQueue, ^{
|
|
350
|
-
type = valueCopy;
|
|
351
|
-
});
|
|
352
|
-
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
/**
|
|
356
|
-
* The extra data to use for this service via Bonjour.
|
|
357
|
-
**/
|
|
358
|
-
- (NSDictionary *)TXTRecordDictionary
|
|
359
|
-
{
|
|
360
|
-
__block NSDictionary *result;
|
|
361
|
-
|
|
362
|
-
dispatch_sync(serverQueue, ^{
|
|
363
|
-
result = txtRecordDictionary;
|
|
364
|
-
});
|
|
365
|
-
|
|
366
|
-
return result;
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
- (void)setTXTRecordDictionary:(NSDictionary *)value
|
|
370
|
-
{
|
|
371
|
-
HTTPLogTrace();
|
|
372
|
-
|
|
373
|
-
NSDictionary *valueCopy = [value copy];
|
|
374
|
-
|
|
375
|
-
dispatch_async(serverQueue, ^{
|
|
376
|
-
|
|
377
|
-
txtRecordDictionary = valueCopy;
|
|
378
|
-
|
|
379
|
-
// Update the txtRecord of the netService if it has already been published
|
|
380
|
-
if (netService)
|
|
381
|
-
{
|
|
382
|
-
NSNetService *theNetService = netService;
|
|
383
|
-
NSData *txtRecordData = nil;
|
|
384
|
-
if (txtRecordDictionary)
|
|
385
|
-
txtRecordData = [NSNetService dataFromTXTRecordDictionary:txtRecordDictionary];
|
|
386
|
-
|
|
387
|
-
dispatch_block_t bonjourBlock = ^{
|
|
388
|
-
[theNetService setTXTRecordData:txtRecordData];
|
|
389
|
-
};
|
|
390
|
-
|
|
391
|
-
[[self class] performBonjourBlock:bonjourBlock];
|
|
392
|
-
}
|
|
393
|
-
});
|
|
394
|
-
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
398
|
-
#pragma mark Server Control
|
|
399
|
-
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
400
|
-
|
|
401
|
-
- (BOOL)start:(NSError **)errPtr
|
|
402
|
-
{
|
|
403
|
-
HTTPLogTrace();
|
|
404
|
-
|
|
405
|
-
__block BOOL success = YES;
|
|
406
|
-
__block NSError *err = nil;
|
|
407
|
-
|
|
408
|
-
dispatch_sync(serverQueue, ^{ @autoreleasepool {
|
|
409
|
-
|
|
410
|
-
success = [asyncSocket acceptOnInterface:interface port:port error:&err];
|
|
411
|
-
if (success)
|
|
412
|
-
{
|
|
413
|
-
HTTPLogInfo(@"%@: Started HTTP server on port %hu", THIS_FILE, [asyncSocket localPort]);
|
|
414
|
-
|
|
415
|
-
isRunning = YES;
|
|
416
|
-
[self publishBonjour];
|
|
417
|
-
}
|
|
418
|
-
else
|
|
419
|
-
{
|
|
420
|
-
HTTPLogError(@"%@: Failed to start HTTP Server: %@", THIS_FILE, err);
|
|
421
|
-
}
|
|
422
|
-
}});
|
|
423
|
-
|
|
424
|
-
if (errPtr)
|
|
425
|
-
*errPtr = err;
|
|
426
|
-
|
|
427
|
-
return success;
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
- (void)stop
|
|
431
|
-
{
|
|
432
|
-
[self stop:NO];
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
- (void)stop:(BOOL)keepExistingConnections
|
|
436
|
-
{
|
|
437
|
-
HTTPLogTrace();
|
|
438
|
-
|
|
439
|
-
dispatch_sync(serverQueue, ^{ @autoreleasepool {
|
|
440
|
-
|
|
441
|
-
// First stop publishing the service via bonjour
|
|
442
|
-
[self unpublishBonjour];
|
|
443
|
-
|
|
444
|
-
// Stop listening / accepting incoming connections
|
|
445
|
-
[asyncSocket disconnect];
|
|
446
|
-
isRunning = NO;
|
|
447
|
-
|
|
448
|
-
if (!keepExistingConnections)
|
|
449
|
-
{
|
|
450
|
-
// Stop all HTTP connections the server owns
|
|
451
|
-
[connectionsLock lock];
|
|
452
|
-
for (HTTPConnection *connection in connections)
|
|
453
|
-
{
|
|
454
|
-
[connection stop];
|
|
455
|
-
}
|
|
456
|
-
[connections removeAllObjects];
|
|
457
|
-
[connectionsLock unlock];
|
|
458
|
-
}
|
|
459
|
-
}});
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
- (BOOL)isRunning
|
|
463
|
-
{
|
|
464
|
-
__block BOOL result;
|
|
465
|
-
|
|
466
|
-
dispatch_sync(serverQueue, ^{
|
|
467
|
-
result = isRunning;
|
|
468
|
-
});
|
|
469
|
-
|
|
470
|
-
return result;
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
474
|
-
#pragma mark Server Status
|
|
475
|
-
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
476
|
-
|
|
477
|
-
/**
|
|
478
|
-
* Returns the number of http client connections that are currently connected to the server.
|
|
479
|
-
**/
|
|
480
|
-
- (NSUInteger)numberOfHTTPConnections
|
|
481
|
-
{
|
|
482
|
-
NSUInteger result = 0;
|
|
483
|
-
|
|
484
|
-
[connectionsLock lock];
|
|
485
|
-
result = [connections count];
|
|
486
|
-
[connectionsLock unlock];
|
|
487
|
-
|
|
488
|
-
return result;
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
492
|
-
#pragma mark Incoming Connections
|
|
493
|
-
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
494
|
-
|
|
495
|
-
- (HTTPConfig *)config
|
|
496
|
-
{
|
|
497
|
-
// Override me if you want to provide a custom config to the new connection.
|
|
498
|
-
//
|
|
499
|
-
// Generally this involves overriding the HTTPConfig class to include any custom settings,
|
|
500
|
-
// and then having this method return an instance of 'MyHTTPConfig'.
|
|
501
|
-
|
|
502
|
-
// Note: Think you can make the server faster by putting each connection on its own queue?
|
|
503
|
-
// Then benchmark it before and after and discover for yourself the shocking truth!
|
|
504
|
-
//
|
|
505
|
-
// Try the apache benchmark tool (already installed on your Mac):
|
|
506
|
-
// $ ab -n 1000 -c 1 http://localhost:<port>/some_path.html
|
|
507
|
-
|
|
508
|
-
return [[HTTPConfig alloc] initWithServer:self documentRoot:documentRoot queue:connectionQueue];
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
- (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket
|
|
512
|
-
{
|
|
513
|
-
HTTPConnection *newConnection = (HTTPConnection *)[[connectionClass alloc] initWithAsyncSocket:newSocket
|
|
514
|
-
configuration:[self config]];
|
|
515
|
-
[connectionsLock lock];
|
|
516
|
-
[connections addObject:newConnection];
|
|
517
|
-
[connectionsLock unlock];
|
|
518
|
-
|
|
519
|
-
[newConnection start];
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
523
|
-
#pragma mark Bonjour
|
|
524
|
-
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
525
|
-
|
|
526
|
-
- (void)publishBonjour
|
|
527
|
-
{
|
|
528
|
-
HTTPLogTrace();
|
|
529
|
-
|
|
530
|
-
NSAssert(dispatch_get_specific(IsOnServerQueueKey) != NULL, @"Must be on serverQueue");
|
|
531
|
-
|
|
532
|
-
if (type)
|
|
533
|
-
{
|
|
534
|
-
netService = [[NSNetService alloc] initWithDomain:domain type:type name:name port:[asyncSocket localPort]];
|
|
535
|
-
[netService setDelegate:self];
|
|
536
|
-
|
|
537
|
-
NSNetService *theNetService = netService;
|
|
538
|
-
NSData *txtRecordData = nil;
|
|
539
|
-
if (txtRecordDictionary)
|
|
540
|
-
txtRecordData = [NSNetService dataFromTXTRecordDictionary:txtRecordDictionary];
|
|
541
|
-
|
|
542
|
-
dispatch_block_t bonjourBlock = ^{
|
|
543
|
-
|
|
544
|
-
[theNetService removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
|
|
545
|
-
[theNetService scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
|
|
546
|
-
[theNetService publish];
|
|
547
|
-
|
|
548
|
-
// Do not set the txtRecordDictionary prior to publishing!!!
|
|
549
|
-
// This will cause the OS to crash!!!
|
|
550
|
-
if (txtRecordData)
|
|
551
|
-
{
|
|
552
|
-
[theNetService setTXTRecordData:txtRecordData];
|
|
553
|
-
}
|
|
554
|
-
};
|
|
555
|
-
|
|
556
|
-
[[self class] startBonjourThreadIfNeeded];
|
|
557
|
-
[[self class] performBonjourBlock:bonjourBlock];
|
|
558
|
-
}
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
- (void)unpublishBonjour
|
|
562
|
-
{
|
|
563
|
-
HTTPLogTrace();
|
|
564
|
-
|
|
565
|
-
NSAssert(dispatch_get_specific(IsOnServerQueueKey) != NULL, @"Must be on serverQueue");
|
|
566
|
-
|
|
567
|
-
if (netService)
|
|
568
|
-
{
|
|
569
|
-
NSNetService *theNetService = netService;
|
|
570
|
-
|
|
571
|
-
dispatch_block_t bonjourBlock = ^{
|
|
572
|
-
|
|
573
|
-
[theNetService stop];
|
|
574
|
-
};
|
|
575
|
-
|
|
576
|
-
[[self class] performBonjourBlock:bonjourBlock];
|
|
577
|
-
|
|
578
|
-
netService = nil;
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
/**
|
|
583
|
-
* Republishes the service via bonjour if the server is running.
|
|
584
|
-
* If the service was not previously published, this method will publish it (if the server is running).
|
|
585
|
-
**/
|
|
586
|
-
- (void)republishBonjour
|
|
587
|
-
{
|
|
588
|
-
HTTPLogTrace();
|
|
589
|
-
|
|
590
|
-
dispatch_async(serverQueue, ^{
|
|
591
|
-
|
|
592
|
-
[self unpublishBonjour];
|
|
593
|
-
[self publishBonjour];
|
|
594
|
-
});
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
/**
|
|
598
|
-
* Called when our bonjour service has been successfully published.
|
|
599
|
-
* This method does nothing but output a log message telling us about the published service.
|
|
600
|
-
**/
|
|
601
|
-
- (void)netServiceDidPublish:(NSNetService *)ns
|
|
602
|
-
{
|
|
603
|
-
// Override me to do something here...
|
|
604
|
-
//
|
|
605
|
-
// Note: This method is invoked on our bonjour thread.
|
|
606
|
-
|
|
607
|
-
HTTPLogInfo(@"Bonjour Service Published: domain(%@) type(%@) name(%@)", [ns domain], [ns type], [ns name]);
|
|
608
|
-
}
|
|
609
|
-
|
|
610
|
-
/**
|
|
611
|
-
* Called if our bonjour service failed to publish itself.
|
|
612
|
-
* This method does nothing but output a log message telling us about the published service.
|
|
613
|
-
**/
|
|
614
|
-
- (void)netService:(NSNetService *)ns didNotPublish:(NSDictionary *)errorDict
|
|
615
|
-
{
|
|
616
|
-
// Override me to do something here...
|
|
617
|
-
//
|
|
618
|
-
// Note: This method in invoked on our bonjour thread.
|
|
619
|
-
|
|
620
|
-
HTTPLogWarn(@"Failed to Publish Service: domain(%@) type(%@) name(%@) - %@",
|
|
621
|
-
[ns domain], [ns type], [ns name], errorDict);
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
625
|
-
#pragma mark Notifications
|
|
626
|
-
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
627
|
-
|
|
628
|
-
/**
|
|
629
|
-
* This method is automatically called when a notification of type HTTPConnectionDidDieNotification is posted.
|
|
630
|
-
* It allows us to remove the connection from our array.
|
|
631
|
-
**/
|
|
632
|
-
- (void)connectionDidDie:(NSNotification *)notification
|
|
633
|
-
{
|
|
634
|
-
// Note: This method is called on the connection queue that posted the notification
|
|
635
|
-
|
|
636
|
-
[connectionsLock lock];
|
|
637
|
-
|
|
638
|
-
HTTPLogTrace();
|
|
639
|
-
[connections removeObject:[notification object]];
|
|
640
|
-
|
|
641
|
-
[connectionsLock unlock];
|
|
642
|
-
}
|
|
643
|
-
|
|
644
|
-
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
645
|
-
#pragma mark Bonjour Thread
|
|
646
|
-
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
647
|
-
|
|
648
|
-
/**
|
|
649
|
-
* NSNetService is runloop based, so it requires a thread with a runloop.
|
|
650
|
-
* This gives us two options:
|
|
651
|
-
*
|
|
652
|
-
* - Use the main thread
|
|
653
|
-
* - Setup our own dedicated thread
|
|
654
|
-
*
|
|
655
|
-
* Since we have various blocks of code that need to synchronously access the netservice objects,
|
|
656
|
-
* using the main thread becomes troublesome and a potential for deadlock.
|
|
657
|
-
**/
|
|
658
|
-
|
|
659
|
-
static NSThread *bonjourThread;
|
|
660
|
-
|
|
661
|
-
+ (void)startBonjourThreadIfNeeded
|
|
662
|
-
{
|
|
663
|
-
HTTPLogTrace();
|
|
664
|
-
|
|
665
|
-
static dispatch_once_t predicate;
|
|
666
|
-
dispatch_once(&predicate, ^{
|
|
667
|
-
|
|
668
|
-
HTTPLogVerbose(@"%@: Starting bonjour thread...", THIS_FILE);
|
|
669
|
-
|
|
670
|
-
bonjourThread = [[NSThread alloc] initWithTarget:self
|
|
671
|
-
selector:@selector(bonjourThread)
|
|
672
|
-
object:nil];
|
|
673
|
-
[bonjourThread start];
|
|
674
|
-
});
|
|
675
|
-
}
|
|
676
|
-
|
|
677
|
-
+ (void)bonjourThread
|
|
678
|
-
{
|
|
679
|
-
@autoreleasepool {
|
|
680
|
-
|
|
681
|
-
HTTPLogVerbose(@"%@: BonjourThread: Started", THIS_FILE);
|
|
682
|
-
|
|
683
|
-
// We can't run the run loop unless it has an associated input source or a timer.
|
|
684
|
-
// So we'll just create a timer that will never fire - unless the server runs for 10,000 years.
|
|
685
|
-
#pragma clang diagnostic push
|
|
686
|
-
#pragma clang diagnostic ignored "-Wundeclared-selector"
|
|
687
|
-
[NSTimer scheduledTimerWithTimeInterval:[[NSDate distantFuture] timeIntervalSinceNow]
|
|
688
|
-
target:self
|
|
689
|
-
selector:@selector(donothingatall:)
|
|
690
|
-
userInfo:nil
|
|
691
|
-
repeats:YES];
|
|
692
|
-
#pragma clang diagnostic pop
|
|
693
|
-
|
|
694
|
-
[[NSRunLoop currentRunLoop] run];
|
|
695
|
-
|
|
696
|
-
HTTPLogVerbose(@"%@: BonjourThread: Aborted", THIS_FILE);
|
|
697
|
-
|
|
698
|
-
}
|
|
699
|
-
}
|
|
700
|
-
|
|
701
|
-
+ (void)executeBonjourBlock:(dispatch_block_t)block
|
|
702
|
-
{
|
|
703
|
-
HTTPLogTrace();
|
|
704
|
-
|
|
705
|
-
NSAssert([NSThread currentThread] == bonjourThread, @"Executed on incorrect thread");
|
|
706
|
-
|
|
707
|
-
block();
|
|
708
|
-
}
|
|
709
|
-
|
|
710
|
-
+ (void)performBonjourBlock:(dispatch_block_t)block
|
|
711
|
-
{
|
|
712
|
-
HTTPLogTrace();
|
|
713
|
-
|
|
714
|
-
[self performSelector:@selector(executeBonjourBlock:)
|
|
715
|
-
onThread:bonjourThread
|
|
716
|
-
withObject:block
|
|
717
|
-
waitUntilDone:YES];
|
|
718
|
-
}
|
|
719
|
-
|
|
720
|
-
@end
|