appium-mac2-driver 4.3.3 → 4.3.4

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 CHANGED
@@ -1,3 +1,9 @@
1
+ ## [4.3.4](https://github.com/appium/appium-mac2-driver/compare/v4.3.3...v4.3.4) (2026-09-02)
2
+
3
+ ### Bug Fixes
4
+
5
+ * harden AMHTTPServer's HTTP/1.1 request framing ([#418](https://github.com/appium/appium-mac2-driver/issues/418)) ([0d487d6](https://github.com/appium/appium-mac2-driver/commit/0d487d66a7834edb077a90119da312743b7ac640))
6
+
1
7
  ## [4.3.3](https://github.com/appium/appium-mac2-driver/compare/v4.3.2...v4.3.3) (2026-09-01)
2
8
 
3
9
  ### Miscellaneous Chores
@@ -25,6 +25,33 @@
25
25
  // bodies above this size instead of buffering them fully in memory.
26
26
  static const NSUInteger kMaxHTTPRequestBodySize = 64 * 1024 * 1024;
27
27
 
28
+ // Caps a request's header block, so a connection that never completes one cannot grow its buffer
29
+ // without limit. Matches node's default --max-http-header-size.
30
+ static const NSUInteger kMaxHTTPRequestHeaderSize = 16 * 1024;
31
+
32
+ // ASCII decimal digits only. -integerValue must not be used here: it maps garbage silently
33
+ // ("bogus" -> 0, "12abc" -> 12), desyncing the framing of every later request on the connection.
34
+ static BOOL AMParseContentLength(NSString *value, NSUInteger *outLength)
35
+ {
36
+ if (value.length < 1) {
37
+ return NO;
38
+ }
39
+ NSUInteger result = 0;
40
+ for (NSUInteger i = 0; i < value.length; i++) {
41
+ unichar c = [value characterAtIndex:i];
42
+ if (c < '0' || c > '9') {
43
+ return NO;
44
+ }
45
+ NSUInteger digit = (NSUInteger)(c - '0');
46
+ if (result > (NSUIntegerMax - digit) / 10) {
47
+ return NO;
48
+ }
49
+ result = result * 10 + digit;
50
+ }
51
+ *outLength = result;
52
+ return YES;
53
+ }
54
+
28
55
  static NSData *AMCRLFCRLFData(void)
29
56
  {
30
57
  static NSData *data;
@@ -258,89 +285,197 @@ static NSData * _Nonnull AMUTF8Data(NSString *string)
258
285
  }
259
286
 
260
287
  if (nil == pending) {
261
- NSRange headerEndRange = [buffer rangeOfData:AMCRLFCRLFData() options:(NSDataSearchOptions)0 range:NSMakeRange(0, buffer.length)];
262
- if (NSNotFound == headerEndRange.location) {
263
- // Wait for the rest of the header block to arrive.
264
- return;
265
- }
266
-
267
- NSData *headerData = [buffer subdataWithRange:NSMakeRange(0, headerEndRange.location)];
268
- NSString *headerString = [[NSString alloc] initWithData:headerData encoding:NSUTF8StringEncoding];
269
- NSArray<NSString *> *lines = [headerString componentsSeparatedByString:@"\r\n"];
270
- if (lines.count < 1) {
271
- [self respondBadRequestToClient:client];
272
- return;
273
- }
274
-
275
- NSArray<NSString *> *requestLineParts = [lines.firstObject componentsSeparatedByString:@" "];
276
- if (requestLineParts.count < 2) {
277
- [self respondBadRequestToClient:client];
278
- return;
279
- }
280
-
281
- NSMutableDictionary<NSString *, NSString *> *requestHeaders = [NSMutableDictionary dictionary];
282
- for (NSUInteger i = 1; i < lines.count; i++) {
283
- NSString *line = lines[i];
284
- NSRange colonRange = [line rangeOfString:@":"];
285
- if (NSNotFound == colonRange.location) {
286
- continue;
287
- }
288
- NSString *name = [line substringToIndex:colonRange.location];
289
- NSString *value = [[line substringFromIndex:colonRange.location + 1]
290
- stringByTrimmingCharactersInSet:NSCharacterSet.whitespaceCharacterSet];
291
- requestHeaders[name.lowercaseString] = value;
292
- }
293
-
294
- NSString *transferEncoding = requestHeaders[@"transfer-encoding"].lowercaseString;
295
- if (nil != transferEncoding && NSNotFound != [transferEncoding rangeOfString:@"chunked"].location) {
296
- // De-chunking isn't implemented - fail loudly instead of silently misreading the body as
297
- // empty and desyncing the rest of the connection's request stream.
298
- RouteResponse *notImplemented = [RouteResponse new];
299
- id<FBResponsePayload> notImplementedPayload = FBResponseWithStatus([FBCommandStatus unknownCommandErrorWithMessage:@"Chunked Transfer-Encoding is not supported"
300
- traceback:nil]);
301
- [notImplementedPayload dispatchWithResponse:notImplemented];
302
- [self failClient:client withResponse:notImplemented];
303
- return;
304
- }
305
-
306
- NSUInteger contentLength = (NSUInteger)requestHeaders[@"content-length"].integerValue;
307
- if (contentLength > kMaxHTTPRequestBodySize) {
308
- // Closes the connection after responding, since the rest of the oversized body is still
309
- // incoming.
310
- RouteResponse *tooLarge = [RouteResponse new];
311
- id<FBResponsePayload> tooLargePayload = FBResponseWithStatus([FBCommandStatus unknownCommandErrorWithMessage:@"Request Entity Too Large"
312
- traceback:nil]);
313
- [tooLargePayload dispatchWithResponse:tooLarge];
314
- [self failClient:client withResponse:tooLarge];
288
+ pending = [self parsedRequestHeaderFromBuffer:buffer forClient:client];
289
+ if (nil == pending) {
290
+ // Either the header block is still incomplete, or it was rejected and answered already.
315
291
  return;
316
292
  }
317
-
318
- pending = [AMPendingHTTPRequestHeader new];
319
- pending.method = requestLineParts[0].uppercaseString;
320
- pending.pathAndQuery = requestLineParts[1];
321
- pending.bodyStart = headerEndRange.location + headerEndRange.length;
322
- pending.contentLength = contentLength;
323
293
  @synchronized (self.connectionBuffers) {
324
294
  [self.pendingRequestHeaders setObject:pending forKey:client];
325
295
  }
326
296
  }
327
297
 
328
- NSUInteger totalRequestLength = pending.bodyStart + pending.contentLength;
329
- if (buffer.length < totalRequestLength) {
330
- // Wait for the rest of the body to arrive - the parsed header stays cached above, so this
331
- // doesn't re-scan/re-parse the header block on every subsequently arriving chunk.
298
+ if (![self dispatchBufferedRequestWithHeader:pending fromBuffer:buffer forClient:client]) {
299
+ // The body hasn't fully arrived yet - stop instead of re-checking the same unchanged
300
+ // buffer, which would spin forever on this connection's queue and starve every other
301
+ // connection's receive callbacks behind it.
332
302
  return;
333
303
  }
304
+ }
305
+ }
334
306
 
