From 2dd40e3abba3d3a5a949aa4980f741ae412147ba Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Mon, 9 Apr 2018 14:21:00 -0700 Subject: Removing FirebaseStorage.downloadURL --- Firebase/Storage/FIRStorageErrors.m | 11 ++ Firebase/Storage/FIRStorageGetDownloadURLTask.m | 113 +++++++++++++++++++++ Firebase/Storage/FIRStorageGetMetadataTask.m | 34 ++----- Firebase/Storage/FIRStorageMetadata.m | 48 --------- Firebase/Storage/FIRStorageReference.m | 16 ++- Firebase/Storage/FIRStorageUpdateMetadataTask.m | 34 ++----- Firebase/Storage/FIRStorageUploadTask.m | 9 +- .../Storage/Private/FIRStorageConstants_Private.h | 1 - Firebase/Storage/Private/FIRStorageErrors.h | 10 +- .../Storage/Private/FIRStorageGetDownloadURLTask.h | 37 +++++++ Firebase/Storage/Public/FIRStorageMetadata.h | 14 --- 11 files changed, 197 insertions(+), 130 deletions(-) create mode 100644 Firebase/Storage/FIRStorageGetDownloadURLTask.m create mode 100644 Firebase/Storage/Private/FIRStorageGetDownloadURLTask.h (limited to 'Firebase/Storage') diff --git a/Firebase/Storage/FIRStorageErrors.m b/Firebase/Storage/FIRStorageErrors.m index ecfae02..7cc4beb 100644 --- a/Firebase/Storage/FIRStorageErrors.m +++ b/Firebase/Storage/FIRStorageErrors.m @@ -170,4 +170,15 @@ return clientError; } ++ (NSError *)errorWithInvalidRequest:(NSData *)request { + NSString *requestString = [[NSString alloc] initWithData:request encoding:NSUTF8StringEncoding]; + NSString *invalidDataString = + [NSString stringWithFormat:kFIRStorageInvalidDataFormat, requestString]; + NSDictionary *dict; + if (invalidDataString.length > 0) { + dict = @{NSLocalizedFailureReasonErrorKey : invalidDataString}; + } + return [FIRStorageErrors errorWithCode:FIRStorageErrorCodeUnknown infoDictionary:dict]; +} + @end diff --git a/Firebase/Storage/FIRStorageGetDownloadURLTask.m b/Firebase/Storage/FIRStorageGetDownloadURLTask.m new file mode 100644 index 0000000..c46bbd8 --- /dev/null +++ b/Firebase/Storage/FIRStorageGetDownloadURLTask.m @@ -0,0 +1,113 @@ +// Copyright 2018 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FIRStorageGetDownloadURLTask.h" +#import + +#import "FIRStorageConstants.h" +#import "FIRStorageMetadata_Private.h" +#import "FIRStorageTask_Private.h" +#import "FIRStorageUtils.h" + +#import "FirebaseStorage.h" + +@implementation FIRStorageGetDownloadURLTask { + @private + FIRStorageVoidURLError _completion; +} + +@synthesize fetcher = _fetcher; +@synthesize fetcherCompletion = _fetcherCompletion; + +- (instancetype)initWithReference:(FIRStorageReference *)reference + fetcherService:(GTMSessionFetcherService *)service + completion:(FIRStorageVoidURLError)completion { + self = [super initWithReference:reference fetcherService:service]; + if (self) { + _completion = [completion copy]; + } + return self; +} + +- (void)dealloc { + [_fetcher stopFetching]; +} + ++ (NSURL *)downloadURLFromMetadataDictionary:(NSDictionary *)dictionary { + NSString *downloadTokens = dictionary[kFIRStorageMetadataDownloadTokens]; + + if (downloadTokens && downloadTokens.length > 0) { + NSArray *downloadTokenArray = [downloadTokens componentsSeparatedByString:@","]; + NSString *bucket = dictionary[kFIRStorageMetadataBucket]; + NSString *path = dictionary[kFIRStorageMetadataName]; + NSString *fullPath = [NSString stringWithFormat:kFIRStorageFullPathFormat, bucket, + [FIRStorageUtils GCSEscapedString:path]]; + + NSURLComponents *components = [[NSURLComponents alloc] init]; + components.scheme = kFIRStorageScheme; + components.host = kFIRStorageHost; + components.percentEncodedPath = fullPath; + components.query = [NSString stringWithFormat:@"alt=media&token=%@", downloadTokenArray[0]]; + + return [components URL]; + } + + return nil; +} + +- (void)enqueue { + NSMutableURLRequest *request = [self.baseRequest mutableCopy]; + request.HTTPMethod = @"GET"; + request.timeoutInterval = self.reference.storage.maxDownloadRetryTime; + + FIRStorageVoidURLError callback = _completion; + _completion = nil; + + GTMSessionFetcher *fetcher = [self.fetcherService fetcherWithRequest:request]; + _fetcher = fetcher; + fetcher.comment = @"DownloadURLTask"; + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-retain-cycles" + _fetcherCompletion = ^(NSData *data, NSError *error) { + NSURL *downloadURL; + if (error) { + if (!self.error) { + self.error = [FIRStorageErrors errorWithServerError:error reference:self.reference]; + } + } else { + NSDictionary *responseDictionary = [NSDictionary frs_dictionaryFromJSONData:data]; + if (responseDictionary != nil) { + downloadURL = + [FIRStorageGetDownloadURLTask downloadURLFromMetadataDictionary:responseDictionary]; + } else { + self.error = [FIRStorageErrors errorWithInvalidRequest:data]; + } + } + + if (callback) { + callback(downloadURL, self.error); + } + + self->_fetcherCompletion = nil; + }; +#pragma clang diagnostic pop + + __weak FIRStorageGetDownloadURLTask *weakSelf = self; + [fetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) { + weakSelf.fetcherCompletion(data, error); + }]; +} + +@end diff --git a/Firebase/Storage/FIRStorageGetMetadataTask.m b/Firebase/Storage/FIRStorageGetMetadataTask.m index 2623652..077dcd7 100644 --- a/Firebase/Storage/FIRStorageGetMetadataTask.m +++ b/Firebase/Storage/FIRStorageGetMetadataTask.m @@ -58,37 +58,23 @@ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-retain-cycles" _fetcherCompletion = ^(NSData *data, NSError *error) { + FIRStorageMetadata *metadata; if (error) { if (!self.error) { self.error = [FIRStorageErrors errorWithServerError:error reference:self.reference]; } - if (callback) { - callback(nil, self.error); + } else { + NSDictionary *responseDictionary = [NSDictionary frs_dictionaryFromJSONData:data]; + if (responseDictionary != nil) { + metadata = [[FIRStorageMetadata alloc] initWithDictionary:responseDictionary]; + [metadata setType:FIRStorageMetadataTypeFile]; + } else { + self.error = [FIRStorageErrors errorWithInvalidRequest:data]; } - self->_fetcherCompletion = nil; - return; } - NSDictionary *responseDictionary = [NSDictionary frs_dictionaryFromJSONData:data]; - if (responseDictionary != nil) { - FIRStorageMetadata *metadata = - [[FIRStorageMetadata alloc] initWithDictionary:responseDictionary]; - [metadata setType:FIRStorageMetadataTypeFile]; - if (callback) { - callback(metadata, nil); - } - } else { - NSString *returnedData = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; - NSString *invalidDataString = - [NSString stringWithFormat:kFIRStorageInvalidDataFormat, returnedData]; - NSDictionary *dict; - if (invalidDataString.length > 0) { - dict = @{NSLocalizedFailureReasonErrorKey : invalidDataString}; - } - self.error = [FIRStorageErrors errorWithCode:FIRStorageErrorCodeUnknown infoDictionary:dict]; - if (callback) { - callback(nil, self.error); - } + if (callback) { + callback(metadata, self.error); } self->_fetcherCompletion = nil; }; diff --git a/Firebase/Storage/FIRStorageMetadata.m b/Firebase/Storage/FIRStorageMetadata.m index ab25076..764907c 100644 --- a/Firebase/Storage/FIRStorageMetadata.m +++ b/Firebase/Storage/FIRStorageMetadata.m @@ -41,7 +41,6 @@ _contentType = dictionary[kFIRStorageMetadataContentType]; _customMetadata = dictionary[kFIRStorageMetadataCustomMetadata]; _size = [dictionary[kFIRStorageMetadataSize] longLongValue]; - _downloadURLs = dictionary[kFIRStorageMetadataDownloadURLs]; _generation = [dictionary[kFIRStorageMetadataGeneration] longLongValue]; _metageneration = [dictionary[kFIRStorageMetadataMetageneration] longLongValue]; _timeCreated = [self dateFromRFC3339String:dictionary[kFIRStorageMetadataTimeCreated]]; @@ -50,26 +49,6 @@ // GCS "name" is our path, our "name" is just the last path component of the path _path = dictionary[kFIRStorageMetadataName]; _name = [_path lastPathComponent]; - NSString *downloadTokens = dictionary[kFIRStorageMetadataDownloadTokens]; - if (downloadTokens) { - NSArray *downloadStringArray = [downloadTokens componentsSeparatedByString:@","]; - NSMutableArray *downloadURLArray = - [[NSMutableArray alloc] initWithCapacity:[downloadStringArray count]]; - [downloadStringArray enumerateObjectsUsingBlock:^(NSString *_Nonnull token, NSUInteger idx, - BOOL *_Nonnull stop) { - NSURLComponents *components = [[NSURLComponents alloc] init]; - components.scheme = kFIRStorageScheme; - components.host = kFIRStorageHost; - NSString *path = [FIRStorageUtils GCSEscapedString:self->_path]; - NSString *fullPath = - [NSString stringWithFormat:kFIRStorageFullPathFormat, self->_bucket, path]; - components.percentEncodedPath = fullPath; - components.query = [NSString stringWithFormat:@"alt=media&token=%@", token]; - - [downloadURLArray insertObject:[components URL] atIndex:idx]; - }]; - _downloadURLs = downloadURLArray; - } } return self; } @@ -147,29 +126,6 @@ metadataDictionary[kFIRStorageMetadataCustomMetadata] = _customMetadata; } - if (_downloadURLs) { - NSMutableArray *downloadTokens = [[NSMutableArray alloc] init]; - [_downloadURLs - enumerateObjectsUsingBlock:^(NSURL *_Nonnull URL, NSUInteger idx, BOOL *_Nonnull stop) { - NSArray *queryItems = [URL.query componentsSeparatedByString:@"&"]; - [queryItems enumerateObjectsUsingBlock:^(NSString *queryString, NSUInteger idx, - BOOL *_Nonnull stop) { - NSString *key; - NSString *value; - NSScanner *scanner = [NSScanner scannerWithString:queryString]; - [scanner scanUpToString:@"=" intoString:&key]; - [scanner scanString:@"=" intoString:NULL]; - [scanner scanUpToString:@"\n" intoString:&value]; - if ([key isEqual:@"token"]) { - [downloadTokens addObject:value]; - *stop = YES; - } - }]; - }]; - NSString *downloadTokenString = [downloadTokens componentsJoinedByString:@","]; - metadataDictionary[kFIRStorageMetadataDownloadTokens] = downloadTokenString; - } - if (_generation) { NSString *generationString = [NSString stringWithFormat:@"%lld", _generation]; metadataDictionary[kFIRStorageMetadataGeneration] = generationString; @@ -207,10 +163,6 @@ return _type == FIRStorageMetadataTypeFolder; } -- (nullable NSURL *)downloadURL { - return [_downloadURLs firstObject]; -} - #pragma mark - Private methods + (void)removeMatchingMetadata:(NSMutableDictionary *)metadata diff --git a/Firebase/Storage/FIRStorageReference.m b/Firebase/Storage/FIRStorageReference.m index 7bc1934..5b70a9c 100644 --- a/Firebase/Storage/FIRStorageReference.m +++ b/Firebase/Storage/FIRStorageReference.m @@ -17,6 +17,7 @@ #import "FIRStorageConstants_Private.h" #import "FIRStorageDeleteTask.h" #import "FIRStorageDownloadTask_Private.h" +#import "FIRStorageGetDownloadURLTask.h" #import "FIRStorageGetMetadataTask.h" #import "FIRStorageMetadata_Private.h" #import "FIRStorageReference_Private.h" @@ -319,16 +320,11 @@ } - (void)downloadURLWithCompletion:(FIRStorageVoidURLError)completion { - dispatch_queue_t callbackQueue = _storage.fetcherServiceForApp.callbackQueue; - if (!callbackQueue) { - callbackQueue = dispatch_get_main_queue(); - } - - return [self metadataWithCompletion:^(FIRStorageMetadata *metadata, NSError *error) { - dispatch_async(callbackQueue, ^{ - completion(metadata.downloadURL, error); - }); - }]; + FIRStorageGetDownloadURLTask *task = + [[FIRStorageGetDownloadURLTask alloc] initWithReference:self + fetcherService:_storage.fetcherServiceForApp + completion:completion]; + [task enqueue]; } #pragma mark - Metadata Operations diff --git a/Firebase/Storage/FIRStorageUpdateMetadataTask.m b/Firebase/Storage/FIRStorageUpdateMetadataTask.m index fa5955a..d866329 100644 --- a/Firebase/Storage/FIRStorageUpdateMetadataTask.m +++ b/Firebase/Storage/FIRStorageUpdateMetadataTask.m @@ -64,37 +64,23 @@ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-retain-cycles" _fetcherCompletion = ^(NSData *data, NSError *error) { + FIRStorageMetadata *metadata; if (error) { if (!self.error) { self.error = [FIRStorageErrors errorWithServerError:error reference:self.reference]; } - if (callback) { - callback(nil, self.error); + } else { + NSDictionary *responseDictionary = [NSDictionary frs_dictionaryFromJSONData:data]; + if (responseDictionary) { + metadata = [[FIRStorageMetadata alloc] initWithDictionary:responseDictionary]; + [metadata setType:FIRStorageMetadataTypeFile]; + } else { + self.error = [FIRStorageErrors errorWithInvalidRequest:data]; } - self->_fetcherCompletion = nil; - return; } - NSDictionary *responseDictionary = [NSDictionary frs_dictionaryFromJSONData:data]; - if (responseDictionary) { - FIRStorageMetadata *metadata = - [[FIRStorageMetadata alloc] initWithDictionary:responseDictionary]; - [metadata setType:FIRStorageMetadataTypeFile]; - if (callback) { - callback(metadata, nil); - } - } else { - NSString *returnedData = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; - NSString *invalidDataString = - [NSString stringWithFormat:kFIRStorageInvalidDataFormat, returnedData]; - NSDictionary *dict; - if (invalidDataString.length > 0) { - dict = @{NSLocalizedFailureReasonErrorKey : invalidDataString}; - } - self.error = [FIRStorageErrors errorWithCode:FIRStorageErrorCodeUnknown infoDictionary:dict]; - if (callback) { - callback(nil, self.error); - } + if (callback) { + callback(metadata, self.error); } self->_fetcherCompletion = nil; }; diff --git a/Firebase/Storage/FIRStorageUploadTask.m b/Firebase/Storage/FIRStorageUploadTask.m index f84c2c7..2c4daa9 100644 --- a/Firebase/Storage/FIRStorageUploadTask.m +++ b/Firebase/Storage/FIRStorageUploadTask.m @@ -154,14 +154,7 @@ [metadata setType:FIRStorageMetadataTypeFile]; self.metadata = metadata; } else { - NSString *returnedData = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; - NSString *invalidDataString = - [NSString stringWithFormat:kFIRStorageInvalidDataFormat, returnedData]; - NSDictionary *dict; - if (invalidDataString.length > 0) { - dict = @{NSLocalizedFailureReasonErrorKey : invalidDataString}; - } - self.error = [FIRStorageErrors errorWithCode:FIRStorageErrorCodeUnknown infoDictionary:dict]; + self.error = [FIRStorageErrors errorWithInvalidRequest:data]; } [self fireHandlersForStatus:FIRStorageTaskStatusSuccess snapshot:self.snapshot]; diff --git a/Firebase/Storage/Private/FIRStorageConstants_Private.h b/Firebase/Storage/Private/FIRStorageConstants_Private.h index 498c687..cf12337 100644 --- a/Firebase/Storage/Private/FIRStorageConstants_Private.h +++ b/Firebase/Storage/Private/FIRStorageConstants_Private.h @@ -55,7 +55,6 @@ FOUNDATION_EXPORT NSString *const kFIRStorageMetadataContentLanguage; FOUNDATION_EXPORT NSString *const kFIRStorageMetadataContentType; FOUNDATION_EXPORT NSString *const kFIRStorageMetadataCustomMetadata; FOUNDATION_EXPORT NSString *const kFIRStorageMetadataSize; -FOUNDATION_EXPORT NSString *const kFIRStorageMetadataDownloadURLs; FOUNDATION_EXPORT NSString *const kFIRStorageMetadataGeneration; FOUNDATION_EXPORT NSString *const kFIRStorageMetadataMetageneration; FOUNDATION_EXPORT NSString *const kFIRStorageMetadataTimeCreated; diff --git a/Firebase/Storage/Private/FIRStorageErrors.h b/Firebase/Storage/Private/FIRStorageErrors.h index 7c236d9..46e87d2 100644 --- a/Firebase/Storage/Private/FIRStorageErrors.h +++ b/Firebase/Storage/Private/FIRStorageErrors.h @@ -44,11 +44,19 @@ NS_ASSUME_NONNULL_BEGIN * Creates a Firebase Storage error from a specific GCS error and FIRStorageReference. * @param error Server error to wrap and return as a Firebase Storage error. * @param reference FIRStorageReference which provides context about the request being made. - * @return Returns an Firebase Storage error, or nil if no error is provided. + * @return Returns a Firebase Storage error, or nil if no error is provided. */ + (nullable NSError *)errorWithServerError:(nullable NSError *)error reference:(nullable FIRStorageReference *)reference; +/** + * Creates a Firebase Storage error from an invalid request. + * + * @param request The NSData representation of the invalid user request. + * @return Returns the corresponding Firebase Storage error. + */ ++ (NSError *)errorWithInvalidRequest:(NSData *)request; + @end NS_ASSUME_NONNULL_END diff --git a/Firebase/Storage/Private/FIRStorageGetDownloadURLTask.h b/Firebase/Storage/Private/FIRStorageGetDownloadURLTask.h new file mode 100644 index 0000000..c349f30 --- /dev/null +++ b/Firebase/Storage/Private/FIRStorageGetDownloadURLTask.h @@ -0,0 +1,37 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FIRStorageTask.h" + +@class GTMSessionFetcherService; + +NS_ASSUME_NONNULL_BEGIN + +/** + * Task which provides the ability to get a download URL for an object in Firebase Storage. + */ +@interface FIRStorageGetDownloadURLTask : FIRStorageTask + +- (instancetype)initWithReference:(FIRStorageReference *)reference + fetcherService:(GTMSessionFetcherService *)service + completion:(FIRStorageVoidURLError)completion; + +// Visible for testing. ++ (NSURL *)downloadURLFromMetadataDictionary:(NSDictionary *)dictionary; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Firebase/Storage/Public/FIRStorageMetadata.h b/Firebase/Storage/Public/FIRStorageMetadata.h index 2e3cc13..63b8798 100644 --- a/Firebase/Storage/Public/FIRStorageMetadata.h +++ b/Firebase/Storage/Public/FIRStorageMetadata.h @@ -112,12 +112,6 @@ NS_SWIFT_NAME(StorageMetadata) */ @property(strong, nonatomic, readonly, nullable) FIRStorageReference *storageReference; -/** - * An array containing all download URLs available for the object. - */ -@property(strong, nonatomic, readonly, nullable) NSArray *downloadURLs __deprecated_msg( - "Use `StorageReference.downloadURLWithCompletion()` to obtain a current download URL."); - /** * Creates an instanece of FIRStorageMetadata from the contents of a dictionary. * @return An instance of FIRStorageMetadata that represents the contents of a dictionary. @@ -141,14 +135,6 @@ NS_SWIFT_NAME(StorageMetadata) */ @property(readonly, getter=isFolder) BOOL folder; -/** - * Retrieves a download URL for the given object, or nil if none exist. - * Note that if there are many valid download tokens, this will always return the first - * valid token created. - */ -- (nullable NSURL *)downloadURL __deprecated_msg( - "Use `StorageReference.downloadURLWithCompletion()` to obtain a current download URL."); - @end NS_ASSUME_NONNULL_END -- cgit v1.2.3 From 1feabba011dd73fed97fcf38828500d7bd7e79ff Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Mon, 9 Apr 2018 16:37:33 -0700 Subject: Removing unused imports --- Firebase/Storage/FIRStorageGetDownloadURLTask.m | 2 -- 1 file changed, 2 deletions(-) (limited to 'Firebase/Storage') diff --git a/Firebase/Storage/FIRStorageGetDownloadURLTask.m b/Firebase/Storage/FIRStorageGetDownloadURLTask.m index c46bbd8..7447888 100644 --- a/Firebase/Storage/FIRStorageGetDownloadURLTask.m +++ b/Firebase/Storage/FIRStorageGetDownloadURLTask.m @@ -13,10 +13,8 @@ // limitations under the License. #import "FIRStorageGetDownloadURLTask.h" -#import #import "FIRStorageConstants.h" -#import "FIRStorageMetadata_Private.h" #import "FIRStorageTask_Private.h" #import "FIRStorageUtils.h" -- cgit v1.2.3 From e86665b1ba2bbaf7ddd70873118badc812e0bc20 Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Fri, 13 Apr 2018 12:17:36 -0700 Subject: Addressing feedback --- .../Tests/Integration/FIRStorageIntegrationTests.m | 15 +++++++++-- .../Storage/Tests/Unit/FIRStorageMetadataTests.m | 1 + Firebase/Storage/CHANGELOG.md | 6 ++++- Firebase/Storage/FIRStorageErrors.m | 6 +++++ Firebase/Storage/FIRStorageGetDownloadURLTask.m | 20 ++++++++++----- Firebase/Storage/FIRStorageGetMetadataTask.m | 2 +- Firebase/Storage/Private/FIRStorageErrors.h | 8 ++++++ .../Storage/Private/FIRStorageGetDownloadURLTask.h | 3 --- .../Private/FIRStorageGetDownloadURLTask_Private.h | 30 ++++++++++++++++++++++ 9 files changed, 77 insertions(+), 14 deletions(-) create mode 100644 Firebase/Storage/Private/FIRStorageGetDownloadURLTask_Private.h (limited to 'Firebase/Storage') diff --git a/Example/Storage/Tests/Integration/FIRStorageIntegrationTests.m b/Example/Storage/Tests/Integration/FIRStorageIntegrationTests.m index 5b428c1..b20108a 100644 --- a/Example/Storage/Tests/Integration/FIRStorageIntegrationTests.m +++ b/Example/Storage/Tests/Integration/FIRStorageIntegrationTests.m @@ -392,10 +392,21 @@ NSTimeInterval kFIRStorageIntegrationTestTimeout = 30; FIRStorageReference *ref = [self.storage referenceWithPath:@"ios/public/1mb"]; + // Download URL format is + // "https://firebasestorage.googleapis.com/v0/b/{bucket}/o/{path}?alt=media&token={token}" + NSString *downloadURLPattern = + @"^https:\\/\\/firebasestorage.googleapis.com\\/v0\\/b\\/[^\\/]*\\/o\\/" + @"ios%2Fpublic%2F1mb\\?alt=media&token=[a-z0-9-]*$"; + [ref downloadURLWithCompletion:^(NSURL *downloadURL, NSError *error) { XCTAssertNil(error); - XCTAssertTrue( - [[downloadURL absoluteString] hasPrefix:@"https://firebasestorage.googleapis.com/"]); + NSRegularExpression *testRegex = + [NSRegularExpression regularExpressionWithPattern:downloadURLPattern options:0 error:nil]; + NSString *urlString = [downloadURL absoluteString]; + XCTAssertEqual([testRegex numberOfMatchesInString:urlString + options:0 + range:NSMakeRange(0, [urlString length])], + 1); [expectation fulfill]; }]; diff --git a/Example/Storage/Tests/Unit/FIRStorageMetadataTests.m b/Example/Storage/Tests/Unit/FIRStorageMetadataTests.m index 6c8bfa5..6a83741 100644 --- a/Example/Storage/Tests/Unit/FIRStorageMetadataTests.m +++ b/Example/Storage/Tests/Unit/FIRStorageMetadataTests.m @@ -16,6 +16,7 @@ #import #import "FIRStorageGetDownloadURLTask.h" +#import "FIRStorageGetDownloadURLTask_Private.h" #import "FIRStorageMetadata.h" #import "FIRStorageMetadata_Private.h" #import "FIRStorageUtils.h" diff --git a/Firebase/Storage/CHANGELOG.md b/Firebase/Storage/CHANGELOG.md index 5054cf2..a48c3c5 100644 --- a/Firebase/Storage/CHANGELOG.md +++ b/Firebase/Storage/CHANGELOG.md @@ -1,5 +1,9 @@ +# v3.0.0 +- [removed] Removed `downloadURLs` property on `StorageMetadata`. Use `StorageReference.downloadURL(completion:)` to obtain a current download URL. +- [changed] The `maxOperationRetryTime` timeout now applies to calls to `StorageReference.getMetadata(completion:)`. + # v2.2.0 -- [changed] Deprecated `downloadURLs` property on `StorageMetadata`. Use `StorageReference.downloadURLWithCompletion()` to obtain a current download URL. +- [changed] Deprecated `downloadURLs` property on `StorageMetadata`. Use `StorageReference.downloadURL(completion:)` to obtain a current download URL. # v2.1.3 - [changed] Addresses CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF warnings that surface in newer versions of Xcode and CocoaPods. diff --git a/Firebase/Storage/FIRStorageErrors.m b/Firebase/Storage/FIRStorageErrors.m index 7cc4beb..651bfd1 100644 --- a/Firebase/Storage/FIRStorageErrors.m +++ b/Firebase/Storage/FIRStorageErrors.m @@ -181,4 +181,10 @@ return [FIRStorageErrors errorWithCode:FIRStorageErrorCodeUnknown infoDictionary:dict]; } ++ (NSError *)errorWithCustomMessage:(NSString *)errorMessage { + return [NSError errorWithDomain:FIRStorageErrorDomain + code:FIRStorageErrorCodeUnknown + userInfo:@{NSLocalizedDescriptionKey : errorMessage}]; +} + @end diff --git a/Firebase/Storage/FIRStorageGetDownloadURLTask.m b/Firebase/Storage/FIRStorageGetDownloadURLTask.m index 7447888..c4e0035 100644 --- a/Firebase/Storage/FIRStorageGetDownloadURLTask.m +++ b/Firebase/Storage/FIRStorageGetDownloadURLTask.m @@ -14,11 +14,7 @@ #import "FIRStorageGetDownloadURLTask.h" -#import "FIRStorageConstants.h" #import "FIRStorageTask_Private.h" -#import "FIRStorageUtils.h" - -#import "FirebaseStorage.h" @implementation FIRStorageGetDownloadURLTask { @private @@ -56,7 +52,13 @@ components.scheme = kFIRStorageScheme; components.host = kFIRStorageHost; components.percentEncodedPath = fullPath; - components.query = [NSString stringWithFormat:@"alt=media&token=%@", downloadTokenArray[0]]; + + // The backend can return an arbitrary number of download tokens, but we only expose the first + // token via the download URL. + NSURLQueryItem *altItem = [[NSURLQueryItem alloc] initWithName:@"alt" value:@"media"]; + NSURLQueryItem *tokenItem = + [[NSURLQueryItem alloc] initWithName:@"token" value:downloadTokenArray[0]]; + components.queryItems = @[ altItem, tokenItem ]; return [components URL]; } @@ -67,14 +69,14 @@ - (void)enqueue { NSMutableURLRequest *request = [self.baseRequest mutableCopy]; request.HTTPMethod = @"GET"; - request.timeoutInterval = self.reference.storage.maxDownloadRetryTime; + request.timeoutInterval = self.reference.storage.maxOperationRetryTime; FIRStorageVoidURLError callback = _completion; _completion = nil; GTMSessionFetcher *fetcher = [self.fetcherService fetcherWithRequest:request]; _fetcher = fetcher; - fetcher.comment = @"DownloadURLTask"; + fetcher.comment = @"GetDownloadURLTask"; #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-retain-cycles" @@ -89,6 +91,10 @@ if (responseDictionary != nil) { downloadURL = [FIRStorageGetDownloadURLTask downloadURLFromMetadataDictionary:responseDictionary]; + if (!downloadURL) { + self.error = + [FIRStorageErrors errorWithCustomMessage:@"Failed to retrieve a download URL"]; + } } else { self.error = [FIRStorageErrors errorWithInvalidRequest:data]; } diff --git a/Firebase/Storage/FIRStorageGetMetadataTask.m b/Firebase/Storage/FIRStorageGetMetadataTask.m index 077dcd7..752c410 100644 --- a/Firebase/Storage/FIRStorageGetMetadataTask.m +++ b/Firebase/Storage/FIRStorageGetMetadataTask.m @@ -46,7 +46,7 @@ - (void)enqueue { NSMutableURLRequest *request = [self.baseRequest mutableCopy]; request.HTTPMethod = @"GET"; - request.timeoutInterval = self.reference.storage.maxDownloadRetryTime; + request.timeoutInterval = self.reference.storage.maxOperationRetryTime; FIRStorageVoidMetadataError callback = _completion; _completion = nil; diff --git a/Firebase/Storage/Private/FIRStorageErrors.h b/Firebase/Storage/Private/FIRStorageErrors.h index 46e87d2..a76a6aa 100644 --- a/Firebase/Storage/Private/FIRStorageErrors.h +++ b/Firebase/Storage/Private/FIRStorageErrors.h @@ -57,6 +57,14 @@ NS_ASSUME_NONNULL_BEGIN */ + (NSError *)errorWithInvalidRequest:(NSData *)request; +/** + * Creates a Firebase Storage error with a custom error message. + * + * @param errorMessage A custom error message. + * @return Returns the corresponding Firebase Storage error. + */ ++ (NSError *)errorWithCustomMessage:(NSString *)errorMessage; + @end NS_ASSUME_NONNULL_END diff --git a/Firebase/Storage/Private/FIRStorageGetDownloadURLTask.h b/Firebase/Storage/Private/FIRStorageGetDownloadURLTask.h index c349f30..8cd9eb3 100644 --- a/Firebase/Storage/Private/FIRStorageGetDownloadURLTask.h +++ b/Firebase/Storage/Private/FIRStorageGetDownloadURLTask.h @@ -29,9 +29,6 @@ NS_ASSUME_NONNULL_BEGIN fetcherService:(GTMSessionFetcherService *)service completion:(FIRStorageVoidURLError)completion; -// Visible for testing. -+ (NSURL *)downloadURLFromMetadataDictionary:(NSDictionary *)dictionary; - @end NS_ASSUME_NONNULL_END diff --git a/Firebase/Storage/Private/FIRStorageGetDownloadURLTask_Private.h b/Firebase/Storage/Private/FIRStorageGetDownloadURLTask_Private.h new file mode 100644 index 0000000..ac5fd80 --- /dev/null +++ b/Firebase/Storage/Private/FIRStorageGetDownloadURLTask_Private.h @@ -0,0 +1,30 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FIRStorageGetDownloadURLTask.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + * Task which provides the ability to get a download URL for an object in Firebase Storage. + */ +@interface FIRStorageGetDownloadURLTask () + ++ (NSURL *)downloadURLFromMetadataDictionary:(NSDictionary *)dictionary; + +@end + +NS_ASSUME_NONNULL_END -- cgit v1.2.3 From 81709006e65a648fb529f3081224ea749a95ccc6 Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Fri, 13 Apr 2018 14:07:56 -0700 Subject: More comments --- Firebase/Storage/CHANGELOG.md | 2 +- Firebase/Storage/FIRStorageGetDownloadURLTask.m | 2 +- Firebase/Storage/FIRStorageUpdateMetadataTask.m | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'Firebase/Storage') diff --git a/Firebase/Storage/CHANGELOG.md b/Firebase/Storage/CHANGELOG.md index a48c3c5..135de40 100644 --- a/Firebase/Storage/CHANGELOG.md +++ b/Firebase/Storage/CHANGELOG.md @@ -1,6 +1,6 @@ # v3.0.0 - [removed] Removed `downloadURLs` property on `StorageMetadata`. Use `StorageReference.downloadURL(completion:)` to obtain a current download URL. -- [changed] The `maxOperationRetryTime` timeout now applies to calls to `StorageReference.getMetadata(completion:)`. +- [changed] The `maxOperationRetryTime` timeout now applies to calls to `StorageReference.getMetadata(completion:)` and `StorageReference.updateMetadata(completion:)`. These calls previously used the `maxDownloadRetryTime` and `maxUploadRetryTime` timeouts. # v2.2.0 - [changed] Deprecated `downloadURLs` property on `StorageMetadata`. Use `StorageReference.downloadURL(completion:)` to obtain a current download URL. diff --git a/Firebase/Storage/FIRStorageGetDownloadURLTask.m b/Firebase/Storage/FIRStorageGetDownloadURLTask.m index c4e0035..02d202e 100644 --- a/Firebase/Storage/FIRStorageGetDownloadURLTask.m +++ b/Firebase/Storage/FIRStorageGetDownloadURLTask.m @@ -93,7 +93,7 @@ [FIRStorageGetDownloadURLTask downloadURLFromMetadataDictionary:responseDictionary]; if (!downloadURL) { self.error = - [FIRStorageErrors errorWithCustomMessage:@"Failed to retrieve a download URL"]; + [FIRStorageErrors errorWithCustomMessage:@"Failed to retrieve a download URL."]; } } else { self.error = [FIRStorageErrors errorWithInvalidRequest:data]; diff --git a/Firebase/Storage/FIRStorageUpdateMetadataTask.m b/Firebase/Storage/FIRStorageUpdateMetadataTask.m index d866329..cea4e7d 100644 --- a/Firebase/Storage/FIRStorageUpdateMetadataTask.m +++ b/Firebase/Storage/FIRStorageUpdateMetadataTask.m @@ -48,7 +48,7 @@ NSDictionary *updateDictionary = [_updateMetadata updatedMetadata]; NSData *updateData = [NSData frs_dataFromJSONDictionary:updateDictionary]; request.HTTPMethod = @"PATCH"; - request.timeoutInterval = self.reference.storage.maxUploadRetryTime; + request.timeoutInterval = self.reference.storage.maxOperationRetryTime; request.HTTPBody = updateData; NSString *typeString = @"application/json; charset=UTF-8"; [request setValue:typeString forHTTPHeaderField:@"Content-Type"]; -- cgit v1.2.3 From d7316f70dc4825e75cecd47740c0541248aa9641 Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Fri, 13 Apr 2018 14:12:16 -0700 Subject: Adding comment to downloadURLFromMetadataDictionary --- Firebase/Storage/Private/FIRStorageGetDownloadURLTask_Private.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'Firebase/Storage') diff --git a/Firebase/Storage/Private/FIRStorageGetDownloadURLTask_Private.h b/Firebase/Storage/Private/FIRStorageGetDownloadURLTask_Private.h index ac5fd80..0da04a4 100644 --- a/Firebase/Storage/Private/FIRStorageGetDownloadURLTask_Private.h +++ b/Firebase/Storage/Private/FIRStorageGetDownloadURLTask_Private.h @@ -23,7 +23,8 @@ NS_ASSUME_NONNULL_BEGIN */ @interface FIRStorageGetDownloadURLTask () -+ (NSURL *)downloadURLFromMetadataDictionary:(NSDictionary *)dictionary; +/** Extracts a download URL from the StorageMetadata dictonary representation. */ ++ (nullable NSURL *)downloadURLFromMetadataDictionary:(NSDictionary *)dictionary; @end -- cgit v1.2.3