appium-webdriveragent 16.6.0 → 16.7.0
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 +6 -0
- package/WebDriverAgent.xcodeproj/project.pbxproj +45 -303
- package/WebDriverAgentLib/Info.plist +2 -2
- package/WebDriverAgentLib/Routing/{WatchOS/FBWatchHTTPServer.h → FBHTTPServer.h} +11 -7
- package/WebDriverAgentLib/Routing/{WatchOS/FBWatchHTTPServer.m → FBHTTPServer.m} +26 -13
- package/WebDriverAgentLib/Routing/FBTCPSocket.h +10 -45
- package/WebDriverAgentLib/Routing/FBTCPSocket.m +12 -94
- package/WebDriverAgentLib/Routing/FBWebServer.h +1 -1
- package/WebDriverAgentLib/Routing/FBWebServer.m +4 -49
- package/WebDriverAgentLib/Routing/{WatchOS/RouteRequest.h → RouteRequest.h} +2 -4
- package/WebDriverAgentLib/Routing/{WatchOS/RouteResponse.h → RouteResponse.h} +2 -2
- package/WebDriverAgentLib/Utilities/FBMjpegServer.h +3 -5
- package/WebDriverAgentLib/Utilities/FBMjpegServer.m +1 -66
- package/package.json +1 -1
- package/WebDriverAgentLib/Vendor/CocoaAsyncSocket/GCDAsyncSocket.h +0 -1220
- package/WebDriverAgentLib/Vendor/CocoaAsyncSocket/GCDAsyncSocket.m +0 -8786
- package/WebDriverAgentLib/Vendor/CocoaAsyncSocket/GCDAsyncUdpSocket.h +0 -1036
- package/WebDriverAgentLib/Vendor/CocoaAsyncSocket/GCDAsyncUdpSocket.m +0 -5868
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/Categories/DDNumber.h +0 -12
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/Categories/DDNumber.m +0 -88
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/Categories/DDRange.h +0 -56
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/Categories/DDRange.m +0 -100
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPConnection.h +0 -109
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPConnection.m +0 -2281
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPLogging.h +0 -122
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPMessage.h +0 -53
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPMessage.m +0 -357
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPResponse.h +0 -149
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPServer.h +0 -126
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPServer.m +0 -372
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/LICENSE +0 -18
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/Responses/HTTPDataResponse.h +0 -13
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/Responses/HTTPDataResponse.m +0 -83
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/Responses/HTTPErrorResponse.h +0 -9
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/Responses/HTTPErrorResponse.m +0 -38
- package/WebDriverAgentLib/Vendor/RoutingHTTPServer/HTTPResponseProxy.h +0 -13
- package/WebDriverAgentLib/Vendor/RoutingHTTPServer/HTTPResponseProxy.m +0 -84
- package/WebDriverAgentLib/Vendor/RoutingHTTPServer/LICENSE +0 -19
- package/WebDriverAgentLib/Vendor/RoutingHTTPServer/Route.h +0 -18
- package/WebDriverAgentLib/Vendor/RoutingHTTPServer/Route.m +0 -11
- package/WebDriverAgentLib/Vendor/RoutingHTTPServer/RouteRequest.h +0 -16
- package/WebDriverAgentLib/Vendor/RoutingHTTPServer/RouteRequest.m +0 -50
- package/WebDriverAgentLib/Vendor/RoutingHTTPServer/RouteResponse.h +0 -20
- package/WebDriverAgentLib/Vendor/RoutingHTTPServer/RouteResponse.m +0 -66
- package/WebDriverAgentLib/Vendor/RoutingHTTPServer/RoutingConnection.h +0 -5
- package/WebDriverAgentLib/Vendor/RoutingHTTPServer/RoutingConnection.m +0 -142
- package/WebDriverAgentLib/Vendor/RoutingHTTPServer/RoutingHTTPServer.h +0 -55
- package/WebDriverAgentLib/Vendor/RoutingHTTPServer/RoutingHTTPServer.m +0 -303
- /package/WebDriverAgentLib/Routing/{WatchOS/RouteRequest.m → RouteRequest.m} +0 -0
- /package/WebDriverAgentLib/Routing/{WatchOS/RouteResponse.m → RouteResponse.m} +0 -0
|
@@ -15,11 +15,11 @@
|
|
|
15
15
|
<key>CFBundlePackageType</key>
|
|
16
16
|
<string>FMWK</string>
|
|
17
17
|
<key>CFBundleShortVersionString</key>
|
|
18
|
-
<string>16.
|
|
18
|
+
<string>16.7.0</string>
|
|
19
19
|
<key>CFBundleSignature</key>
|
|
20
20
|
<string>????</string>
|
|
21
21
|
<key>CFBundleVersion</key>
|
|
22
|
-
<string>16.
|
|
22
|
+
<string>16.7.0</string>
|
|
23
23
|
<key>NSPrincipalClass</key>
|
|
24
24
|
<string/>
|
|
25
25
|
</dict>
|
|
@@ -6,13 +6,11 @@
|
|
|
6
6
|
* LICENSE file in the root directory of this source tree.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
//
|
|
10
|
-
// forbids - see FBTCPSocket.h/.m.
|
|
11
|
-
// FBTCPSocket, mirroring just enough of RoutingHTTPServer's API for FBWebServer.m to swap
|
|
12
|
-
// servers with a single #if TARGET_OS_WATCH.
|
|
9
|
+
// A minimal HTTP/1.1 server on top of FBTCPSocket (Network.framework-backed on every platform,
|
|
10
|
+
// since watchOS forbids BSD sockets outright - see FBTCPSocket.h/.m).
|
|
13
11
|
//
|
|
14
12
|
// No chunked encoding, range requests, or pipelining - just request line + headers +
|
|
15
|
-
// Content-Length body, and ":param" path matching
|
|
13
|
+
// Content-Length body, and ":param" path matching.
|
|
16
14
|
|
|
17
15
|
@import Foundation;
|
|
18
16
|
|
|
@@ -21,7 +19,7 @@
|
|
|
21
19
|
|
|
22
20
|
NS_ASSUME_NONNULL_BEGIN
|
|
23
21
|
|
|
24
|
-
@interface
|
|
22
|
+
@interface FBHTTPServer : NSObject
|
|
25
23
|
|
|
26
24
|
/*! The port the server is (or will be) listening on */
|
|
27
25
|
@property (nonatomic) uint16_t port;
|
|
@@ -40,9 +38,15 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
40
38
|
*/
|
|
41
39
|
- (void)setDefaultHeader:(NSString *)field value:(NSString *)value;
|
|
42
40
|
|
|
41
|
+
/**
|
|
42
|
+
Sets the local IP address to bind the listener to. Must be called before -start:. Pass nil (the
|
|
43
|
+
default) to listen on all interfaces.
|
|
44
|
+
*/
|
|
45
|
+
- (void)setInterface:(nullable NSString *)interface;
|
|
46
|
+
|
|
43
47
|
/**
|
|
44
48
|
Registers a route handler for the given HTTP method and path pattern (":param" segments are
|
|
45
|
-
captured into the request's `params
|
|
49
|
+
captured into the request's `params`).
|
|
46
50
|
*/
|
|
47
51
|
- (void)handleMethod:(NSString *)method
|
|
48
52
|
withPath:(NSString *)path
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* LICENSE file in the root directory of this source tree.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
#import "
|
|
9
|
+
#import "FBHTTPServer.h"
|
|
10
10
|
|
|
11
11
|
#import "FBConfiguration.h"
|
|
12
12
|
#import "FBTCPSocket.h"
|
|
@@ -28,29 +28,30 @@ static NSData * _Nonnull FBUTF8Data(NSString *string)
|
|
|
28
28
|
return (NSData * _Nonnull)[string dataUsingEncoding:NSUTF8StringEncoding];
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
@interface
|
|
31
|
+
@interface FBHTTPRoute : NSObject
|
|
32
32
|
@property (nonatomic, copy) NSString *verb;
|
|
33
33
|
@property (nonatomic, strong) NSRegularExpression *regex;
|
|
34
34
|
@property (nonatomic, copy, nullable) NSArray<NSString *> *keys;
|
|
35
35
|
@property (nonatomic, copy) void (^block)(RouteRequest *request, RouteResponse *response);
|
|
36
36
|
@end
|
|
37
37
|
|
|
38
|
-
@implementation
|
|
38
|
+
@implementation FBHTTPRoute
|
|
39
39
|
@end
|
|
40
40
|
|
|
41
41
|
|
|
42
|
-
@interface
|
|
42
|
+
@interface FBHTTPServer () <FBTCPSocketDelegate>
|
|
43
43
|
|
|
44
44
|
@property (nonatomic, nullable, strong) FBTCPSocket *socket;
|
|
45
|
-
@property (nonatomic, strong) NSMutableArray<
|
|
45
|
+
@property (nonatomic, strong) NSMutableArray<FBHTTPRoute *> *routes;
|
|
46
46
|
@property (nonatomic, strong) NSMutableDictionary<NSString *, NSString *> *defaultHeaders;
|
|
47
47
|
@property (nonatomic, nullable) dispatch_queue_t routeQueue;
|
|
48
|
+
@property (nonatomic, copy, nullable) NSString *interface;
|
|
48
49
|
// nw_connection_t isn't NSCopying, so it can't be an NSDictionary key - use NSMapTable instead.
|
|
49
50
|
@property (nonatomic, strong) NSMapTable<id, NSMutableData *> *connectionBuffers;
|
|
50
51
|
|
|
51
52
|
@end
|
|
52
53
|
|
|
53
|
-
@implementation
|
|
54
|
+
@implementation FBHTTPServer
|
|
54
55
|
|
|
55
56
|
- (instancetype)init
|
|
56
57
|
{
|
|
@@ -73,15 +74,20 @@ static NSData * _Nonnull FBUTF8Data(NSString *string)
|
|
|
73
74
|
self.defaultHeaders[field] = value;
|
|
74
75
|
}
|
|
75
76
|
|
|
77
|
+
- (void)setInterface:(nullable NSString *)interface
|
|
78
|
+
{
|
|
79
|
+
_interface = interface.copy;
|
|
80
|
+
}
|
|
81
|
+
|
|
76
82
|
#pragma mark - Route registration
|
|
77
83
|
|
|
78
|
-
- (
|
|
84
|
+
- (FBHTTPRoute *)compiledRouteWithPath:(NSString *)path
|
|
79
85
|
{
|
|
80
|
-
|
|
86
|
+
FBHTTPRoute *route = [FBHTTPRoute new];
|
|
81
87
|
NSMutableArray<NSString *> *keys = [NSMutableArray array];
|
|
82
88
|
|
|
83
89
|
// Escape regex-significant characters before substituting :param placeholders, like
|
|
84
|
-
// RoutingHTTPServer.m
|
|
90
|
+
// RoutingHTTPServer.m used to.
|
|
85
91
|
NSRegularExpression *escapeRegex = [NSRegularExpression regularExpressionWithPattern:@"[.+()]"
|
|
86
92
|
options:(NSRegularExpressionOptions)0
|
|
87
93
|
error:nil];
|
|
@@ -126,7 +132,7 @@ static NSData * _Nonnull FBUTF8Data(NSString *string)
|
|
|
126
132
|
withPath:(NSString *)path
|
|
127
133
|
block:(void (^)(RouteRequest *request, RouteResponse *response))block
|
|
128
134
|
{
|
|
129
|
-
|
|
135
|
+
FBHTTPRoute *route = [self compiledRouteWithPath:path];
|
|
130
136
|
route.verb = method.uppercaseString;
|
|
131
137
|
route.block = block;
|
|
132
138
|
[self.routes addObject:route];
|
|
@@ -142,6 +148,7 @@ static NSData * _Nonnull FBUTF8Data(NSString *string)
|
|
|
142
148
|
- (BOOL)start:(NSError **)error
|
|
143
149
|
{
|
|
144
150
|
FBTCPSocket *socket = [[FBTCPSocket alloc] initWithPort:self.port];
|
|
151
|
+
socket.interface = self.interface;
|
|
145
152
|
socket.delegate = self;
|
|
146
153
|
if (![socket startWithError:error]) {
|
|
147
154
|
return NO;
|
|
@@ -239,8 +246,8 @@ static NSData * _Nonnull FBUTF8Data(NSString *string)
|
|
|
239
246
|
|
|
240
247
|
NSUInteger contentLength = (NSUInteger)requestHeaders[@"content-length"].integerValue;
|
|
241
248
|
if (contentLength > FBConfiguration.sharedInstance.httpRequestBodySizeLimit) {
|
|
242
|
-
// Mirrors
|
|
243
|
-
//
|
|
249
|
+
// Mirrors CocoaHTTPServer's maxRequestBodySize enforcement. Closes the connection after
|
|
250
|
+
// responding, since the rest of the oversized body is still incoming.
|
|
244
251
|
RouteResponse *tooLarge = [RouteResponse new];
|
|
245
252
|
tooLarge.statusCode = kHTTPStatusCodeRequestEntityTooLarge;
|
|
246
253
|
[tooLarge respondWithString:@"Request Entity Too Large"];
|
|
@@ -269,7 +276,7 @@ static NSData * _Nonnull FBUTF8Data(NSString *string)
|
|
|
269
276
|
NSURLComponents *requestTarget = [NSURLComponents componentsWithString:pathAndQuery];
|
|
270
277
|
NSString *path = requestTarget.path ?: pathAndQuery;
|
|
271
278
|
|
|
272
|
-
for (
|
|
279
|
+
for (FBHTTPRoute *route in self.routes) {
|
|
273
280
|
if (![route.verb isEqualToString:method]) {
|
|
274
281
|
continue;
|
|
275
282
|
}
|
|
@@ -367,6 +374,12 @@ static NSData * _Nonnull FBUTF8Data(NSString *string)
|
|
|
367
374
|
return @"Bad Request";
|
|
368
375
|
} else if (kHTTPStatusCodeNotFound == statusCode) {
|
|
369
376
|
return @"Not Found";
|
|
377
|
+
} else if (kHTTPStatusCodeMethodNotAllowed == statusCode) {
|
|
378
|
+
return @"Method Not Allowed";
|
|
379
|
+
} else if (kHTTPStatusCodeRequestTimeout == statusCode) {
|
|
380
|
+
return @"Request Timeout";
|
|
381
|
+
} else if (kHTTPStatusCodeRequestEntityTooLarge == statusCode) {
|
|
382
|
+
return @"Request Entity Too Large";
|
|
370
383
|
} else if (kHTTPStatusCodeInternalServerError == statusCode) {
|
|
371
384
|
return @"Internal Server Error";
|
|
372
385
|
}
|
|
@@ -6,28 +6,18 @@
|
|
|
6
6
|
* LICENSE file in the root directory of this source tree.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
// TARGET_OS_WATCH must be defined before the #if below runs, or (on some older Xcode/SDK
|
|
10
|
-
// toolchains) it silently evaluates as undefined/false here despite being true for the rest of
|
|
11
|
-
// the translation unit - which desyncs this file's declarations from FBTCPSocket.m's own
|
|
12
|
-
// #if TARGET_OS_WATCH branch.
|
|
13
|
-
#import <TargetConditionals.h>
|
|
14
|
-
|
|
15
|
-
#if TARGET_OS_WATCH
|
|
16
9
|
@import Foundation;
|
|
17
10
|
// A textual import, not `@import Network;` - older Xcode/watchOS SDK combinations (verified:
|
|
18
11
|
// Xcode 15.4/watchOS 10.5) fail to expose nw_listener_t/nw_connection_t and friends through the
|
|
19
12
|
// Network module map on watchOS, even though the underlying API has existed since watchOS 5.0.
|
|
13
|
+
// Kept unconditional (rather than gated to watchOS) since it also builds cleanly on iOS/tvOS.
|
|
20
14
|
#import <Network/Network.h>
|
|
21
|
-
#else
|
|
22
|
-
#import "GCDAsyncSocket.h"
|
|
23
|
-
#endif
|
|
24
15
|
|
|
25
16
|
NS_ASSUME_NONNULL_BEGIN
|
|
26
17
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
//
|
|
30
|
-
// hence a differently-shaped, push-style delegate protocol.
|
|
18
|
+
// Backed by Network.framework rather than BSD sockets on every platform, since watchOS forbids
|
|
19
|
+
// BSD sockets outright and there is no reason to keep a second, socket-based implementation
|
|
20
|
+
// around just for iOS/tvOS.
|
|
31
21
|
@protocol FBTCPSocketDelegate <NSObject>
|
|
32
22
|
|
|
33
23
|
/**
|
|
@@ -54,35 +44,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
54
44
|
|
|
55
45
|
@end
|
|
56
46
|
|
|
57
|
-
#else
|
|
58
|
-
|
|
59
|
-
@protocol FBTCPSocketDelegate
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
The callback which is fired on new TCP client connection
|
|
63
|
-
|
|
64
|
-
@param newClient The newly connected socket
|
|
65
|
-
*/
|
|
66
|
-
- (void)didClientConnect:(GCDAsyncSocket *)newClient;
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
The callback which is fired when the TCP server receives a data from a connected client
|
|
70
|
-
|
|
71
|
-
@param client The client, which sent the data
|
|
72
|
-
*/
|
|
73
|
-
- (void)didClientSendData:(GCDAsyncSocket *)client;
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
The callback which is fired when TCP client disconnects
|
|
77
|
-
|
|
78
|
-
@param client The actual diconnected client
|
|
79
|
-
*/
|
|
80
|
-
- (void)didClientDisconnect:(GCDAsyncSocket *)client;
|
|
81
|
-
|
|
82
|
-
@end
|
|
83
|
-
|
|
84
|
-
#endif
|
|
85
|
-
|
|
86
47
|
|
|
87
48
|
@interface FBTCPSocket : NSObject
|
|
88
49
|
|
|
@@ -99,6 +60,12 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
99
60
|
*/
|
|
100
61
|
@property (nonatomic, readonly) uint16_t port;
|
|
101
62
|
|
|
63
|
+
/**
|
|
64
|
+
The local IP address to bind the listener to, or nil to listen on all interfaces. Must be set
|
|
65
|
+
before -startWithError: is called.
|
|
66
|
+
*/
|
|
67
|
+
@property (nonatomic, copy, nullable) NSString *interface;
|
|
68
|
+
|
|
102
69
|
/**
|
|
103
70
|
Creates TCP socket isntance which is going to be started on the specified port
|
|
104
71
|
|
|
@@ -120,7 +87,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
120
87
|
*/
|
|
121
88
|
- (void)stop;
|
|
122
89
|
|
|
123
|
-
#if TARGET_OS_WATCH
|
|
124
90
|
/**
|
|
125
91
|
Writes data to the given connected client
|
|
126
92
|
|
|
@@ -139,7 +105,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
139
105
|
@param completion Called once the send attempt finishes
|
|
140
106
|
*/
|
|
141
107
|
- (void)writeData:(NSData *)data toClient:(nw_connection_t)client completion:(nullable void (^)(void))completion;
|
|
142
|
-
#endif
|
|
143
108
|
|
|
144
109
|
@end
|
|
145
110
|
|
|
@@ -8,8 +8,6 @@
|
|
|
8
8
|
|
|
9
9
|
#import "FBTCPSocket.h"
|
|
10
10
|
|
|
11
|
-
#if TARGET_OS_WATCH
|
|
12
|
-
|
|
13
11
|
@interface FBTCPSocket()
|
|
14
12
|
@property (readonly, nonatomic) dispatch_queue_t socketQueue;
|
|
15
13
|
@property (nullable, nonatomic) nw_listener_t listener;
|
|
@@ -37,7 +35,18 @@
|
|
|
37
35
|
NSString *portString = [NSString stringWithFormat:@"%u", (unsigned int)self.port];
|
|
38
36
|
// portString is always valid UTF8; -UTF8String is just declared nullable in general.
|
|
39
37
|
const char * _Nonnull portCString = (const char * _Nonnull)portString.UTF8String;
|
|
40
|
-
|
|
38
|
+
|
|
39
|
+
nw_listener_t listener;
|
|
40
|
+
if (nil != self.interface) {
|
|
41
|
+
const char * _Nonnull interfaceCString = (const char * _Nonnull)((NSString * _Nonnull)self.interface).UTF8String;
|
|
42
|
+
nw_endpoint_t localEndpoint = nw_endpoint_create_host(interfaceCString, portCString);
|
|
43
|
+
nw_parameters_set_local_endpoint(parameters, localEndpoint);
|
|
44
|
+
// The port is already encoded in localEndpoint above - do not also pass it to
|
|
45
|
+
// nw_listener_create_with_port, which would be ambiguous.
|
|
46
|
+
listener = nw_listener_create(parameters);
|
|
47
|
+
} else {
|
|
48
|
+
listener = nw_listener_create_with_port(portCString, parameters);
|
|
49
|
+
}
|
|
41
50
|
if (nil == listener) {
|
|
42
51
|
if (error) {
|
|
43
52
|
*error = [NSError errorWithDomain:@"FBTCPSocket"
|
|
@@ -206,94 +215,3 @@
|
|
|
206
215
|
}
|
|
207
216
|
|
|
208
217
|
@end
|
|
209
|
-
|
|
210
|
-
#else
|
|
211
|
-
|
|
212
|
-
@interface FBTCPSocket()
|
|
213
|
-
@property (readonly, nonatomic) dispatch_queue_t socketQueue;
|
|
214
|
-
@property (readonly, nonatomic) GCDAsyncSocket *listeningSocket;
|
|
215
|
-
@property (readonly, nonatomic) NSMutableArray *connectedClients;
|
|
216
|
-
@end
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
@interface FBTCPSocket(AsyncSocket) <GCDAsyncSocketDelegate>
|
|
220
|
-
|
|
221
|
-
@end
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
@implementation FBTCPSocket
|
|
225
|
-
|
|
226
|
-
- (instancetype)initWithPort:(uint16_t)port
|
|
227
|
-
{
|
|
228
|
-
if ((self = [super init])) {
|
|
229
|
-
_socketQueue = dispatch_queue_create("socketQueue", NULL);
|
|
230
|
-
_listeningSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:_socketQueue];
|
|
231
|
-
_connectedClients = [[NSMutableArray alloc] initWithCapacity:1];
|
|
232
|
-
_port = port;
|
|
233
|
-
_delegate = nil;
|
|
234
|
-
}
|
|
235
|
-
return self;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
- (BOOL)startWithError:(NSError **)error
|
|
239
|
-
{
|
|
240
|
-
if (![self.listeningSocket acceptOnPort:self.port error:error]) {
|
|
241
|
-
return NO;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
_port = self.listeningSocket.localPort;
|
|
245
|
-
return YES;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
- (void)stop
|
|
249
|
-
{
|
|
250
|
-
@synchronized(self.connectedClients) {
|
|
251
|
-
NSArray *clients = self.connectedClients.copy;
|
|
252
|
-
[self.connectedClients removeAllObjects];
|
|
253
|
-
for (GCDAsyncSocket *client in clients) {
|
|
254
|
-
[client disconnect];
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
self.delegate = nil;
|
|
259
|
-
[self.listeningSocket disconnect];
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
@end
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
@implementation FBTCPSocket(AsyncSocket)
|
|
266
|
-
|
|
267
|
-
- (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket
|
|
268
|
-
{
|
|
269
|
-
@synchronized(self.connectedClients) {
|
|
270
|
-
[self.connectedClients addObject:newSocket];
|
|
271
|
-
}
|
|
272
|
-
id<FBTCPSocketDelegate> delegate = self.delegate;
|
|
273
|
-
if (nil != delegate) {
|
|
274
|
-
[delegate didClientConnect:newSocket];
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
|
|
279
|
-
{
|
|
280
|
-
id<FBTCPSocketDelegate> delegate = self.delegate;
|
|
281
|
-
if (nil != delegate) {
|
|
282
|
-
[delegate didClientSendData:sock];
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err
|
|
287
|
-
{
|
|
288
|
-
@synchronized(self.connectedClients) {
|
|
289
|
-
[self.connectedClients removeObject:sock];
|
|
290
|
-
}
|
|
291
|
-
id<FBTCPSocketDelegate> delegate = self.delegate;
|
|
292
|
-
if (nil != delegate) {
|
|
293
|
-
[delegate didClientDisconnect:sock];
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
@end
|
|
298
|
-
|
|
299
|
-
#endif
|
|
@@ -8,12 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
#import "FBWebServer.h"
|
|
10
10
|
|
|
11
|
-
#
|
|
12
|
-
#import "FBWatchHTTPServer.h"
|
|
13
|
-
#else
|
|
14
|
-
#import "RoutingConnection.h"
|
|
15
|
-
#import "RoutingHTTPServer.h"
|
|
16
|
-
#endif
|
|
11
|
+
#import "FBHTTPServer.h"
|
|
17
12
|
#import "FBMjpegServer.h"
|
|
18
13
|
#import "FBTCPSocket.h"
|
|
19
14
|
|
|
@@ -32,34 +27,9 @@
|
|
|
32
27
|
static NSString *const FBServerURLBeginMarker = @"ServerURLHere->";
|
|
33
28
|
static NSString *const FBServerURLEndMarker = @"<-ServerURLHere";
|
|
34
29
|
|
|
35
|
-
#if !TARGET_OS_WATCH
|
|
36
|
-
@interface FBHTTPConnection : RoutingConnection
|
|
37
|
-
@end
|
|
38
|
-
|
|
39
|
-
@implementation FBHTTPConnection
|
|
40
|
-
|
|
41
|
-
- (void)handleResourceNotFound
|
|
42
|
-
{
|
|
43
|
-
[FBLogger logFmt:@"Received request for %@ which we do not handle", self.requestURI];
|
|
44
|
-
[super handleResourceNotFound];
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
- (UInt64)maxRequestBodySize
|
|
48
|
-
{
|
|
49
|
-
return FBConfiguration.sharedInstance.httpRequestBodySizeLimit;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
@end
|
|
53
|
-
#endif
|
|
54
|
-
|
|
55
|
-
|
|
56
30
|
@interface FBWebServer ()
|
|
57
31
|
@property (nonatomic, strong) FBExceptionHandler *exceptionHandler;
|
|
58
|
-
|
|
59
|
-
@property (nonatomic, strong) FBWatchHTTPServer *server;
|
|
60
|
-
#else
|
|
61
|
-
@property (nonatomic, strong) RoutingHTTPServer *server;
|
|
62
|
-
#endif
|
|
32
|
+
@property (nonatomic, strong) FBHTTPServer *server;
|
|
63
33
|
@property (nonatomic, nullable) FBTCPSocket *screenshotsBroadcaster;
|
|
64
34
|
@property (nonatomic, nullable, strong) FBMjpegServer *mjpegServer;
|
|
65
35
|
@property (atomic, assign) BOOL keepAlive;
|
|
@@ -104,30 +74,21 @@ static NSString *const FBServerURLEndMarker = @"<-ServerURLHere";
|
|
|
104
74
|
|
|
105
75
|
- (BOOL)startHTTPServer
|
|
106
76
|
{
|
|
107
|
-
|
|
108
|
-
self.server = [[FBWatchHTTPServer alloc] init];
|
|
109
|
-
#else
|
|
110
|
-
self.server = [[RoutingHTTPServer alloc] init];
|
|
111
|
-
#endif
|
|
77
|
+
self.server = [[FBHTTPServer alloc] init];
|
|
112
78
|
[self.server setRouteQueue:dispatch_get_main_queue()];
|
|
113
79
|
[self.server setDefaultHeader:@"Server" value:@"WebDriverAgent/1.0"];
|
|
114
80
|
[self.server setDefaultHeader:@"Access-Control-Allow-Origin" value:@"*"];
|
|
115
81
|
[self.server setDefaultHeader:@"Access-Control-Allow-Headers" value:@"Content-Type, X-Requested-With"];
|
|
116
|
-
#if !TARGET_OS_WATCH
|
|
117
|
-
[self.server setConnectionClass:[FBHTTPConnection self]];
|
|
118
|
-
#endif
|
|
119
82
|
|
|
120
83
|
[self registerRouteHandlers:[self.class collectCommandHandlerClasses]];
|
|
121
84
|
[self registerServerKeyRouteHandlers];
|
|
122
85
|
|
|
123
86
|
NSRange serverPortRange = FBConfiguration.sharedInstance.bindingPortRange;
|
|
124
87
|
NSString *bindingIP = FBConfiguration.sharedInstance.bindingIPAddress;
|
|
125
|
-
#if !TARGET_OS_WATCH
|
|
126
88
|
if (bindingIP != nil) {
|
|
127
89
|
[self.server setInterface:bindingIP];
|
|
128
90
|
[FBLogger logFmt:@"Using custom binding IP address: %@", bindingIP];
|
|
129
91
|
}
|
|
130
|
-
#endif
|
|
131
92
|
|
|
132
93
|
NSError *error;
|
|
133
94
|
BOOL serverStarted = NO;
|
|
@@ -165,9 +126,7 @@ static NSString *const FBServerURLEndMarker = @"<-ServerURLHere";
|
|
|
165
126
|
self.mjpegServer = [[FBMjpegServer alloc] init];
|
|
166
127
|
self.screenshotsBroadcaster = [[FBTCPSocket alloc]
|
|
167
128
|
initWithPort:(uint16_t)FBConfiguration.sharedInstance.mjpegServerPort];
|
|
168
|
-
#if TARGET_OS_WATCH
|
|
169
129
|
self.mjpegServer.socket = self.screenshotsBroadcaster;
|
|
170
|
-
#endif
|
|
171
130
|
self.screenshotsBroadcaster.delegate = self.mjpegServer;
|
|
172
131
|
NSError *error;
|
|
173
132
|
if (![self.screenshotsBroadcaster startWithError:&error]) {
|
|
@@ -220,11 +179,7 @@ static NSString *const FBServerURLEndMarker = @"<-ServerURLHere";
|
|
|
220
179
|
self.keepAlive = NO;
|
|
221
180
|
}
|
|
222
181
|
|
|
223
|
-
|
|
224
|
-
- (BOOL)attemptToStartServer:(FBWatchHTTPServer *)server onPort:(NSInteger)port withError:(NSError **)error
|
|
225
|
-
#else
|
|
226
|
-
- (BOOL)attemptToStartServer:(RoutingHTTPServer *)server onPort:(NSInteger)port withError:(NSError **)error
|
|
227
|
-
#endif
|
|
182
|
+
- (BOOL)attemptToStartServer:(FBHTTPServer *)server onPort:(NSInteger)port withError:(NSError **)error
|
|
228
183
|
{
|
|
229
184
|
server.port = (UInt16)port;
|
|
230
185
|
NSError *innerError = nil;
|
|
@@ -6,10 +6,8 @@
|
|
|
6
6
|
* LICENSE file in the root directory of this source tree.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
// built there (see FBWatchHTTPServer.h). Exposes just the surface FBWebServer's route blocks
|
|
12
|
-
// and FBRoute.decorateRequest: read.
|
|
9
|
+
// A minimal request value type, exposing just the surface FBWebServer's route blocks and
|
|
10
|
+
// FBRoute.decorateRequest: read.
|
|
13
11
|
|
|
14
12
|
@import Foundation;
|
|
15
13
|
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
* LICENSE file in the root directory of this source tree.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
//
|
|
10
|
-
//
|
|
9
|
+
// A minimal response value type, exposing just the surface FBRoute.m/FBResponseJSONPayload.m
|
|
10
|
+
// call on it.
|
|
11
11
|
|
|
12
12
|
@import Foundation;
|
|
13
13
|
#import <WebDriverAgentLib/FBHTTPStatusCodes.h>
|
|
@@ -19,14 +19,12 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
19
19
|
*/
|
|
20
20
|
- (instancetype)init;
|
|
21
21
|
|
|
22
|
-
#if TARGET_OS_WATCH
|
|
23
22
|
/**
|
|
24
|
-
The socket that owns this instance as its delegate.
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
The socket that owns this instance as its delegate. Clients are bare nw_connection_t values
|
|
24
|
+
with no write method of their own, so frame writes are routed through
|
|
25
|
+
-[FBTCPSocket writeData:toClient:]. Must be set before streaming starts.
|
|
27
26
|
*/
|
|
28
27
|
@property (nonatomic, weak, nullable) FBTCPSocket *socket;
|
|
29
|
-
#endif
|
|
30
28
|
|
|
31
29
|
/**
|
|
32
30
|
Stops screenshot broadcasting and prevents future scheduling.
|
|
@@ -11,12 +11,8 @@
|
|
|
11
11
|
#import <mach/mach_time.h>
|
|
12
12
|
@import UniformTypeIdentifiers;
|
|
13
13
|
|
|
14
|
-
#if TARGET_OS_WATCH
|
|
15
14
|
// Textual import, not `@import Network;` - see the comment in FBTCPSocket.h.
|
|
16
15
|
#import <Network/Network.h>
|
|
17
|
-
#else
|
|
18
|
-
#import "GCDAsyncSocket.h"
|
|
19
|
-
#endif
|
|
20
16
|
#import "FBConfiguration.h"
|
|
21
17
|
#import "FBLogger.h"
|
|
22
18
|
#import "FBScreenshot.h"
|
|
@@ -41,11 +37,7 @@ static NSUInteger FBNormalizedMjpegFramerate(NSUInteger framerate)
|
|
|
41
37
|
@interface FBMjpegServer()
|
|
42
38
|
|
|
43
39
|
@property (nonatomic, readonly) dispatch_queue_t backgroundQueue;
|
|
44
|
-
#if TARGET_OS_WATCH
|
|
45
40
|
@property (nonatomic, readonly) NSMutableArray<nw_connection_t> *listeningClients;
|
|
46
|
-
#else
|
|
47
|
-
@property (nonatomic, readonly) NSMutableArray<GCDAsyncSocket *> *listeningClients;
|
|
48
|
-
#endif
|
|
49
41
|
@property (nonatomic, readonly) FBImageProcessor *imageProcessor;
|
|
50
42
|
@property (nonatomic, readonly) long long mainScreenID;
|
|
51
43
|
@property (nonatomic, assign) NSUInteger consecutiveScreenshotFailures;
|
|
@@ -157,16 +149,9 @@ static NSUInteger FBNormalizedMjpegFramerate(NSUInteger framerate)
|
|
|
157
149
|
return;
|
|
158
150
|
}
|
|
159
151
|
NSUInteger clientCount = self.listeningClients.count;
|
|
160
|
-
#if TARGET_OS_WATCH
|
|
161
152
|
for (nw_connection_t client in self.listeningClients) {
|
|
162
153
|
[self.socket writeData:chunk toClient:client];
|
|
163
154
|
}
|
|
164
|
-
#else
|
|
165
|
-
for (GCDAsyncSocket *client in self.listeningClients) {
|
|
166
|
-
// Slow clients should fail/close instead of buffering indefinitely.
|
|
167
|
-
[client writeData:chunk withTimeout:FRAME_TIMEOUT tag:0];
|
|
168
|
-
}
|
|
169
|
-
#endif
|
|
170
155
|
self.sentFramesCount++;
|
|
171
156
|
self.sentBytesCount += chunk.length * clientCount;
|
|
172
157
|
NSUInteger framerate = FBNormalizedMjpegFramerate(FBConfiguration.sharedInstance.mjpegServerFramerate);
|
|
@@ -179,13 +164,10 @@ static NSUInteger FBNormalizedMjpegFramerate(NSUInteger framerate)
|
|
|
179
164
|
}
|
|
180
165
|
}
|
|
181
166
|
|
|
182
|
-
#if TARGET_OS_WATCH
|
|
183
|
-
|
|
184
167
|
- (void)didClientConnect:(nw_connection_t)newClient
|
|
185
168
|
{
|
|
186
169
|
[FBLogger log:@"Got screenshots broadcast client connection"];
|
|
187
|
-
// FBTCPSocket already schedules the receive that -client:didReceiveData: relies on below
|
|
188
|
-
// unlike GCDAsyncSocket, there is nothing to arm here.
|
|
170
|
+
// FBTCPSocket already schedules the receive that -client:didReceiveData: relies on below.
|
|
189
171
|
}
|
|
190
172
|
|
|
191
173
|
- (void)client:(nw_connection_t)client didReceiveData:(NSData *)data
|
|
@@ -224,53 +206,6 @@ static NSUInteger FBNormalizedMjpegFramerate(NSUInteger framerate)
|
|
|
224
206
|
}
|
|
225
207
|
}
|
|
226
208
|
|
|
227
|
-
#else
|
|
228
|
-
|
|
229
|
-
- (void)didClientConnect:(GCDAsyncSocket *)newClient
|
|
230
|
-
{
|
|
231
|
-
[FBLogger logFmt:@"Got screenshots broadcast client connection at %@:%d", newClient.connectedHost, newClient.connectedPort];
|
|
232
|
-
// Start broadcast only after there is any data from the client
|
|
233
|
-
[newClient readDataWithTimeout:-1 tag:0];
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
- (void)didClientSendData:(GCDAsyncSocket *)client
|
|
237
|
-
{
|
|
238
|
-
@synchronized (self.listeningClients) {
|
|
239
|
-
if ([self.listeningClients containsObject:client]) {
|
|
240
|
-
return;
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
[FBLogger logFmt:@"Starting screenshots broadcast for the client at %@:%d", client.connectedHost, client.connectedPort];
|
|
245
|
-
NSString *streamHeader = [NSString stringWithFormat:@"HTTP/1.0 200 OK\r\nServer: %@\r\nConnection: close\r\nMax-Age: 0\r\nExpires: 0\r\nCache-Control: no-cache, private\r\nPragma: no-cache\r\nContent-Type: multipart/x-mixed-replace; boundary=--BoundaryString\r\n\r\n", SERVER_NAME];
|
|
246
|
-
[client writeData:(id)[streamHeader dataUsingEncoding:NSUTF8StringEncoding] withTimeout:-1 tag:0];
|
|
247
|
-
@synchronized (self.listeningClients) {
|
|
248
|
-
[self.listeningClients addObject:client];
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
- (void)didClientDisconnect:(GCDAsyncSocket *)client
|
|
253
|
-
{
|
|
254
|
-
@synchronized (self.listeningClients) {
|
|
255
|
-
[self.listeningClients removeObject:client];
|
|
256
|
-
}
|
|
257
|
-
[FBLogger log:@"Disconnected a client from screenshots broadcast"];
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
- (void)stopStreaming
|
|
261
|
-
{
|
|
262
|
-
self.isStreaming = NO;
|
|
263
|
-
@synchronized (self.listeningClients) {
|
|
264
|
-
NSArray<GCDAsyncSocket *> *clients = self.listeningClients.copy;
|
|
265
|
-
[self.listeningClients removeAllObjects];
|
|
266
|
-
for (GCDAsyncSocket *client in clients) {
|
|
267
|
-
[client disconnect];
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
#endif
|
|
273
|
-
|
|
274
209
|
- (void)dealloc
|
|
275
210
|
{
|
|
276
211
|
[self stopStreaming];
|