335
- NSData *body = pending.contentLength > 0 ? [buffer subdataWithRange:NSMakeRange(pending.bodyStart, pending.contentLength)] : [NSData data];
307
+ // Locates the CRLFCRLF that ends the buffered header block and bounds the block's size. Returns
308
+ // NO when nothing can be parsed yet - either because more bytes are needed or because the block
309
+ // was rejected, in which case the 400 has already been written.
310
+ - (BOOL)findHeaderBlockEnd:(out NSRange *)outHeaderEndRange
311
+ inBuffer:(NSMutableData *)buffer
312
+ forClient:(nw_connection_t)client
313
+ {
314
+ NSRange headerEndRange = [buffer rangeOfData:AMCRLFCRLFData() options:(NSDataSearchOptions)0 range:NSMakeRange(0, buffer.length)];
315
+ if (NSNotFound == headerEndRange.location) {
316
+ if (buffer.length > kMaxHTTPRequestHeaderSize) {
317
+ // Past any legitimate header block and still unterminated - stop buffering.
318
+ [self respondBadRequestToClient:client];
319
+ }
320
+ // Otherwise wait for the rest of the header block to arrive.
321
+ return NO;
322
+ }
323
+ if (headerEndRange.location > kMaxHTTPRequestHeaderSize) {
324
+ // The check above only fires while the terminator is missing; one large receive can deliver
325
+ // an oversized block with it, so bound the completed block too before parsing it.
326
+ [self respondBadRequestToClient:client];
327
+ return NO;
328
+ }
329
+ *outHeaderEndRange = headerEndRange;
330
+ return YES;
331
+ }
336
332
 
