Skip to content

Commit 2c1f579

Browse files
Add useEmulator() to Storage (#7379)
1 parent d937b2f commit 2c1f579

25 files changed

+295
-105
lines changed

FirebaseStorage/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
# 8.0.0
2+
- [added] Added `FirebaseStorage.useEmulator()`, which allows the Storage SDK to
3+
connect to the Cloud Storage for Firebase emulator.
24
- [added] Added abuse reduction features. (#7928)
35

46
# 7.4.0

FirebaseStorage/Sources/FIRStorage.m

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ + (GTMSessionFetcherService *)fetcherServiceForApp:(FIRApp *)app
8484
fetcherService = [[GTMSessionFetcherService alloc] init];
8585
[fetcherService setRetryEnabled:YES];
8686
[fetcherService setRetryBlock:_retryWhenOffline];
87+
[fetcherService setAllowLocalhostRequest:YES];
8788
FIRStorageTokenAuthorizer *authorizer =
8889
[[FIRStorageTokenAuthorizer alloc] initWithGoogleAppID:app.options.googleAppID
8990
fetcherService:fetcherService
@@ -160,11 +161,11 @@ - (instancetype)initWithApp:(FIRApp *)app
160161
_auth = auth;
161162
_appCheck = appCheck;
162163
_storageBucket = bucket;
164+
_host = kFIRStorageHost;
165+
_scheme = kFIRStorageScheme;
166+
_port = @(kFIRStoragePort);
167+
_fetcherServiceForApp = nil; // Configured in `ensureConfigured()`
163168
_dispatchQueue = dispatch_queue_create("com.google.firebase.storage", DISPATCH_QUEUE_SERIAL);
164-
_fetcherServiceForApp = [FIRStorage fetcherServiceForApp:_app
165-
bucket:bucket
166-
auth:auth
167-
appCheck:appCheck];
168169
_maxDownloadRetryTime = 600.0;
169170
_maxDownloadRetryInterval =
170171
[FIRStorageUtils computeRetryIntervalFromRetryTime:_maxDownloadRetryTime];
@@ -271,11 +272,15 @@ - (NSTimeInterval)maxOperationRetryTime {
271272
#pragma mark - Public methods
272273

273274
- (FIRStorageReference *)reference {
275+
[self ensureConfigured];
276+
274277
FIRStoragePath *path = [[FIRStoragePath alloc] initWithBucket:_storageBucket object:nil];
275278
return [[FIRStorageReference alloc] initWithStorage:self path:path];
276279
}
277280

278281
- (FIRStorageReference *)referenceForURL:(NSString *)string {
282+
[self ensureConfigured];
283+
279284
FIRStoragePath *path = [FIRStoragePath pathFromString:string];
280285

281286
// If no default bucket exists (empty string), accept anything.
@@ -302,13 +307,37 @@ - (FIRStorageReference *)referenceWithPath:(NSString *)string {
302307
}
303308

304309
- (dispatch_queue_t)callbackQueue {
310+
[self ensureConfigured];
305311
return _fetcherServiceForApp.callbackQueue;
306312
}
307313

308314
- (void)setCallbackQueue:(dispatch_queue_t)callbackQueue {
315+
[self ensureConfigured];
309316
_fetcherServiceForApp.callbackQueue = callbackQueue;
310317
}
311318

319+
- (void)useEmulatorWithHost:(NSString *)host port:(NSInteger)port {
320+
if (host.length == 0) {
321+
[NSException raise:NSInvalidArgumentException format:@"Cannot connect to nil or empty host."];
322+
}
323+
324+
if (port < 0) {
325+
[NSException raise:NSInvalidArgumentException
326+
format:@"Port must be greater than or equal to zero."];
327+
}
328+
329+
if (_fetcherServiceForApp != nil) {
330+
[NSException raise:NSInternalInconsistencyException
331+
format:@"Cannot connect to emulator after Storage SDK initialization. "
332+
@"Call useEmulator(host:port:) before creating a Storage "
333+
@"reference or trying to load data."];
334+
}
335+
336+
_scheme = @"http";
337+
_host = host;
338+
_port = @(port);
339+
}
340+
312341
#pragma mark - Background tasks
313342

314343
+ (void)enableBackgroundTasks:(BOOL)isEnabled {
@@ -325,4 +354,13 @@ + (void)enableBackgroundTasks:(BOOL)isEnabled {
325354
return nil;
326355
}
327356

357+
- (void)ensureConfigured {
358+
if (!_fetcherServiceForApp) {
359+
_fetcherServiceForApp = [FIRStorage fetcherServiceForApp:_app
360+
bucket:_storageBucket
361+
auth:_auth
362+
appCheck:_appCheck];
363+
}
364+
}
365+
328366
@end

FirebaseStorage/Sources/FIRStorageConstants.m

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
NSString *const kFIRStorageScheme = @"https";
2727
NSString *const kFIRStorageHost = @"firebasestorage.googleapis.com";
28+
NSInteger const kFIRStoragePort = 443;
2829
NSString *const kFIRStorageVersionPath = @"v0";
2930
NSString *const kFIRStorageBucketPathFormat = @"b/%@";
3031
NSString *const kFIRStorageObjectPathFormat = @"o/%@";

FirebaseStorage/Sources/FIRStorageConstants_Private.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ FOUNDATION_EXPORT NSString *const kGCSObjectPathFormat;
2929

3030
FOUNDATION_EXPORT NSString *const kFIRStorageScheme;
3131
FOUNDATION_EXPORT NSString *const kFIRStorageHost;
32+
FOUNDATION_EXPORT NSInteger const kFIRStoragePort;
3233
FOUNDATION_EXPORT NSString *const kFIRStorageVersionPath;
3334
FOUNDATION_EXPORT NSString *const kFIRStorageBucketPathFormat;
3435
FOUNDATION_EXPORT NSString *const kFIRStorageObjectPathFormat;

FirebaseStorage/Sources/FIRStorageGetDownloadURLTask.m

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#import "FirebaseStorage/Sources/FIRStorageGetDownloadURLTask.h"
1616

1717
#import "FirebaseStorage/Sources/FIRStorageTask_Private.h"
18+
#import "FirebaseStorage/Sources/FIRStorage_Private.h"
1819

1920
@implementation FIRStorageGetDownloadURLTask {
2021
@private
@@ -39,7 +40,7 @@ - (void)dealloc {
3940
[_fetcher stopFetching];
4041
}
4142

42-
+ (NSURL *)downloadURLFromMetadataDictionary:(NSDictionary *)dictionary {
43+
- (NSURL *)downloadURLFromMetadataDictionary:(NSDictionary *)dictionary {
4344
NSString *downloadTokens = dictionary[kFIRStorageMetadataDownloadTokens];
4445

4546
if (downloadTokens && downloadTokens.length > 0) {
@@ -50,8 +51,9 @@ + (NSURL *)downloadURLFromMetadataDictionary:(NSDictionary *)dictionary {
5051
[FIRStorageUtils GCSEscapedString:path]];
5152

5253
NSURLComponents *components = [[NSURLComponents alloc] init];
53-
components.scheme = kFIRStorageScheme;
54-
components.host = kFIRStorageHost;
54+
components.scheme = self.reference.storage.scheme;
55+
components.host = self.reference.storage.host;
56+
components.port = self.reference.storage.port;
5557
components.percentEncodedPath = fullPath;
5658

5759
// The backend can return an arbitrary number of download tokens, but we only expose the first
@@ -72,7 +74,6 @@ - (void)enqueue {
7274

7375
[self dispatchAsync:^() {
7476
FIRStorageGetDownloadURLTask *strongSelf = weakSelf;
75-
7677
if (!strongSelf) {
7778
return;
7879
}
@@ -97,8 +98,7 @@ - (void)enqueue {
9798
} else {
9899
NSDictionary *responseDictionary = [NSDictionary frs_dictionaryFromJSONData:data];
99100
if (responseDictionary != nil) {
100-
downloadURL =
101-
[FIRStorageGetDownloadURLTask downloadURLFromMetadataDictionary:responseDictionary];
101+
downloadURL = [strongSelf downloadURLFromMetadataDictionary:responseDictionary];
102102
if (!downloadURL) {
103103
self.error =
104104
[FIRStorageErrors errorWithCustomMessage:@"Failed to retrieve a download URL."];

FirebaseStorage/Sources/FIRStorageGetDownloadURLTask_Private.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ NS_ASSUME_NONNULL_BEGIN
2424
@interface FIRStorageGetDownloadURLTask ()
2525

2626
/** Extracts a download URL from the StorageMetadata dictonary representation. */
27-
+ (nullable NSURL *)downloadURLFromMetadataDictionary:(NSDictionary *)dictionary;
27+
- (nullable NSURL *)downloadURLFromMetadataDictionary:(NSDictionary *)dictionary;
2828

2929
@end
3030

FirebaseStorage/Sources/FIRStorageListTask.m

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,10 +78,9 @@ - (void)enqueue {
7878
queryParams[@"pageToken"] = strongSelf->_previousPageToken;
7979
}
8080

81-
FIRStoragePath *basePath = [[FIRStoragePath alloc] initWithBucket:self.reference.bucket
82-
object:nil];
81+
FIRStorageReference *root = self.reference.root;
8382
NSMutableURLRequest *request =
84-
[[FIRStorageUtils defaultRequestForPath:basePath queryParams:queryParams] mutableCopy];
83+
[[FIRStorageUtils defaultRequestForReference:root queryParams:queryParams] mutableCopy];
8584

8685
request.HTTPMethod = @"GET";
8786
request.timeoutInterval = strongSelf.reference.storage.maxOperationRetryTime;

FirebaseStorage/Sources/FIRStoragePath.m

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -59,27 +59,23 @@ + (nullable FIRStoragePath *)pathFromHTTPURL:(NSString *)aURLString {
5959
NSURL *httpsURL = [NSURL URLWithString:aURLString];
6060
NSArray *pathComponents = httpsURL.pathComponents; // [/, v0, b, <bucket>, o, <objects/...>]
6161

62-
if ([httpsURL.host isEqual:kFIRStorageHost]) {
63-
// Have a bucket name
64-
if ([pathComponents count] > 3) {
65-
bucketName = pathComponents[3];
66-
}
67-
68-
// Have an object name
69-
if ([pathComponents count] > 5) {
70-
NSRange objectRange = NSMakeRange(5, [pathComponents count] - 5);
71-
objectName = [[pathComponents subarrayWithRange:objectRange] componentsJoinedByString:@"/"];
72-
}
73-
}
74-
75-
if (bucketName.length == 0) {
62+
if ([pathComponents count] <= 3 || ![pathComponents[1] isEqual:@"v0"] ||
63+
![pathComponents[2] isEqual:@"b"]) {
7664
[NSException raise:NSInternalInconsistencyException
7765
format:@"URL must be in the form of "
78-
@"http[s]://firebasestorage.googleapis.com/v0/b/<bucket>/o/<path/to/"
66+
@"http[s]://<host>/v0/b/<bucket>/o/<path/to/"
7967
@"object>[?token=signed_url_params]"];
8068
return nil;
8169
}
8270

71+
bucketName = pathComponents[3];
72+
73+
// Have an object name
74+
if ([pathComponents count] > 5) {
75+
NSRange objectRange = NSMakeRange(5, [pathComponents count] - 5);
76+
objectName = [[pathComponents subarrayWithRange:objectRange] componentsJoinedByString:@"/"];
77+
}
78+
8379
if (objectName.length == 0) {
8480
objectName = nil;
8581
}

FirebaseStorage/Sources/FIRStorageTask.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ - (instancetype)initWithReference:(FIRStorageReference *)reference
4343
self = [super init];
4444
if (self) {
4545
_reference = reference;
46-
_baseRequest = [FIRStorageUtils defaultRequestForPath:reference.path];
46+
_baseRequest = [FIRStorageUtils defaultRequestForReference:reference];
4747
_fetcherService = service;
4848
_fetcherService.maxRetryInterval = _reference.storage.maxOperationRetryInterval;
4949
_dispatchQueue = queue;

FirebaseStorage/Sources/FIRStorageUtils.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#import <Foundation/Foundation.h>
1818

1919
@class FIRStoragePath;
20+
@class FIRStorageReference;
2021

2122
NS_ASSUME_NONNULL_BEGIN
2223

@@ -53,20 +54,20 @@ NS_ASSUME_NONNULL_BEGIN
5354

5455
/**
5556
* Returns a base NSURLRequest used by all tasks.
56-
* @param path The FIRStoragePath to create a request for.
57+
* @param reference The FIRStorageReference to create a request for.
5758
* @return Returns a properly formatted NSURLRequest of the form:
5859
* scheme://host/version/b/<bucket>/o[/path/to/object]
5960
*/
60-
+ (NSURLRequest *)defaultRequestForPath:(FIRStoragePath *)path;
61+
+ (NSURLRequest *)defaultRequestForReference:(FIRStorageReference *)reference;
6162

6263
/**
6364
* Returns a base NSURLRequest with custom query parameters.
64-
* @param path The FIRStoragePath to create a request for.
65+
* @param reference The FIRStorageReference to create a request for.
6566
* @param queryParams A key/value dictionary with query parameters.
6667
* @return Returns a formatted NSURLRequest
6768
*/
68-
+ (NSURLRequest *)defaultRequestForPath:(FIRStoragePath *)path
69-
queryParams:(NSDictionary<NSString *, NSString *> *)queryParams;
69+
+ (NSURLRequest *)defaultRequestForReference:(FIRStorageReference *)reference
70+
queryParams:(NSDictionary<NSString *, NSString *> *)queryParams;
7071

7172
/**
7273
* Creates the appropriate GCS percent escaped path for a given FIRStoragePath.

0 commit comments

Comments
 (0)