FIRStorageMetadata.m 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. // Copyright 2017 Google
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #import "FIRStorageMetadata.h"
  15. #import "FIRStorageConstants.h"
  16. #import "FIRStorageConstants_Private.h"
  17. #import "FIRStorageMetadata_Private.h"
  18. #import "FIRStorageUtils.h"
  19. // TODO: consider rewriting this using GTLR (GTLRStorageObjects.h)
  20. @implementation FIRStorageMetadata
  21. #pragma mark - Initializers
  22. - (instancetype)init {
  23. return [self initWithDictionary:[NSDictionary dictionary]];
  24. }
  25. - (instancetype)initWithDictionary:(NSDictionary *)dictionary {
  26. self = [super init];
  27. if (self) {
  28. _bucket = dictionary[kFIRStorageMetadataBucket];
  29. _cacheControl = dictionary[kFIRStorageMetadataCacheControl];
  30. _contentDisposition = dictionary[kFIRStorageMetadataContentDisposition];
  31. _contentEncoding = dictionary[kFIRStorageMetadataContentEncoding];
  32. _contentLanguage = dictionary[kFIRStorageMetadataContentLanguage];
  33. _contentType = dictionary[kFIRStorageMetadataContentType];
  34. _customMetadata = dictionary[kFIRStorageMetadataCustomMetadata];
  35. _size = [dictionary[kFIRStorageMetadataSize] longLongValue];
  36. _downloadURLs = dictionary[kFIRStorageMetadataDownloadURLs];
  37. _generation = [dictionary[kFIRStorageMetadataGeneration] longLongValue];
  38. _metageneration = [dictionary[kFIRStorageMetadataMetageneration] longLongValue];
  39. _timeCreated = [self dateFromRFC3339String:dictionary[kFIRStorageMetadataTimeCreated]];
  40. _updated = [self dateFromRFC3339String:dictionary[kFIRStorageMetadataUpdated]];
  41. // GCS "name" is our path, our "name" is just the last path component of the path
  42. _path = dictionary[kFIRStorageMetadataName];
  43. _name = [_path lastPathComponent];
  44. NSString *downloadTokens = dictionary[kFIRStorageMetadataDownloadTokens];
  45. if (downloadTokens) {
  46. NSArray<NSString *> *downloadStringArray = [downloadTokens componentsSeparatedByString:@","];
  47. NSMutableArray<NSURL *> *downloadURLArray =
  48. [[NSMutableArray alloc] initWithCapacity:[downloadStringArray count]];
  49. [downloadStringArray enumerateObjectsUsingBlock:^(NSString *_Nonnull token, NSUInteger idx,
  50. BOOL *_Nonnull stop) {
  51. NSURLComponents *components = [[NSURLComponents alloc] init];
  52. components.scheme = kFIRStorageScheme;
  53. components.host = kFIRStorageHost;
  54. NSString *path = [FIRStorageUtils GCSEscapedString:_path];
  55. NSString *fullPath = [NSString stringWithFormat:kFIRStorageFullPathFormat, _bucket, path];
  56. components.percentEncodedPath = fullPath;
  57. components.query = [NSString stringWithFormat:@"alt=media&token=%@", token];
  58. [downloadURLArray insertObject:[components URL] atIndex:idx];
  59. }];
  60. _downloadURLs = downloadURLArray;
  61. }
  62. }
  63. return self;
  64. }
  65. #pragma mark - NSObject overrides
  66. - (instancetype)copyWithZone:(NSZone *)zone {
  67. return [[[self class] allocWithZone:zone] initWithDictionary:[self dictionaryRepresentation]];
  68. }
  69. - (BOOL)isEqual:(id)object {
  70. if (self == object) {
  71. return YES;
  72. }
  73. if (![object isKindOfClass:[FIRStorageMetadata class]]) {
  74. return NO;
  75. }
  76. BOOL isEqualObject = [self isEqualToFIRStorageMetadata:(FIRStorageMetadata *)object];
  77. return isEqualObject;
  78. }
  79. - (BOOL)isEqualToFIRStorageMetadata:(FIRStorageMetadata *)metadata {
  80. return [[self dictionaryRepresentation] isEqualToDictionary:[metadata dictionaryRepresentation]];
  81. }
  82. - (NSUInteger)hash {
  83. NSUInteger hash = [[self dictionaryRepresentation] hash];
  84. return hash;
  85. }
  86. - (NSString *)description {
  87. NSDictionary *metadataDictionary = [self dictionaryRepresentation];
  88. return [NSString stringWithFormat:@"%@ %p: %@", [self class], self, metadataDictionary];
  89. }
  90. #pragma mark - Public methods
  91. - (NSDictionary *)dictionaryRepresentation {
  92. NSMutableDictionary *metadataDictionary = [[NSMutableDictionary alloc] initWithCapacity:13];
  93. if (_bucket) {
  94. metadataDictionary[kFIRStorageMetadataBucket] = _bucket;
  95. }
  96. if (_cacheControl) {
  97. metadataDictionary[kFIRStorageMetadataCacheControl] = _cacheControl;
  98. }
  99. if (_contentDisposition) {
  100. metadataDictionary[kFIRStorageMetadataContentDisposition] = _contentDisposition;
  101. }
  102. if (_contentEncoding) {
  103. metadataDictionary[kFIRStorageMetadataContentEncoding] = _contentEncoding;
  104. }
  105. if (_contentLanguage) {
  106. metadataDictionary[kFIRStorageMetadataContentLanguage] = _contentLanguage;
  107. }
  108. if (_contentType) {
  109. metadataDictionary[kFIRStorageMetadataContentType] = _contentType;
  110. }
  111. if (_customMetadata) {
  112. metadataDictionary[kFIRStorageMetadataCustomMetadata] = _customMetadata;
  113. }
  114. if (_downloadURLs) {
  115. NSMutableArray *downloadTokens = [[NSMutableArray alloc] init];
  116. [_downloadURLs
  117. enumerateObjectsUsingBlock:^(NSURL *_Nonnull URL, NSUInteger idx, BOOL *_Nonnull stop) {
  118. NSArray *queryItems = [URL.query componentsSeparatedByString:@"&"];
  119. [queryItems enumerateObjectsUsingBlock:^(NSString *queryString, NSUInteger idx,
  120. BOOL *_Nonnull stop) {
  121. NSString *key;
  122. NSString *value;
  123. NSScanner *scanner = [NSScanner scannerWithString:queryString];
  124. [scanner scanUpToString:@"=" intoString:&key];
  125. [scanner scanString:@"=" intoString:NULL];
  126. [scanner scanUpToString:@"\n" intoString:&value];
  127. if ([key isEqual:@"token"]) {
  128. [downloadTokens addObject:value];
  129. *stop = YES;
  130. }
  131. }];
  132. }];
  133. NSString *downloadTokenString = [downloadTokens componentsJoinedByString:@","];
  134. metadataDictionary[kFIRStorageMetadataDownloadTokens] = downloadTokenString;
  135. }
  136. if (_generation) {
  137. NSString *generationString = [NSString stringWithFormat:@"%lld", _generation];
  138. metadataDictionary[kFIRStorageMetadataGeneration] = generationString;
  139. }
  140. if (_metageneration) {
  141. NSString *metagenerationString = [NSString stringWithFormat:@"%lld", _metageneration];
  142. metadataDictionary[kFIRStorageMetadataMetageneration] = metagenerationString;
  143. }
  144. if (_timeCreated) {
  145. metadataDictionary[kFIRStorageMetadataTimeCreated] = [self RFC3339StringFromDate:_timeCreated];
  146. }
  147. if (_updated) {
  148. metadataDictionary[kFIRStorageMetadataUpdated] = [self RFC3339StringFromDate:_updated];
  149. }
  150. if (_path) {
  151. metadataDictionary[kFIRStorageMetadataName] = _path;
  152. }
  153. return [metadataDictionary copy];
  154. }
  155. - (BOOL)isFile {
  156. return _type == FIRStorageMetadataTypeFile;
  157. }
  158. - (BOOL)isFolder {
  159. return _type == FIRStorageMetadataTypeFolder;
  160. }
  161. - (nullable NSURL *)downloadURL {
  162. return [_downloadURLs firstObject];
  163. }
  164. #pragma mark - RFC 3339 conversions
  165. static NSDateFormatter *sRFC3339DateFormatter;
  166. static void setupDateFormatterOnce(void) {
  167. static dispatch_once_t onceToken;
  168. dispatch_once(&onceToken, ^{
  169. sRFC3339DateFormatter = [[NSDateFormatter alloc] init];
  170. NSLocale *enUSPOSIXLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
  171. [sRFC3339DateFormatter setLocale:enUSPOSIXLocale];
  172. [sRFC3339DateFormatter setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ss.SSSZZZZZ"];
  173. [sRFC3339DateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
  174. });
  175. }
  176. - (nullable NSDate *)dateFromRFC3339String:(NSString *)dateString {
  177. setupDateFormatterOnce();
  178. NSDate *rfc3339Date = [sRFC3339DateFormatter dateFromString:dateString];
  179. return rfc3339Date;
  180. }
  181. - (nullable NSString *)RFC3339StringFromDate:(NSDate *)date {
  182. setupDateFormatterOnce();
  183. NSString *rfc3339String = [sRFC3339DateFormatter stringFromDate:date];
  184. return rfc3339String;
  185. }
  186. @end