@@ -1594,56 +1594,65 @@ - (void)setSessionIdentifierInternal:(nullable NSString *)sessionIdentifier {
1594
1594
if (_sessionUserInfo == nil) {
1595
1595
// We'll return the metadata dictionary with internal keys removed. This avoids the user
1596
1596
// re-using the userInfo dictionary later and accidentally including the internal keys.
1597
+ // Just incase something got corrupted in storage and parsed back out differently, ensure
1598
+ // the api contract on types is still valid.
1597
1599
NSMutableDictionary *metadata = [[self sessionIdentifierMetadataUnsynchronized] mutableCopy];
1598
1600
NSSet *keysToRemove = [metadata keysOfEntriesPassingTest:^BOOL(id key, id obj, BOOL *stop) {
1599
- return [key hasPrefix:@"_"];
1601
+ return ![key isKindOfClass:[NSString class]] || ![obj isKindOfClass:[NSString class]] ||
1602
+ [key hasPrefix:@"_"];
1600
1603
}];
1601
- [metadata removeObjectsForKeys:[keysToRemove allObjects]];
1602
- if (metadata.count > 0) {
1603
- _sessionUserInfo = metadata;
1604
-
1605
1604
#if DEBUG
1605
+ // If we're pruning, give warnings about the things that were invalid as some bug has slipped
1606
+ // through.
1607
+ if (keysToRemove.count) {
1606
1608
[metadata enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj,
1607
1609
BOOL *_Nonnull stop) {
1608
- GTMSESSION_ASSERT_DEBUG([key isKindOfClass:[NSString class]],
1609
- @"sessionUserInfo keys must be NSStrings: %@", key);
1610
- if (![obj isKindOfClass:[NSString class]]) {
1611
- GTMSESSION_LOG_DEBUG(@"WARNING: sessionUserInfo included a non String value, this will "
1612
- @"be an error in the future: %@: %@",
1613
- key, obj);
1610
+ if (![key isKindOfClass:[NSString class]]) {
1611
+ GTMSESSION_LOG_DEBUG(
1612
+ @"InternalError: restoring sessionUserInfo is pruning a non String key: %@", key);
1613
+ } else if (![obj isKindOfClass:[NSString class]]) {
1614
+ GTMSESSION_LOG_DEBUG(
1615
+ @"InternalError: restoring sessionUserInfo is pruning a non String value: %@: %@",
1616
+ key, obj);
1614
1617
}
1615
1618
}];
1619
+ }
1616
1620
#endif // DEBUG
1621
+ [metadata removeObjectsForKeys:[keysToRemove allObjects]];
1622
+
1623
+ if (metadata.count > 0) {
1624
+ _sessionUserInfo = metadata;
1617
1625
}
1618
1626
}
1619
1627
return _sessionUserInfo;
1620
1628
} // @synchronized(self)
1621
1629
}
1622
1630
1623
1631
- (void)setSessionUserInfo:(nullable NSDictionary<NSString *, NSString *> *)dictionary {
1632
+ [dictionary enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj,
1633
+ BOOL *_Nonnull stop) {
1634
+ if (![key isKindOfClass:[NSString class]]) {
1635
+ [NSException raise:NSInvalidArgumentException
1636
+ format:@"sessionUserInfo keys must be NSStrings: %@", key];
1637
+ }
1638
+ if ([key hasPrefix:@"_"]) {
1639
+ [NSException
1640
+ raise:NSInvalidArgumentException
1641
+ format:
1642
+ @"sessionUserInfo keys starting with an underscore are reserved for the library: %@",
1643
+ key];
1644
+ }
1645
+ if (![obj isKindOfClass:[NSString class]]) {
1646
+ [NSException raise:NSInvalidArgumentException
1647
+ format:@"Values in sessionUserInfo must be NSStrings: %@: %@", key, obj];
1648
+ }
1649
+ }];
1650
+
1624
1651
@synchronized(self) {
1625
1652
GTMSessionMonitorSynchronized(self);
1626
1653
1627
1654
GTMSESSION_ASSERT_DEBUG(_sessionIdentifier == nil, @"Too late to assign userInfo");
1628
1655
_sessionUserInfo = dictionary;
1629
-
1630
- #if DEBUG
1631
- [dictionary enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj,
1632
- BOOL *_Nonnull stop) {
1633
- GTMSESSION_ASSERT_DEBUG([key isKindOfClass:[NSString class]],
1634
- @"sessionUserInfo keys must be NSStrings: %@", key);
1635
- if ([key hasPrefix:@"_"]) {
1636
- GTMSESSION_LOG_DEBUG(@"WARNING: sessionUserInfo keys starting with an underscore are "
1637
- @"reserved for the library, this will become an error in the future: "
1638
- @"%@: %@", key, obj);
1639
- }
1640
- if (![obj isKindOfClass:[NSString class]]) {
1641
- GTMSESSION_LOG_DEBUG(@"WARNING: sessionUserInfo included a non String value, this will be "
1642
- @"an error in the future: %@: %@",
1643
- key, obj);
1644
- }
1645
- }];
1646
- #endif // DEBUG
1647
1656
} // @synchronized(self)
1648
1657
}
1649
1658
@@ -1734,34 +1743,39 @@ - (NSString *)createSessionIdentifierWithMetadata:(nullable NSDictionary *)metad
1734
1743
_sessionIdentifier =
1735
1744
[NSString stringWithFormat:@"%@_%@", kGTMSessionIdentifierPrefix, _sessionIdentifierUUID];
1736
1745
1737
- #if DEBUG
1738
- // _sessionUserInfo was declared as `strong` (not `copy`, so it could have been modifed after
1739
- // having been set.
1740
- [_sessionUserInfo enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj,
1741
- BOOL *_Nonnull stop) {
1742
- GTMSESSION_ASSERT_DEBUG([key isKindOfClass:[NSString class]],
1743
- @"sessionUserInfo keys must be NSStrings: %@", key);
1744
- if ([key hasPrefix:@"_"]) {
1745
- GTMSESSION_LOG_DEBUG(@"WARNING: sessionUserInfo keys starting with an underscore are "
1746
- @"reserved for the library, this will become an error in the future: "
1747
- @"%@: %@", key, obj);
1748
- }
1749
- if (![obj isKindOfClass:[NSString class]]) {
1750
- GTMSESSION_LOG_DEBUG(@"WARNING: sessionUserInfo included a non String value, this will "
1751
- @"be an error in the future: %@: %@",
1752
- key, obj);
1753
- }
1754
- }];
1755
- #endif // DEBUG
1756
-
1757
1746
// Start with user-supplied keys so they cannot accidentally override the fetcher's keys.
1758
1747
NSMutableDictionary *metadataDict =
1759
1748
[NSMutableDictionary dictionaryWithDictionary:(NSDictionary *_Nonnull)_sessionUserInfo];
1760
1749
1750
+ // sessionUserInfo was declared as `strong` (not `copy`), so it could have been modifed after
1751
+ // having been set. So remove anything that breaks the contract.
1752
+ NSSet *keysToRemove = [metadataDict keysOfEntriesPassingTest:^BOOL(id key, id obj, BOOL *stop) {
1753
+ return ![key isKindOfClass:[NSString class]] || ![obj isKindOfClass:[NSString class]] ||
1754
+ [key hasPrefix:@"_"];
1755
+ }];
1756
+ #if DEBUG
1757
+ // If we're pruning, give warnings about the things that were invalid as some bug has slipped
1758
+ // through.
1759
+ if (keysToRemove.count) {
1760
+ [metadataDict enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj,
1761
+ BOOL *_Nonnull stop) {
1762
+ if (![key isKindOfClass:[NSString class]]) {
1763
+ GTMSESSION_LOG_DEBUG(
1764
+ @"Warning: sessionUserInfo has been modifed to include a non String key: %@", key);
1765
+ } else if (![obj isKindOfClass:[NSString class]]) {
1766
+ GTMSESSION_LOG_DEBUG(
1767
+ @"Warning: sessionUserInfo has been modifed to include a non String value: %@: %@",
1768
+ key, obj);
1769
+ }
1770
+ }];
1771
+ }
1772
+ #endif // DEBUG
1773
+ [metadataDict removeObjectsForKeys:[keysToRemove allObjects]];
1774
+
1761
1775
if (metadataToInclude) {
1762
1776
#if DEBUG
1763
- [metadataToInclude enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj,
1764
- BOOL * _Nonnull stop) {
1777
+ [metadataToInclude enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj,
1778
+ BOOL *_Nonnull stop) {
1765
1779
GTMSESSION_ASSERT_DEBUG([key isKindOfClass:[NSString class]],
1766
1780
@"metadataToInclude keys must be NSStrings: %@", key);
1767
1781
GTMSESSION_ASSERT_DEBUG([key hasPrefix:@"_"],
@@ -1774,7 +1788,7 @@ - (NSString *)createSessionIdentifierWithMetadata:(nullable NSDictionary *)metad
1774
1788
NSDictionary *defaultMetadataDict = [self sessionIdentifierDefaultMetadata];
1775
1789
if (defaultMetadataDict) {
1776
1790
#if DEBUG
1777
- [defaultMetadataDict enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj,
1791
+ [defaultMetadataDict enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj,
1778
1792
BOOL * _Nonnull stop) {
1779
1793
GTMSESSION_ASSERT_DEBUG([key isKindOfClass:[NSString class]],
1780
1794
@"defaultMetadataDict keys must be NSStrings: %@", key);
0 commit comments