337
- @synchronized (self.connectionBuffers) {
338
- [buffer replaceBytesInRange:NSMakeRange(0, totalRequestLength) withBytes:NULL length:0];
339
- [self.pendingRequestHeaders removeObjectForKey:client];
333
+ // Turns the header lines that follow the request line into a lowercase-keyed dictionary.
334
+ // Returns nil for the malformed and ambiguous shapes, having written the 400 already.
335
+ - (nullable NSDictionary<NSString *, NSString *> *)parsedHeaderFieldsFromLines:(NSArray<NSString *> *)lines
336
+ forClient:(nw_connection_t)client
337
+ {
338
+ NSMutableDictionary<NSString *, NSString *> *requestHeaders = [NSMutableDictionary dictionary];
339
+ for (NSUInteger i = 1; i < lines.count; i++) {
340
+ NSString *line = lines[i];
341
+ if (0 == line.length) {
342
+ continue;
340
343
  }
344
+ NSRange colonRange = [line rangeOfString:@":"];
345
+ if (NSNotFound == colonRange.location) {
346
+ // Malformed. Skipping it would drop what it meant to say: "Content-Length 5" would
347
+ // dispatch with an empty body, leaving its bytes to be parsed as another request.
348
+ [self respondBadRequestToClient:client];
349
+ return nil;
350
+ }
351
+ NSString *name = [line substringToIndex:colonRange.location];
352
+ // RFC 7230 (3.2.4): whitespace before the colon MUST be rejected. Storing "content-length "
353
+ // as its own key would drop the real header and desync the framing.
354
+ if (0 == name.length
355
+ || NSNotFound != [name rangeOfCharacterFromSet:NSCharacterSet.whitespaceAndNewlineCharacterSet].location) {
356
+ [self respondBadRequestToClient:client];
357
+ return nil;
358
+ }
359
+ NSString *value = [[line substringFromIndex:colonRange.location + 1]
360
+ stringByTrimmingCharactersInSet:NSCharacterSet.whitespaceCharacterSet];
361
+ NSString *normalizedName = name.lowercaseString;
362
+ // RFC 7230 (3.3.3): repeated framing fields are unrecoverable. Last-wins would let an empty
363
+ // "Transfer-Encoding:" mask an earlier "chunked", and the last Content-Length drive parsing.
364
+ if (([normalizedName isEqualToString:@"content-length"] || [normalizedName isEqualToString:@"transfer-encoding"])
365
+ && nil != requestHeaders[normalizedName]) {
366
+ [self respondBadRequestToClient:client];
367
+ return nil;
368
+ }
369
+ requestHeaders[normalizedName] = value;
370
+ }
371
+ return requestHeaders;
372
+ }
373
+
374
+ // Rejects framing this server cannot honour and resolves the declared body length from the
375
+ // remaining framing headers. Returns NO having written the closing error response already.
376
+ - (BOOL)resolveBodyLength:(out NSUInteger *)outBodyLength
377
+ fromHeaderFields:(NSDictionary<NSString *, NSString *> *)requestHeaders
378
+ forClient:(nw_connection_t)client
379
+ {
380
+ NSString *transferEncoding = requestHeaders[@"transfer-encoding"];
381
+ if (nil != transferEncoding) {
382
+ // No transfer decoder is implemented at all, so any encoding (chunked or otherwise -
383
+ // including a value only introduced by a duplicate header overwriting "chunked" above) is
384
+ // rejected rather than risking the body being misread as empty and desyncing the rest of
385
+ // the connection's request stream.
386
+ RouteResponse *notImplemented = [RouteResponse new];
387
+ id<FBResponsePayload> notImplementedPayload = FBResponseWithStatus([FBCommandStatus invalidArgumentErrorWithMessage:@"Transfer-Encoding is not supported"
388
+ traceback:nil]);
389
+ [notImplementedPayload dispatchWithResponse:notImplemented];
390
+ [self failClient:client withResponse:notImplemented];
391
+ return NO;
392
+ }
393
+
394
+ NSString *contentLengthValue = requestHeaders[@"content-length"];
395
+ NSUInteger contentLength = 0;
396
+ if (nil != contentLengthValue && !AMParseContentLength(contentLengthValue, &contentLength)) {
397
+ // The body's extent is unknowable, so the connection cannot be resynced - reject and close.
398
+ [self respondBadRequestToClient:client];
399
+ return NO;
400
+ }
401
+ if (contentLength > kMaxHTTPRequestBodySize) {
402
+ // Closes the connection after responding, since the rest of the oversized body is still
403
+ // incoming.
404
+ RouteResponse *tooLarge = [RouteResponse new];
405
+ id<FBResponsePayload> tooLargePayload = FBResponseWithStatus([FBCommandStatus invalidArgumentErrorWithMessage:@"Request Entity Too Large"
406
+ traceback:nil]);
407
+ [tooLargePayload dispatchWithResponse:tooLarge];
408
+ [self failClient:client withResponse:tooLarge];
409
+ return NO;
410
+ }
411
+ *outBodyLength = contentLength;
412
+ return YES;
413
+ }
414
+
415
+ // Parses the request line and headers of the request at the head of the buffer. Returns nil
416
+ // while the header block is still incomplete, and for a rejected one, which is answered here.
417
+ - (nullable AMPendingHTTPRequestHeader *)parsedRequestHeaderFromBuffer:(NSMutableData *)buffer
418
+ forClient:(nw_connection_t)client
419
+ {
420
+ NSRange headerEndRange;
421
+ if (![self findHeaderBlockEnd:&headerEndRange inBuffer:buffer forClient:client]) {
422
+ return nil;
423
+ }
341
424
 
342
- [self dispatchMethod:pending.method pathAndQuery:pending.pathAndQuery body:body client:client];
425
+ NSData *headerData = [buffer subdataWithRange:NSMakeRange(0, headerEndRange.location)];
426
+ NSString *headerString = [[NSString alloc] initWithData:headerData encoding:NSUTF8StringEncoding];
427
+ NSArray<NSString *> *lines = [headerString componentsSeparatedByString:@"\r\n"];
428
+ if (lines.count < 1) {
429
+ [self respondBadRequestToClient:client];
430
+ return nil;
343
431
  }
432
+
433
+ NSArray<NSString *> *requestLineParts = [lines.firstObject componentsSeparatedByString:@" "];
434
+ if (requestLineParts.count < 2) {
435
+ [self respondBadRequestToClient:client];
436
+ return nil;
437
+ }
438
+
439
+ NSDictionary<NSString *, NSString *> *requestHeaders = [self parsedHeaderFieldsFromLines:lines forClient:client];
440
+ if (nil == requestHeaders) {
441
+ return nil;
442
+ }
443
+ NSUInteger contentLength = 0;
444
+ if (![self resolveBodyLength:&contentLength fromHeaderFields:requestHeaders forClient:client]) {
445
+ return nil;
446
+ }
447
+
448
+ AMPendingHTTPRequestHeader *pending = [AMPendingHTTPRequestHeader new];
449
+ pending.method = requestLineParts[0].uppercaseString;
450
+ pending.pathAndQuery = requestLineParts[1];
451
+ pending.bodyStart = headerEndRange.location + headerEndRange.length;
452
+ pending.contentLength = contentLength;
453
+ return pending;
454
+ }
455
+
456
+ // Consumes the already-parsed request from the head of the buffer and dispatches it, once its
457
+ // whole body has arrived. Leaves the cached header in place and returns NO while it hasn't, so
458
+ // the caller's pipelining loop knows to stop rather than re-checking the same unchanged buffer.
459
+ - (BOOL)dispatchBufferedRequestWithHeader:(AMPendingHTTPRequestHeader *)pending
460
+ fromBuffer:(NSMutableData *)buffer
461
+ forClient:(nw_connection_t)client
462
+ {
463
+ NSUInteger totalRequestLength = pending.bodyStart + pending.contentLength;
464
+ if (buffer.length < totalRequestLength) {
465
+ // Wait for the rest of the body to arrive - the parsed header stays cached, so this
466
+ // doesn't re-scan/re-parse the header block on every subsequently arriving chunk.
467
+ return NO;
468
+ }
469
+
470
+ NSData *body = pending.contentLength > 0 ? [buffer subdataWithRange:NSMakeRange(pending.bodyStart, pending.contentLength)] : [NSData data];
471
+
472
+ @synchronized (self.connectionBuffers) {
473
+ [buffer replaceBytesInRange:NSMakeRange(0, totalRequestLength) withBytes:NULL length:0];
474
+ [self.pendingRequestHeaders removeObjectForKey:client];
475
+ }
476
+
477
+ [self dispatchMethod:pending.method pathAndQuery:pending.pathAndQuery body:body client:client];
478
+ return YES;
344
479
  }
345
480
 
346
481
  // Removes the client's buffered state and responds with a closing error response. Removing the
@@ -359,7 +494,7 @@ static NSData * _Nonnull AMUTF8Data(NSString *string)
359
494
  - (void)respondBadRequestToClient:(nw_connection_t)client
360
495
  {
361
496
  RouteResponse *badRequest = [RouteResponse new];
362
- id<FBResponsePayload> payload = FBResponseWithStatus([FBCommandStatus unknownCommandErrorWithMessage:@"The request could not be parsed as valid HTTP"
497
+ id<FBResponsePayload> payload = FBResponseWithStatus([FBCommandStatus invalidArgumentErrorWithMessage:@"The request could not be parsed as valid HTTP"
363
498
  traceback:nil]);
364
499
  [payload dispatchWithResponse:badRequest];
365
500
  [self failClient:client withResponse:badRequest];
@@ -8,8 +8,10 @@
8
8
 
9
9
  /* Begin PBXBuildFile section */
10
10
  06865ADF2DB5D6F7819CE2A8 /* AMTCPSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 702867B5FC5F035D1CC8E596 /* AMTCPSocket.h */; };
11
+ 1E964A1C6D82FF8B9E17C024 /* AMHTTPServerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6AFF6D8DC9CE6831D94DFA00 /* AMHTTPServerTests.m */; };
11
12
  2A45B1885FA76B1DE65D4E09 /* AMHTTPServer.h in Headers */ = {isa = PBXBuildFile; fileRef = B1768D9362DADEAF91410A76 /* AMHTTPServer.h */; };
12
13
  5EF3E477CF0A6BC92AE1338B /* RouteRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 56444252148A6377AB34CC3B /* RouteRequest.m */; };
14
+ 6997C4841DC0CE773A10731D /* WebDriverAgentLib.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7199B3AB2565B122000B5C51 /* WebDriverAgentLib.framework */; };
13
15
  7109BFB02565B413006BFD13 /* WebDriverAgentLib.h in Headers */ = {isa = PBXBuildFile; fileRef = 71688AD2256465540007F55B /* WebDriverAgentLib.h */; settings = {ATTRIBUTES = (Public, ); }; };
