appium-webdriveragent 16.13.0 → 16.13.2

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,15 @@
1
+ ## [16.13.2](https://github.com/appium/WebDriverAgent/compare/v16.13.1...v16.13.2) (2026-09-30)
2
+
3
+ ### Bug Fixes
4
+
5
+ * process received HTTP bytes before handling EOF ([#1277](https://github.com/appium/WebDriverAgent/issues/1277)) ([203fc4f](https://github.com/appium/WebDriverAgent/commit/203fc4f012ab1d90caf0127fe85f119ad85cb0e8))
6
+
7
+ ## [16.13.1](https://github.com/appium/WebDriverAgent/compare/v16.13.0...v16.13.1) (2026-09-30)
8
+
9
+ ### Performance Improvements
10
+
11
+ * reuse sibling indices and geometry during XML serialization ([#1283](https://github.com/appium/WebDriverAgent/issues/1283)) ([f352660](https://github.com/appium/WebDriverAgent/commit/f352660deb52728c195a875b4172e38e1a1496b8))
12
+
1
13
  ## [16.13.0](https://github.com/appium/WebDriverAgent/compare/v16.12.11...v16.13.0) (2026-09-30)
2
14
 
3
15
  ### Features
@@ -15,11 +15,11 @@
15
15
  <key>CFBundlePackageType</key>
16
16
  <string>FMWK</string>
17
17
  <key>CFBundleShortVersionString</key>
18
- <string>16.13.0</string>
18
+ <string>16.13.2</string>
19
19
  <key>CFBundleSignature</key>
20
20
  <string>????</string>
21
21
  <key>CFBundleVersion</key>
22
- <string>16.13.0</string>
22
+ <string>16.13.2</string>
23
23
  <key>NSPrincipalClass</key>
24
24
  <string/>
25
25
  </dict>
@@ -340,18 +340,28 @@ static const int64_t FBStaleConnectionSweepIntervalSec = 10;
340
340
 
341
341
  - (void)didClientDisconnect:(nw_connection_t)client
342
342
  {
343
- BOOL isAwaitingResponse;
344
- @synchronized (self.connectionBuffers) {
345
- isAwaitingResponse = [self.connectionsAwaitingResponse containsObject:client];
346
- [self.connectionBuffers removeObjectForKey:client];
347
- [self.pendingRequestHeaders removeObjectForKey:client];
348
- [self.incompleteRequestStarts removeObjectForKey:client];
349
- }
350
- // A client that only stopped sending may still read the response to its in-flight request, so
351
- // that response's send completion closes the connection instead (it finds no buffer left).
352
- if (!isAwaitingResponse) {
353
- nw_connection_cancel(client);
354
- }
343
+ // EOF must follow every receive already queued for this client. Otherwise it can
344
+ // remove the buffer before those bytes have even been appended and parsed.
345
+ __weak typeof(self) weakSelf = self;
346
+ dispatch_async(self.bufferProcessingQueue, ^{
347
+ __strong typeof(weakSelf) strongSelf = weakSelf;
348
+ if (nil == strongSelf) {
349
+ nw_connection_cancel(client);
350
+ return;
351
+ }
352
+ BOOL isAwaitingResponse;
353
+ @synchronized (strongSelf.connectionBuffers) {
354
+ isAwaitingResponse = [strongSelf.connectionsAwaitingResponse containsObject:client];
355
+ [strongSelf.connectionBuffers removeObjectForKey:client];
356
+ [strongSelf.pendingRequestHeaders removeObjectForKey:client];
357
+ [strongSelf.incompleteRequestStarts removeObjectForKey:client];
358
+ }
359
+ // A client that only stopped sending may still read the response to its in-flight request, so
360
+ // that response's send completion closes the connection instead (it finds no buffer left).
361
+ if (!isAwaitingResponse) {
362
+ nw_connection_cancel(client);
363
+ }
364
+ });
355
365
  }
356
366
 
357
367
  - (void)client:(nw_connection_t)client didReceiveData:(NSData *)data
@@ -504,6 +504,18 @@ static NSString *const topNodeIndexPath = @"top";
504
504
  indexPath:(nullable NSString *)indexPath
505
505
  includedAttributes:(nullable NSSet<Class> *)includedAttributes
506
506
  {
507
+ return [self recordElementAttributes:writer forElement:element indexPath:indexPath
508
+ includedAttributes:includedAttributes siblingIndex:nil];
509
+ }
510
+
511
+ + (int)recordElementAttributes:(xmlTextWriterPtr)writer
512
+ forElement:(id<FBXCElementSnapshot>)element
513
+ indexPath:(nullable NSString *)indexPath
514
+ includedAttributes:(nullable NSSet<Class> *)includedAttributes
515
+ siblingIndex:(nullable NSNumber *)siblingIndex
516
+ {
517
+ FBXCElementSnapshotWrapper *wrapped = [FBXCElementSnapshotWrapper ensureWrapped:element];
518
+ NSDictionary *rect = nil;
507
519
  for (Class attributeCls in FBElementAttribute.supportedAttributes) {
508
520
  // include all supported attributes by default unless enumerated explicitly
509
521
  if (includedAttributes && ![includedAttributes containsObject:attributeCls]) {
@@ -519,8 +531,15 @@ static NSString *const topNodeIndexPath = @"top";
519
531
  !FBDoesElementSupportMinMaxValue(element.elementType)) {
520
532
  continue;
521
533
  }
522
- int rc = [attributeCls recordWithWriter:writer
523
- forElement:[FBXCElementSnapshotWrapper ensureWrapped:element]];
534
+ int rc;
535
+ if (attributeCls == FBIndexAttribute.class && nil != siblingIndex) {
536
+ rc = [attributeCls recordWithWriter:writer forValue:siblingIndex.stringValue];
537
+ } else if ([attributeCls isSubclassOfClass:FBDimensionAttribute.class]) {
538
+ rect = rect ?: wrapped.wdRect;
539
+ rc = [attributeCls recordWithWriter:writer forValue:[rect[[attributeCls name]] description]];
540
+ } else {
541
+ rc = [attributeCls recordWithWriter:writer forElement:wrapped];
542
+ }
524
543
  if (rc < 0) {
525
544
  return rc;
526
545
  }
@@ -559,6 +578,17 @@ static NSString *const topNodeIndexPath = @"top";
559
578
  elementStore:(nullable NSMutableDictionary *)elementStore
560
579
  includedAttributes:(nullable NSSet<Class> *)includedAttributes
561
580
  writer:(xmlTextWriterPtr)writer
581
+ {
582
+ return [self writeXmlWithRootElement:root indexPath:indexPath elementStore:elementStore
583
+ includedAttributes:includedAttributes writer:writer siblingIndex:nil];
584
+ }
585
+
586
+ + (int)writeXmlWithRootElement:(id<FBXCElementSnapshot>)root
587
+ indexPath:(nullable NSString *)indexPath
588
+ elementStore:(nullable NSMutableDictionary *)elementStore
589
+ includedAttributes:(nullable NSSet<Class> *)includedAttributes
590
+ writer:(xmlTextWriterPtr)writer
591
+ siblingIndex:(nullable NSNumber *)siblingIndex
562
592
  {
563
593
  NSAssert((indexPath == nil && elementStore == nil) || (indexPath != nil && elementStore != nil), @"Either both or none of indexPath and elementStore arguments should be equal to nil", nil);
564
594
 
@@ -578,7 +608,8 @@ static NSString *const topNodeIndexPath = @"top";
578
608
  rc = [self recordElementAttributes:writer
579
609
  forElement:root
580
610
  indexPath:indexPath
581
- includedAttributes:includedAttributes];
611
+ includedAttributes:includedAttributes
612
+ siblingIndex:siblingIndex];
582
613
  if (rc < 0) {
583
614
  return rc;
584
615
  }
@@ -594,7 +625,8 @@ static NSString *const topNodeIndexPath = @"top";
594
625
  indexPath:newIndexPath
595
626
  elementStore:elementStore
596
627
  includedAttributes:includedAttributes
597
- writer:writer];
628
+ writer:writer
629
+ siblingIndex:@(i)];
598
630
  if (rc < 0) {
599
631
  return rc;
600
632
  }
@@ -14,6 +14,7 @@
14
14
  #import <unistd.h>
15
15
 
16
16
  #import "FBHTTPServer.h"
17
+ #import "FBTCPSocket.h"
17
18
 
18
19
  static atomic_int gFramingProbeHits;
19
20
 
@@ -242,6 +243,32 @@ static NSString *FBCompleteResponse(NSData *data)
242
243
  XCTAssertEqual([self serverSocketCountSettlingAt:baseline], baseline);
243
244
  }
244
245
 
246
+ - (void)testEofWaitsForPreviouslyReceivedBytesToBeParsed
247
+ {
248
+ FBHTTPServer *server = [FBHTTPServer new];
249
+ __block NSUInteger calls = 0;
250
+ [server get:@"/probe" withBlock:^(RouteRequest *request, RouteResponse *response) {
251
+ calls++;
252
+ }];
253
+ dispatch_queue_t queue = [server valueForKey:@"bufferProcessingQueue"];
254
+ nw_connection_t client = nw_connection_create(nw_endpoint_create_host("127.0.0.1", "1"),
255
+ nw_parameters_create_secure_tcp(NW_PARAMETERS_DISABLE_PROTOCOL, NW_PARAMETERS_DEFAULT_CONFIGURATION));
256
+ id<FBTCPSocketDelegate> delegate = (id)server;
257
+ [delegate didClientConnect:client];
258
+ dispatch_suspend(queue);
259
+ @try {
260
+ NSData *data = [@"GET /probe HTTP/1.1\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding];
261
+ [delegate client:client didReceiveData:data];
262
+ [delegate didClientDisconnect:client];
263
+ } @finally {
264
+ dispatch_resume(queue);
265
+ }
266
+ dispatch_sync(queue, ^{});
267
+ XCTAssertEqual(calls, 1u);
268
+ [server stop:YES];
269
+ nw_connection_cancel(client);
270
+ }
271
+
245
272
  - (void)testHalfClosedClientGetsItsResponseAndIsThenClosed
246
273
  {
247
274
  // A client may shut down its sending side right after the request and wait for the response.
@@ -16,11 +16,47 @@
16
16
  #import "FBXCElementSnapshotWrapper+Helpers.h"
17
17
  #import "XCTestPrivateSymbols.h"
18
18
 
19
+ @interface FBTraversalSnapshot : XCElementSnapshotDouble
20
+ @property (nonatomic, copy) NSArray *childSnapshots;
21
+ @property (nonatomic, weak) FBTraversalSnapshot *parentSnapshot;
22
+ @property (nonatomic) NSUInteger childrenReads;
23
+ @property (nonatomic) NSUInteger frameReads;
24
+ @end
25
+ @implementation FBTraversalSnapshot
26
+ - (NSArray *)children { self.childrenReads++; return self.childSnapshots ?: @[]; }
27
+ - (id)parent { return self.parentSnapshot; }
28
+ - (CGRect)frame { self.frameReads++; return CGRectMake(1, 2, 3, 4); }
29
+ @end
30
+
19
31
  @interface FBXPathTests : XCTestCase
20
32
  @end
21
33
 
22
34
  @implementation FBXPathTests
23
35
 
36
+ - (void)testSerializationVisitsSiblingListAndFrameOnce
37
+ {
38
+ FBTraversalSnapshot *root = [FBTraversalSnapshot new];
39
+ NSMutableArray *children = [NSMutableArray array];
40
+ for (NSUInteger index = 0; index < 64; index++) {
41
+ FBTraversalSnapshot *child = [FBTraversalSnapshot new];
42
+ child.parentSnapshot = root;
43
+ [children addObject:child];
44
+ }
45
+ root.childSnapshots = children;
46
+ NSString *query = @"//*[@index >= 0 and @x=1 and @y=2 and @width=3 and @height=4]";
47
+ xmlDocPtr doc = [self documentForSnapshot:root query:query];
48
+ @try {
49
+ XCTAssertEqual(root.childrenReads, 1u);
50
+ XCTAssertEqual(root.frameReads, 1u);
51
+ for (FBTraversalSnapshot *child in children) {
52
+ XCTAssertEqual(child.frameReads, 1u);
53
+ }
54
+ XCTAssertEqualObjects([self xpathStringResultForQuery:@"count(//*[@index=63])" document:doc], @"1");
55
+ } @finally {
56
+ xmlFreeDoc(doc);
57
+ }
58
+ }
59
+
24
60
  - (NSString *)xmlStringWithElement:(id<FBXCElementSnapshot>)snapshot
25
61
  xpathQuery:(nullable NSString *)query
26
62
  excludingAttributes:(nullable NSArray<NSString *> *)excludedAttributes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "appium-webdriveragent",
3
- "version": "16.13.0",
3
+ "version": "16.13.2",
4
4
  "description": "Package bundling WebDriverAgent",
5
5
  "keywords": [
6
6
  "Appium",