| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178 |
- // Copyright 2017 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 <Foundation/Foundation.h>
- #if TARGET_OS_IOS || TARGET_OS_TV
- #import <MobileCoreServices/MobileCoreServices.h>
- #elif TARGET_OS_OSX || TARGET_OS_WATCH
- #import <CoreServices/CoreServices.h>
- #endif
- #import "FirebaseStorage/Sources/FIRStorageUtils.h"
- #import "FirebaseStorage/Sources/FIRStorageConstants_Private.h"
- #import "FirebaseStorage/Sources/FIRStorageErrors.h"
- #import "FirebaseStorage/Sources/FIRStoragePath.h"
- #if SWIFT_PACKAGE
- @import GTMSessionFetcherCore;
- #else
- #import <GTMSessionFetcher/GTMSessionFetcher.h>
- #endif
- // This is the list at https://cloud.google.com/storage/docs/json_api/ without &, ; and +.
- NSString *const kGCSObjectAllowedCharacterSet =
- @"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$'()*,=:@";
- @implementation FIRStorageUtils
- + (nullable NSString *)GCSEscapedString:(NSString *)string {
- NSCharacterSet *allowedCharacters =
- [NSCharacterSet characterSetWithCharactersInString:kGCSObjectAllowedCharacterSet];
- return [string stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacters];
- }
- + (nullable NSString *)MIMETypeForExtension:(NSString *)extension {
- if (extension == nil) {
- return nil;
- }
- CFStringRef pathExtension = (__bridge_retained CFStringRef)extension;
- CFStringRef type =
- UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, pathExtension, NULL);
- NSString *mimeType =
- (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass(type, kUTTagClassMIMEType);
- CFRelease(pathExtension);
- if (type != NULL) {
- CFRelease(type);
- }
- return mimeType;
- }
- + (NSString *)queryStringForDictionary:(nullable NSDictionary *)dictionary {
- if (!dictionary) {
- return @"";
- }
- __block NSMutableArray *queryItems = [[NSMutableArray alloc] initWithCapacity:[dictionary count]];
- [dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *_Nonnull name, NSString *_Nonnull value,
- BOOL *_Nonnull stop) {
- NSString *item =
- [FIRStorageUtils GCSEscapedString:[NSString stringWithFormat:@"%@=%@", name, value]];
- [queryItems addObject:item];
- }];
- return [queryItems componentsJoinedByString:@"&"];
- }
- + (NSURLRequest *)defaultRequestForPath:(FIRStoragePath *)path {
- NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
- NSURLComponents *components = [[NSURLComponents alloc] init];
- [components setScheme:kFIRStorageScheme];
- [components setHost:kFIRStorageHost];
- NSString *encodedPath = [self encodedURLForPath:path];
- [components setPercentEncodedPath:encodedPath];
- [request setURL:components.URL];
- return request;
- }
- + (NSURLRequest *)defaultRequestForPath:(FIRStoragePath *)path
- queryParams:(NSDictionary<NSString *, NSString *> *)queryParams {
- NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
- NSURLComponents *components = [[NSURLComponents alloc] init];
- [components setScheme:kFIRStorageScheme];
- [components setHost:kFIRStorageHost];
- NSMutableArray<NSURLQueryItem *> *queryItems = [NSMutableArray new];
- for (NSString *key in queryParams) {
- [queryItems addObject:[NSURLQueryItem queryItemWithName:key value:queryParams[key]]];
- }
- [components setQueryItems:queryItems];
- // NSURLComponents does not encode "+" as "%2B". This is however required by our backend, as
- // it treats "+" as a shorthand encoding for spaces. See also
- // https://stackoverflow.com/questions/31577188/how-to-encode-into-2b-with-nsurlcomponents
- [components setPercentEncodedQuery:[[components percentEncodedQuery]
- stringByReplacingOccurrencesOfString:@"+"
- withString:@"%2B"]];
- NSString *encodedPath = [self encodedURLForPath:path];
- [components setPercentEncodedPath:encodedPath];
- [request setURL:components.URL];
- return request;
- }
- + (NSString *)encodedURLForPath:(FIRStoragePath *)path {
- NSString *bucketName = [FIRStorageUtils GCSEscapedString:path.bucket];
- NSString *objectName = [FIRStorageUtils GCSEscapedString:path.object];
- NSString *bucketFormat = [NSString stringWithFormat:kFIRStorageBucketPathFormat, bucketName];
- NSString *urlPath = [@"/" stringByAppendingPathComponent:bucketFormat];
- if (objectName) {
- NSString *objectFormat = [NSString stringWithFormat:kFIRStorageObjectPathFormat, objectName];
- urlPath = [urlPath stringByAppendingFormat:@"/%@", objectFormat];
- } else {
- urlPath = [urlPath stringByAppendingString:@"/o"];
- }
- return [@"/" stringByAppendingString:[kFIRStorageVersionPath stringByAppendingString:urlPath]];
- }
- + (NSError *)storageErrorWithDescription:(NSString *)description code:(NSInteger)code {
- return [NSError errorWithDomain:FIRStorageErrorDomain
- code:code
- userInfo:@{NSLocalizedDescriptionKey : description}];
- }
- + (NSTimeInterval)computeRetryIntervalFromRetryTime:(NSTimeInterval)retryTime {
- // GTMSessionFetcher's retry starts at 1 second and then doubles every time. We use this
- // information to compute a best-effort estimate of what to translate the user provided retry
- // time into.
- // Note that this is the same as 2 << (log2(retryTime) - 1), but deemed more readable.
- NSTimeInterval lastInterval = 1.0;
- NSTimeInterval sumOfAllIntervals = 1.0;
- while (sumOfAllIntervals < retryTime) {
- lastInterval *= 2;
- sumOfAllIntervals += lastInterval;
- }
- return lastInterval;
- }
- @end
- @implementation NSDictionary (FIRStorageNSDictionaryJSONHelpers)
- + (nullable instancetype)frs_dictionaryFromJSONData:(nullable NSData *)data {
- if (!data) {
- return nil;
- }
- return [NSJSONSerialization JSONObjectWithData:data
- options:NSJSONReadingMutableContainers
- error:nil];
- }
- @end
- @implementation NSData (FIRStorageNSDataJSONHelpers)
- + (nullable instancetype)frs_dataFromJSONDictionary:(nullable NSDictionary *)dictionary {
- if (!dictionary) {
- return nil;
- }
- return [NSJSONSerialization dataWithJSONObject:dictionary options:0 error:nil];
- }
- @end
|