14
16
  7109BFB32565B4EA006BFD13 /* FBConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 7151AD932564F56F008B8B2A /* FBConfiguration.h */; settings = {ATTRIBUTES = (Public, ); }; };
15
17
  7109BFB62565B4F0006BFD13 /* FBClassChainQueryParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 7151AD7B2564F56E008B8B2A /* FBClassChainQueryParser.h */; };
@@ -193,6 +195,7 @@
193
195
  AA013B2B4F9CF195D153D94C /* RouteResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = A5BB9951BC45450114B976DD /* RouteResponse.h */; };
194
196
  B97F87AC2D986C39BAEF30F3 /* RouteRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = ED274030E15F4C90E5CD11EE /* RouteRequest.h */; };
195
197
  C4C81277CD6B2937B649C04A /* AMTCPSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 56885A73AAD5DB0A05C9882D /* AMTCPSocket.m */; };
198
+ EC97F434A6E444D0EAB3AB32 /* WebDriverAgentLib.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = 7199B3AB2565B122000B5C51 /* WebDriverAgentLib.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
196
199
  /* End PBXBuildFile section */
197
200
 
198
201
  /* Begin PBXContainerItemProxy section */
@@ -217,9 +220,27 @@
217
220
  remoteGlobalIDString = 7199B3AA2565B122000B5C51;
218
221
  remoteInfo = WebDriverAgentLib;
219
222
  };
223
+ D0BAF1395D24CD4AA02D61E8 /* PBXContainerItemProxy */ = {
224
+ isa = PBXContainerItemProxy;
225
+ containerPortal = 71688A8B256461ED0007F55B /* Project object */;
226
+ proxyType = 1;
227
+ remoteGlobalIDString = 7199B3AA2565B122000B5C51;
228
+ remoteInfo = WebDriverAgentLib;
229
+ };
220
230
  /* End PBXContainerItemProxy section */
221
231
 
222
232
  /* Begin PBXCopyFilesBuildPhase section */
233
+ 30933FC80D3E5A6F006999AA /* Copy Frameworks */ = {
234
+ isa = PBXCopyFilesBuildPhase;
235
+ buildActionMask = 2147483647;
236
+ dstPath = "";
237
+ dstSubfolderSpec = 10;
238
+ files = (
239
+ EC97F434A6E444D0EAB3AB32 /* WebDriverAgentLib.framework in Copy Frameworks */,
240
+ );
241
+ name = "Copy Frameworks";
242
+ runOnlyForDeploymentPostprocessing = 0;
243
+ };
223
244
  7199B3A12565B099000B5C51 /* Copy Frameworks */ = {
224
245
  isa = PBXCopyFilesBuildPhase;
225
246
  buildActionMask = 2147483647;
@@ -236,6 +257,7 @@
236
257
  /* Begin PBXFileReference section */
237
258
  56444252148A6377AB34CC3B /* RouteRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = RouteRequest.m; sourceTree = "<group>"; };
238
259
  56885A73AAD5DB0A05C9882D /* AMTCPSocket.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = AMTCPSocket.m; sourceTree = "<group>"; };
260
+ 6AFF6D8DC9CE6831D94DFA00 /* AMHTTPServerTests.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = AMHTTPServerTests.m; sourceTree = "<group>"; };
239
261
  702867B5FC5F035D1CC8E596 /* AMTCPSocket.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = AMTCPSocket.h; sourceTree = "<group>"; };
240
262
  710527DC2565716600130763 /* FBRouteRequest-Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "FBRouteRequest-Private.h"; sourceTree = "<group>"; };
241
263
  710527E82565731200130763 /* NSPredicate+FBFormat.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSPredicate+FBFormat.m"; sourceTree = "<group>"; };
@@ -428,8 +450,10 @@
428
450
  71E109202D55EBD0008A800D /* AMScreenUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AMScreenUtils.h; sourceTree = "<group>"; };
429
451
  71E109212D55EBD0008A800D /* AMScreenUtils.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AMScreenUtils.m; sourceTree = "<group>"; };
430
452
  99A3E0766E623F457DF47C5D /* RouteResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = RouteResponse.m; sourceTree = "<group>"; };
453
+ A14FCEABDDD9E126A7774B1F /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
431
454
  A5BB9951BC45450114B976DD /* RouteResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = RouteResponse.h; sourceTree = "<group>"; };
432
455
  A82A3B74608C4054AD527A2F /* AMHTTPServer.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = AMHTTPServer.m; sourceTree = "<group>"; };
456
+ AD7D1A66C8DAB1C268B560CA /* UnitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
433
457
  B1768D9362DADEAF91410A76 /* AMHTTPServer.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = AMHTTPServer.h; sourceTree = "<group>"; };
434
458
  ED274030E15F4C90E5CD11EE /* RouteRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = RouteRequest.h; sourceTree = "<group>"; };
435
459
  /* End PBXFileReference section */
@@ -468,6 +492,14 @@
468
492
  );
469
493
  runOnlyForDeploymentPostprocessing = 0;
470
494
  };
495
+ AE0CB8E86D0645D49C257555 /* Frameworks */ = {
496
+ isa = PBXFrameworksBuildPhase;
497
+ buildActionMask = 2147483647;
498
+ files = (
499
+ 6997C4841DC0CE773A10731D /* WebDriverAgentLib.framework in Frameworks */,
500
+ );
501
+ runOnlyForDeploymentPostprocessing = 0;
502
+ };
471
503
  /* End PBXFrameworksBuildPhase section */
472
504
 
473
505
  /* Begin PBXGroup section */
@@ -480,6 +512,7 @@
480
512
  71B00E8C2566D4B90010DA73 /* IntegrationTests */,
481
513
  71688A94256461ED0007F55B /* Products */,
482
514
  71688AE1256466070007F55B /* Frameworks */,
515
+ F77F404560B8EFCDBD22CC9B /* WebDriverAgentTests */,
483
516
  );
484
517
  sourceTree = "<group>";
485
518
  };
@@ -490,6 +523,7 @@
490
523
  71688B1425646A620007F55B /* WebDriverAgentRunner.xctest */,
491
524
  7199B3AB2565B122000B5C51 /* WebDriverAgentLib.framework */,
492
525
  71B00E8B2566D4B90010DA73 /* IntegrationTests.xctest */,
526
+ AD7D1A66C8DAB1C268B560CA /* UnitTests.xctest */,
493
527
  );
494
528
  name = Products;
495
529
  sourceTree = "<group>";
@@ -519,6 +553,7 @@
519
553
  714CA709256648A100353B27 /* libxml2.tbd */,
520
554
  71688AE2256466070007F55B /* XCTest.framework */,
521
555
  71AB00032BD1345000997FF4 /* WebKit.framework */,
556
+ 93D73A724C72B50CCADD9BD6 /* OS X */,
522
557
  );
523
558
  name = Frameworks;
524
559
  sourceTree = "<group>";
@@ -779,6 +814,32 @@
779
814
  path = IntegrationTests;
780
815
  sourceTree = "<group>";
781
816
  };
817
+ 93D73A724C72B50CCADD9BD6 /* OS X */ = {
818
+ isa = PBXGroup;
819
+ children = (
820
+ );
821
+ name = "OS X";
822
+ sourceTree = "<group>";
823
+ };
824
+ F77F404560B8EFCDBD22CC9B /* WebDriverAgentTests */ = {
825
+ isa = PBXGroup;
826
+ children = (
827
+ FF0F816A2EB08456B7F8C045 /* UnitTests */,
828
+ );
829
+ name = WebDriverAgentTests;
830
+ path = WebDriverAgentTests;
831
+ sourceTree = "<group>";
832
+ };
833
+ FF0F816A2EB08456B7F8C045 /* UnitTests */ = {
834
+ isa = PBXGroup;
835
+ children = (
836
+ 6AFF6D8DC9CE6831D94DFA00 /* AMHTTPServerTests.m */,
837
+ A14FCEABDDD9E126A7774B1F /* Info.plist */,
838
+ );
839
+ name = UnitTests;
840
+ path = UnitTests;
841
+ sourceTree = "<group>";
842
+ };
782
843
  /* End PBXGroup section */
783
844
 
784
845
  /* Begin PBXHeadersBuildPhase section */
@@ -879,6 +940,25 @@
879
940
  /* End PBXHeadersBuildPhase section */
880
941
 
881
942
  /* Begin PBXNativeTarget section */
943
+ 550AA1D432DA6EF84D8CD38B /* UnitTests */ = {
944
+ isa = PBXNativeTarget;
945
+ buildConfigurationList = 86DE81E53D912630D97F78C9 /* Build configuration list for PBXNativeTarget "UnitTests" */;
946
+ buildPhases = (
947
+ 3C76651A5497FBB07664E310 /* Sources */,
948
+ AE0CB8E86D0645D49C257555 /* Frameworks */,
949
+ A624E42CFD2C0619F15A83CF /* Resources */,
950
+ 30933FC80D3E5A6F006999AA /* Copy Frameworks */,
951
+ );
952
+ buildRules = (
953
+ );
954
+ dependencies = (
955
+ 09EA511E88960E3AC163573B /* PBXTargetDependency */,
956
+ );
957
+ name = UnitTests;
958
+ productName = UnitTests;
959
+ productReference = AD7D1A66C8DAB1C268B560CA /* UnitTests.xctest */;
960
+ productType = "com.apple.product-type.bundle.unit-test";
961
+ };
882
962
  71688A92256461ED0007F55B /* WebDriverAgent */ = {
883
963
  isa = PBXNativeTarget;
884
964
  buildConfigurationList = 71688ABD256461F00007F55B /* Build configuration list for PBXNativeTarget "WebDriverAgent" */;
@@ -992,6 +1072,7 @@
992
1072
  71688B1325646A620007F55B /* WebDriverAgentRunner */,
993
1073
  7199B3AA2565B122000B5C51 /* WebDriverAgentLib */,
994
1074
  71B00E8A2566D4B90010DA73 /* IntegrationTests */,
1075
+ 550AA1D432DA6EF84D8CD38B /* UnitTests */,
995
1076
  );
996
1077
  };
997
1078
  /* End PBXProject section */
@@ -1027,9 +1108,24 @@
1027
1108
  );
1028
1109
  runOnlyForDeploymentPostprocessing = 0;
1029
1110
  };
1111
+ A624E42CFD2C0619F15A83CF /* Resources */ = {
1112
+ isa = PBXResourcesBuildPhase;
1113
+ buildActionMask = 2147483647;
1114
+ files = (
1115
+ );
1116
+ runOnlyForDeploymentPostprocessing = 0;
1117
+ };
1030
1118
  /* End PBXResourcesBuildPhase section */
1031
1119
 
1032
1120
  /* Begin PBXSourcesBuildPhase section */
1121
+ 3C76651A5497FBB07664E310 /* Sources */ = {
1122
+ isa = PBXSourcesBuildPhase;
1123
+ buildActionMask = 2147483647;
1124
+ files = (
1125
+ 1E964A1C6D82FF8B9E17C024 /* AMHTTPServerTests.m in Sources */,
1126
+ );
1127
+ runOnlyForDeploymentPostprocessing = 0;
1128
+ };
1033
1129
  71688A8F256461ED0007F55B /* Sources */ = {
1034
1130
  isa = PBXSourcesBuildPhase;
1035
1131
  buildActionMask = 2147483647;
@@ -1152,6 +1248,12 @@
1152
1248
  /* End PBXSourcesBuildPhase section */
1153
1249
 
1154
1250
  /* Begin PBXTargetDependency section */
1251
+ 09EA511E88960E3AC163573B /* PBXTargetDependency */ = {
1252
+ isa = PBXTargetDependency;
1253
+ name = WebDriverAgentLib;
1254
+ target = 7199B3AA2565B122000B5C51 /* WebDriverAgentLib */;
1255
+ targetProxy = D0BAF1395D24CD4AA02D61E8 /* PBXContainerItemProxy */;
1256
+ };
1155
1257
  7199B3D22565B243000B5C51 /* PBXTargetDependency */ = {
1156
1258
  isa = PBXTargetDependency;
1157
1259
  target = 7199B3AA2565B122000B5C51 /* WebDriverAgentLib */;
@@ -1181,6 +1283,28 @@
1181
1283
  /* End PBXVariantGroup section */
1182
1284
 
1183
1285
  /* Begin XCBuildConfiguration section */
1286
+ 56A3849C69FC9B9017E26C88 /* Debug */ = {
1287
+ isa = XCBuildConfiguration;
1288
+ buildSettings = {
1289
+ CLANG_ENABLE_OBJC_WEAK = NO;
1290
+ CODE_SIGN_IDENTITY = "-";
1291
+ CODE_SIGN_STYLE = Automatic;
1292
+ COMBINE_HIDPI_IMAGES = YES;
1293
+ DEVELOPMENT_TEAM = "";
1294
+ INFOPLIST_FILE = WebDriverAgentTests/UnitTests/Info.plist;
1295
+ LD_RUNPATH_SEARCH_PATHS = (
1296
+ "$(inherited)",
1297
+ "@executable_path/../Frameworks",
1298
+ "@loader_path/../Frameworks",
1299
+ );
1300
+ MACOSX_DEPLOYMENT_TARGET = 10.15;
1301
+ "MACOSX_DEPLOYMENT_TARGET[sdk=macosx27.*]" = 12.0;
1302
+ PRODUCT_BUNDLE_IDENTIFIER = io.appium.UnitTests;
1303
+ PRODUCT_NAME = "$(TARGET_NAME)";
1304
+ SDKROOT = macosx;
1305
+ };
1306
+ name = Debug;
1307
+ };
1184
1308
  71688ABB256461F00007F55B /* Debug */ = {
1185
1309
  isa = XCBuildConfiguration;
1186
1310
  buildSettings = {
@@ -1456,6 +1580,28 @@
1456
1580
  };
1457
1581
  name = Release;
1458
1582
  };
1583
+ 9B2802616BB30012798E813C /* Release */ = {
1584
+ isa = XCBuildConfiguration;
1585
+ buildSettings = {
1586
+ CLANG_ENABLE_OBJC_WEAK = NO;
1587
+ CODE_SIGN_IDENTITY = "-";
1588
+ CODE_SIGN_STYLE = Automatic;
1589
+ COMBINE_HIDPI_IMAGES = YES;
1590
+ DEVELOPMENT_TEAM = "";
1591
+ INFOPLIST_FILE = WebDriverAgentTests/UnitTests/Info.plist;
1592
+ LD_RUNPATH_SEARCH_PATHS = (
1593
+ "$(inherited)",
1594
+ "@executable_path/../Frameworks",
1595
+ "@loader_path/../Frameworks",
1596
+ );
1597
+ MACOSX_DEPLOYMENT_TARGET = 10.15;
1598
+ "MACOSX_DEPLOYMENT_TARGET[sdk=macosx27.*]" = 12.0;
1599
+ PRODUCT_BUNDLE_IDENTIFIER = io.appium.UnitTests;
1600
+ PRODUCT_NAME = "$(TARGET_NAME)";
1601
+ SDKROOT = macosx;
1602
+ };
1603
+ name = Release;
1604
+ };
1459
1605
  /* End XCBuildConfiguration section */
1460
1606
 
1461
1607
  /* Begin XCConfigurationList section */
@@ -1504,6 +1650,15 @@
1504
1650
  defaultConfigurationIsVisible = 0;
1505
1651
  defaultConfigurationName = Debug;
1506
1652
  };
1653
+ 86DE81E53D912630D97F78C9 /* Build configuration list for PBXNativeTarget "UnitTests" */ = {
1654
+ isa = XCConfigurationList;
1655
+ buildConfigurations = (
1656
+ 9B2802616BB30012798E813C /* Release */,
1657
+ 56A3849C69FC9B9017E26C88 /* Debug */,
1658
+ );
1659
+ defaultConfigurationIsVisible = 0;
1660
+ defaultConfigurationName = Release;
1661
+ };
1507
1662
  /* End XCConfigurationList section */
1508
1663
  };
1509
1664
  rootObject = 71688A8B256461ED0007F55B /* Project object */;
@@ -0,0 +1,69 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <Scheme
3
+ LastUpgradeVersion = "1210"
4
+ version = "1.3">
5
+ <BuildAction
6
+ parallelizeBuildables = "YES"
7
+ buildImplicitDependencies = "YES">
8
+ <BuildActionEntries>
9
+ <BuildActionEntry
10
+ buildForTesting = "YES"
11
+ buildForRunning = "NO"
12
+ buildForProfiling = "NO"
13
+ buildForArchiving = "NO"
14
+ buildForAnalyzing = "YES">
15
+ <BuildableReference
16
+ BuildableIdentifier = "primary"
17
+ BlueprintIdentifier = "550AA1D432DA6EF84D8CD38B"
18
+ BuildableName = "UnitTests.xctest"
19
+ BlueprintName = "UnitTests"
20
+ ReferencedContainer = "container:WebDriverAgentMac.xcodeproj">
21
+ </BuildableReference>
22
+ </BuildActionEntry>
23
+ </BuildActionEntries>
24
+ </BuildAction>
25
+ <TestAction
26
+ buildConfiguration = "Debug"
27
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
28
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
29
+ shouldUseLaunchSchemeArgsEnv = "YES"
30
+ systemAttachmentLifetime = "keepNever">
31
+ <Testables>
32
+ <TestableReference
33
+ skipped = "NO">
34
+ <BuildableReference
35
+ BuildableIdentifier = "primary"
36
+ BlueprintIdentifier = "550AA1D432DA6EF84D8CD38B"
37
+ BuildableName = "UnitTests.xctest"
38
+ BlueprintName = "UnitTests"
39
+ ReferencedContainer = "container:WebDriverAgentMac.xcodeproj">
40
+ </BuildableReference>
41
+ </TestableReference>
42
+ </Testables>
43
+ </TestAction>
44
+ <LaunchAction
45
+ buildConfiguration = "Debug"
46
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
47
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
48
+ launchStyle = "0"
49
+ useCustomWorkingDirectory = "NO"
50
+ ignoresPersistentStateOnLaunch = "NO"
51
+ debugDocumentVersioning = "YES"
52
+ debugServiceExtension = "internal"
53
+ allowLocationSimulation = "YES">
54
+ </LaunchAction>
55
+ <ProfileAction
56
+ buildConfiguration = "Release"
57
+ shouldUseLaunchSchemeArgsEnv = "YES"
58
+ savedToolIdentifier = ""
59
+ useCustomWorkingDirectory = "NO"
60
+ debugDocumentVersioning = "YES">
61
+ </ProfileAction>
62
+ <AnalyzeAction
63
+ buildConfiguration = "Debug">
64
+ </AnalyzeAction>
65
+ <ArchiveAction
66
+ buildConfiguration = "Release"
67
+ revealArchiveInOrganizer = "YES">
68
+ </ArchiveAction>
69
+ </Scheme>
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "appium-mac2-driver",
3
- "version": "4.3.3",
3
+ "version": "4.3.4",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "appium-mac2-driver",
9
- "version": "4.3.3",
9
+ "version": "4.3.4",
10
10
  "license": "Apache-2.0",
11
11
  "dependencies": {
12
12
  "@appium/strongbox": "^2.0.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "appium-mac2-driver",
3
- "version": "4.3.3",
3
+ "version": "4.3.4",
4
4
  "description": "XCTest-based Appium driver for macOS apps automation",
5
5
  "keywords": [
6
6
  "XCTest",