增加换肤功能

This commit is contained in:
启星
2025-08-14 10:07:49 +08:00
parent f6964c1e89
commit 4f9318d98e
8789 changed files with 978530 additions and 2 deletions

View File

@@ -0,0 +1,20 @@
//
// NSData+OSS.h
// AliyunOSSSDK
//
// Created by ws on 2023/12/28.
// Copyright © 2023 aliyun. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface NSData (OSS)
- (NSString *)hexString;
- (NSData *)calculateSha256;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,41 @@
//
// NSData+OSS.m
// AliyunOSSSDK
//
// Created by ws on 2023/12/28.
// Copyright © 2023 aliyun. All rights reserved.
//
#import "NSData+OSS.h"
#import <CommonCrypto/CommonDigest.h>
@implementation NSData (OSS)
- (NSString *)hexString {
NSMutableString *hexString = [NSMutableString string];
Byte *byte = (Byte *)[self bytes];
for (int i = 0; i<[self length]; i++) {
[hexString appendFormat:@"%x", (*(byte + i) >> 4) & 0xf];
[hexString appendFormat:@"%x", *(byte + i) & 0xf];
}
return hexString;
}
- (NSData *)calculateSha256 {
unsigned char *digest = NULL;
digest = malloc(CC_SHA256_DIGEST_LENGTH * sizeof(unsigned char));
memset(digest, 0x0, CC_SHA256_DIGEST_LENGTH);
CC_SHA256(self.bytes, (CC_LONG)self.length, digest);
if (digest) {
NSData *data = [NSData dataWithBytes:digest length:CC_SHA256_DIGEST_LENGTH];
free(digest);
return data;
}
free(digest);
return nil;
}
@end

View File

@@ -0,0 +1,22 @@
//
// NSDate+OSS.h
// AliyunOSSSDK
//
// Created by huaixu on 2018/7/31.
// Copyright © 2018年 aliyun. All rights reserved.
//
#import <Foundation/Foundation.h>
/**
Categories NSDate
*/
@interface NSDate (OSS)
+ (void)oss_setClockSkew:(NSTimeInterval)clockSkew;
+ (NSDate *)oss_dateFromString:(NSString *)string;
+ (NSDate *)oss_clockSkewFixedDate;
- (NSString *)oss_asStringValue;
+ (NSDate *)oss_dateFromString:(NSString *)string
dateFormat:(NSString *)dateFormat;
- (NSString *)oss_asStringValueWithDateFormat:(NSString *)dateFormat;
@end

View File

@@ -0,0 +1,68 @@
//
// NSDate+OSS.m
// AliyunOSSSDK
//
// Created by huaixu on 2018/7/31.
// Copyright © 2018 aliyun. All rights reserved.
//
#import "NSDate+OSS.h"
@implementation NSDate (OSS)
NSString * const serverReturnDateFormat = @"EEE, dd MMM yyyy HH:mm:ss z";
static NSTimeInterval _clockSkew = 0.0;
+ (void)oss_setClockSkew:(NSTimeInterval)clockSkew {
@synchronized(self) {
_clockSkew = clockSkew;
}
}
+ (NSDate *)oss_clockSkewFixedDate {
NSTimeInterval skew = 0.0;
@synchronized(self) {
skew = _clockSkew;
}
return [[NSDate date] dateByAddingTimeInterval:(-1 * skew)];
}
+ (NSDate *)oss_dateFromString:(NSString *)string {
NSDateFormatter *dateFormatter = [NSDateFormatter new];
dateFormatter.timeZone = [NSTimeZone timeZoneWithName:@"GMT"];
dateFormatter.locale = [NSLocale localeWithLocaleIdentifier:@"en_US"];
dateFormatter.dateFormat = serverReturnDateFormat;
return [dateFormatter dateFromString:string];
}
- (NSString *)oss_asStringValue {
NSDateFormatter *dateFormatter = [NSDateFormatter new];
dateFormatter.timeZone = [NSTimeZone timeZoneWithName:@"GMT"];
dateFormatter.locale = [NSLocale localeWithLocaleIdentifier:@"en_US"];
dateFormatter.dateFormat = serverReturnDateFormat;
return [dateFormatter stringFromDate:self];
}
+ (NSDate *)oss_dateFromString:(NSString *)string
dateFormat:(NSString *)dateFormat {
NSDateFormatter *dateFormatter = [NSDateFormatter new];
dateFormatter.timeZone = [NSTimeZone timeZoneWithName:@"GMT"];
dateFormatter.locale = [NSLocale localeWithLocaleIdentifier:@"en_US"];
dateFormatter.dateFormat = dateFormat;
return [dateFormatter dateFromString:string];
}
- (NSString *)oss_asStringValueWithDateFormat:(NSString *)dateFormat {
NSDateFormatter *dateFormatter = [NSDateFormatter new];
dateFormatter.timeZone = [NSTimeZone timeZoneWithName:@"GMT"];
dateFormatter.locale = [NSLocale localeWithLocaleIdentifier:@"en_US"];
dateFormatter.dateFormat = dateFormat;
return [dateFormatter stringFromDate:self];
}
@end

View File

@@ -0,0 +1,15 @@
//
// NSMutableData+OSS_CRC.h
// AliyunOSSSDK
//
// Created by 怀叙 on 2017/11/29.
// Copyright © 2017年 阿里云. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface NSMutableData (OSS_CRC)
- (uint64_t)oss_crc64;
@end

View File

@@ -0,0 +1,19 @@
//
// NSMutableData+OSS_CRC.m
// AliyunOSSSDK
//
// Created by 怀 on 2017/11/29.
// Copyright © 2017 . All rights reserved.
//
#import "NSMutableData+OSS_CRC.h"
#include "aos_crc64.h"
@implementation NSMutableData (OSS_CRC)
- (uint64_t)oss_crc64
{
return aos_crc64(0, self.mutableBytes, self.length);
}
@end

View File

@@ -0,0 +1,15 @@
//
// NSMutableDictionary+OSS.h
// AliyunOSSSDK
//
// Created by huaixu on 2018/8/1.
// Copyright © 2018年 aliyun. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface NSMutableDictionary (OSS)
- (void)oss_setObject:(id)anObject forKey:(id <NSCopying>)aKey;
@end

View File

@@ -0,0 +1,19 @@
//
// NSMutableDictionary+OSS.m
// AliyunOSSSDK
//
// Created by huaixu on 2018/8/1.
// Copyright © 2018 aliyun. All rights reserved.
//
#import "NSMutableDictionary+OSS.h"
@implementation NSMutableDictionary (OSS)
- (void)oss_setObject:(id)anObject forKey:(id <NSCopying>)aKey {
if (anObject && aKey) {
[self setObject:anObject forKey:aKey];
}
}
@end

View File

@@ -0,0 +1,19 @@
//
// NSSet+OSS.h
// AliyunOSSSDK
//
// Created by ws on 2023/12/28.
// Copyright © 2023 aliyun. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface NSSet (OSS)
- (NSString *)componentsJoinedByString:(NSString *)separator;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,30 @@
//
// NSSet+OSS.m
// AliyunOSSSDK
//
// Created by ws on 2023/12/28.
// Copyright © 2023 aliyun. All rights reserved.
//
#import "NSSet+OSS.h"
@implementation NSSet (OSS)
- (NSString *)componentsJoinedByString:(NSString *)separator {
NSMutableString *builder = [NSMutableString new];
int i = 0;
for (NSObject *part in self) {
if ([part isKindOfClass:[NSString class]]) {
[builder appendString:(NSString *)part];
if (i < [self count] - 1) {
[builder appendString:separator];
}
}
i++;
}
return builder;
}
@end

View File

@@ -0,0 +1,34 @@
//
// OSSAllRequestNeededMessage.h
// AliyunOSSSDK
//
// Created by huaixu on 2018/1/22.
// Copyright © 2018年 aliyun. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "OSSConstants.h"
#import "OSSTask.h"
/**
All necessary information in one OSS request.
*/
@interface OSSAllRequestNeededMessage : NSObject
@property (nonatomic, strong) NSString *endpoint;
@property (nonatomic, strong) NSString *httpMethod;
@property (nonatomic, strong) NSString *bucketName;
@property (nonatomic, strong) NSString *objectKey;
@property (nonatomic, strong) NSString *contentType;
@property (nonatomic, strong) NSString *contentMd5;
@property (nonatomic, strong) NSString *range;
@property (nonatomic, strong) NSString *date;
@property (nonatomic, strong) NSMutableDictionary *headerParams;
@property (nonatomic, copy) NSDictionary *params;
@property (nonatomic, copy) NSString *contentSHA1;
@property (nonatomic, assign) BOOL isHostInCnameExcludeList;
@property (nonatomic, assign) BOOL isUseUrlSignature;
@property (nonatomic, copy) NSSet<NSString *> *additionalHeaderNames;
- (OSSTask *)validateRequestParamsInOperationType:(OSSOperationType)operType;
@end

View File

@@ -0,0 +1,72 @@
//
// OSSAllRequestNeededMessage.m
// AliyunOSSSDK
//
// Created by huaixu on 2018/1/22.
// Copyright © 2018 aliyun. All rights reserved.
//
#import "OSSAllRequestNeededMessage.h"
#import "OSSDefine.h"
#import "OSSUtil.h"
@implementation OSSAllRequestNeededMessage
- (instancetype)init
{
self = [super init];
if (self) {
_date = [[NSDate oss_clockSkewFixedDate] oss_asStringValue];
_headerParams = [NSMutableDictionary dictionary];
}
return self;
}
- (void)setHeaderParams:(NSMutableDictionary *)headerParams {
if (!headerParams || [headerParams isEqualToDictionary:_headerParams]) {
return;
}
_headerParams = [headerParams mutableCopy];
}
- (OSSTask *)validateRequestParamsInOperationType:(OSSOperationType)operType {
NSString * errorMessage = nil;
if (!self.endpoint) {
errorMessage = @"Endpoint should not be nil";
}
if (!self.bucketName && operType != OSSOperationTypeGetService) {
errorMessage = @"Bucket name should not be nil";
}
if (self.bucketName && ![OSSUtil validateBucketName:self.bucketName]) {
errorMessage = @"Bucket name invalid";
}
if (!self.objectKey &&
(operType != OSSOperationTypeGetBucket && operType != OSSOperationTypeCreateBucket
&& operType != OSSOperationTypeDeleteBucket && operType != OSSOperationTypeGetService
&& operType != OSSOperationTypeGetBucketACL&& operType != OSSOperationTypeDeleteMultipleObjects
&& operType != OSSOperationTypeListMultipartUploads
&& operType != OSSOperationTypeGetBucketInfo)) {
errorMessage = @"Object key should not be nil";
}
if (self.objectKey && ![OSSUtil validateObjectKey:self.objectKey]) {
errorMessage = @"Object key invalid";
}
if (errorMessage) {
return [OSSTask taskWithError:[NSError errorWithDomain:OSSClientErrorDomain
code:OSSClientErrorCodeInvalidArgument
userInfo:@{OSSErrorMessageTOKEN: errorMessage}]];
} else {
return [OSSTask taskWithResult:nil];
}
}
@end

533
Pods/AliyunOSSiOS/AliyunOSSSDK/OSSClient.h generated Normal file
View File

@@ -0,0 +1,533 @@
//
// OSSClient.h
// oss_ios_sdk
//
// Created by zhouzhuo on 8/16/15.
// Copyright (c) 2015 aliyun.com. All rights reserved.
//
#import <Foundation/Foundation.h>
@class OSSGetServiceRequest;
@class OSSCreateBucketRequest;
@class OSSDeleteBucketRequest;
@class OSSHeadObjectRequest;
@class OSSGetBucketRequest;
@class OSSGetBucketACLRequest;
@class OSSGetObjectRequest;
@class OSSGetObjectACLRequest;
@class OSSPutObjectRequest;
@class OSSPutObjectACLRequest;
@class OSSDeleteObjectRequest;
@class OSSDeleteMultipleObjectsRequest;
@class OSSCopyObjectRequest;
@class OSSInitMultipartUploadRequest;
@class OSSUploadPartRequest;
@class OSSCompleteMultipartUploadRequest;
@class OSSListPartsRequest;
@class OSSListMultipartUploadsRequest;
@class OSSAbortMultipartUploadRequest;
@class OSSAppendObjectRequest;
@class OSSResumableUploadRequest;
@class OSSMultipartUploadRequest;
@class OSSCallBackRequest;
@class OSSImagePersistRequest;
@class OSSGetBucketInfoRequest;
@class OSSPutSymlinkRequest;
@class OSSGetSymlinkRequest;
@class OSSRestoreObjectRequest;
@class OSSGetObjectTaggingRequest;
@class OSSDeleteObjectTaggingRequest;
@class OSSPutObjectTaggingRequest;
@class OSSTask;
@class OSSExecutor;
@class OSSNetworking;
@class OSSClientConfiguration;
@protocol OSSCredentialProvider;
NS_ASSUME_NONNULL_BEGIN
/**
OSSClient is the entry class to access OSS in an iOS client. It provides all the methods to communicate with OSS.
Generally speaking, only one instance of OSSClient is needed in the whole app.
*/
@interface OSSClient : NSObject
/**
OSS endpoint. It varies in different regions. Please check out OSS official website for the exact endpoints for your data.
*/
@property (nonatomic, strong) NSString * endpoint;
/**
The networking instance for sending and receiving data
*/
@property (nonatomic, strong) OSSNetworking * networking;
/**
The credential provider instance
*/
@property (nonatomic, strong) id<OSSCredentialProvider> credentialProvider;
/**
Client configuration instance
*/
@property (nonatomic, strong) OSSClientConfiguration * clientConfiguration;
/// OSS services Region
@property (nonatomic, copy) NSString *region;
/// cloudBoxId OSS cloud box id
@property (nonatomic, copy) NSString *cloudBoxId;
/**
oss operation task queue
*/
@property (nonatomic, strong, readonly) OSSExecutor * ossOperationExecutor;
/**
Initializes an OSSClient instance with the default client configuration.
@endpoint it specifies domain of the bucket's region. Starting 2017, the domain must be prefixed with "https://" to follow Apple's ATS policy.
For example: "https://oss-cn-hangzhou.aliyuncs.com"
@credentialProvider The credential provider
*/
- (instancetype)initWithEndpoint:(NSString *)endpoint
credentialProvider:(id<OSSCredentialProvider>) credentialProvider;
/**
Initializes an OSSClient with the custom client configuration.
@endpoint it specifies domain of the bucket's region. Starting 2017, the domain must be prefixed with "https://" to follow Apple's ATS policy.
For example: "https://oss-cn-hangzhou.aliyuncs.com"
@credentialProvider The credential provider
@conf The custom client configuration such as retry time, timeout values, etc.
*/
- (instancetype)initWithEndpoint:(NSString *)endpoint
credentialProvider:(id<OSSCredentialProvider>)credentialProvider
clientConfiguration:(OSSClientConfiguration *)conf;
#pragma mark restful-api
/**
The corresponding RESTFul API: GetService
Gets all the buckets of the current user
Notes
1. STS is not supported yet in this call.
2. When all buckets are returned, the xml in response body does not have nodes of Prefix, Marker, MaxKeys, IsTruncated and NextMarker.
If there're remaining buckets to return, the xml will have these nodes. The nextMarker is the value of marker in the next call.
*/
- (OSSTask *)getService:(OSSGetServiceRequest *)request;
@end
@interface OSSClient (Bucket)
/**
The corresponding RESTFul API: PutBucket
Creates a bucket--it does not support anonymous access. By default, the datacenter used is oss-cn-hangzhou.
Callers could explicitly specify the datacenter for the bucket to optimize the performance and cost or meet the regulation requirement.
Notes:
1. STS is not supported yet.
*/
- (OSSTask *)createBucket:(OSSCreateBucketRequest *)request;
/**
The corresponding RESTFul API: DeleteBucket
Deletes a bucket.
*/
- (OSSTask *)deleteBucket:(OSSDeleteBucketRequest *)request;
/**
The corresponding RESTFul API: GetBucket
Lists all objects in a bucket. It could be specified with filters such as prefix, marker, delimeter and max-keys.
*/
- (OSSTask *)getBucket:(OSSGetBucketRequest *)request;
/**
The corresponding RESTFul API: GetBucketInfo
Gets the {@link Bucket}'s basic information as well as its ACL.
*/
- (OSSTask *)getBucketInfo:(OSSGetBucketInfoRequest *)request;
/**
The corresponding RESTFul API: GetBucketACL
Gets the bucket ACL.
*/
- (OSSTask *)getBucketACL:(OSSGetBucketACLRequest *)request;
@end
@interface OSSClient (Object)
/**
The corresponding RESTFul API: HeadObject
Gets the object's metadata information. The object's content is not returned.
*/
- (OSSTask *)headObject:(OSSHeadObjectRequest *)request;
/**
The corresponding RESTFul API: GetObject
Gets the whole object (includes content). It requires caller have read permission on the object.
*/
- (OSSTask *)getObject:(OSSGetObjectRequest *)request;
/**
The corresponding RESTFul API: GetObjectACL
get the acl of an object.
*/
- (OSSTask *)getObjectACL:(OSSGetObjectACLRequest *)request;
/**
The corresponding RESTFul API: PutObject
Uploads a file.
*/
- (OSSTask *)putObject:(OSSPutObjectRequest *)request;
/**
Sets the object's ACL. Right now an object has three access permissions: private, public-ready, public-read-write.
The operation specifies the x-oss-object-acl header in the put request. The caller must be the owner of the object.
If succeeds, it returns HTTP status 200; otherwise it returns related error code and error messages.
*/
- (OSSTask *)putObjectACL:(OSSPutObjectACLRequest *)request;
/**
The corresponding RESTFul API: AppendObject
Appends data to an existing or non-existing object. The object created by this operation is appendable.
As a comparison, the object created by Put Object is normal (non-appendable).
*/
- (OSSTask *)appendObject:(OSSAppendObjectRequest *)request;
/**
* @brief Appends data to an existing or non-existing object on the OSS server.
* The object created by this operation is appendable.
* @request request
* @crc64ecma crc64ecma
* if object has been stored on OSS server, you need to invoke headObject
* api get object's crc64ecma,then use this api to append data to the
* object.
*/
- (OSSTask *)appendObject:(OSSAppendObjectRequest *)request withCrc64ecma:(nullable NSString *)crc64ecma;
/**
The corresponding RESTFul API: copyObject
Copies an existing object to another one.The operation sends a PUT request with x-oss-copy-source header to specify the source object.
OSS server side will detect and copy the object. If it succeeds, the new object's metadata information will be returned.
The operation applies for files less than 1GB. For big files, use UploadPartCopy RESTFul API.
*/
- (OSSTask *)copyObject:(OSSCopyObjectRequest *)request;
/**
* Batch deletes the specified files under a specific bucket. If the files
* are non-exist, the operation will still return successful.
*
* @param request
* A OSSDeleteMultipleObjectsRequest instance which specifies the
* bucket and file keys to delete.
* @return A OSSTask with result of OSSDeleteMultipleObjectsResult instance which specifies each
* file's result in normal mode or only failed deletions in quite
* mode. By default it's quite mode.
*/
- (OSSTask *)deleteMultipleObjects:(OSSDeleteMultipleObjectsRequest *)request;
/**
The corresponding RESTFul API: DeleteObject
Deletes an object
*/
- (OSSTask *)deleteObject:(OSSDeleteObjectRequest *)request;
/**
* Creates a symbol link to a target file under the bucket---this is not
* supported for archive class bucket.
*
* @param request
* A OSSPutSymlinkRequest instance that specifies the
* bucket name, symlink name.
* @return An instance of OSSTask. On successful execution, `task.result` will
* contain an instance of `OSSPutSymlinkResult`,otherwise will contain
* an instance of NSError.
*
* for more information,please refer to https://help.aliyun.com/document_detail/45126.html
*/
- (OSSTask *)putSymlink:(OSSPutSymlinkRequest *)request;
/**
* Gets the symlink information for the given symlink name.
*
* @param request
* A OSSGetSymlinkRequest instance which specifies the bucket
* name and symlink name.
* @return An instance of OSSTask. On successful execution, `task.result` will
* contain an instance of `OSSGetSymlinkResult`,otherwise will contain
* an instance of NSError.
*
* for more information,please refer to https://help.aliyun.com/document_detail/45146.html
*/
- (OSSTask *)getSymlink:(OSSGetSymlinkRequest *)request;
/**
* Restores the object of archive storage. The function is not applicable to
* Normal or IA storage. The restoreObject() needs to be called prior to
* calling getObject() on an archive object.
*
* @param request
* A container for the necessary parameters to execute the RestoreObject
* service method.
*
* @return An instance of OSSTask. On successful execution, `task.result` will
* contain an instance of `OSSRestoreObjectResult`,otherwise will contain
* an instance of NSError.
*
* for more information,please refer to https://help.aliyun.com/document_detail/52930.html
*/
- (OSSTask *)restoreObject:(OSSRestoreObjectRequest *)request;
/**
* You can call this operation to query the tags of an object.
*
* @param request
* A OSSGetObjectTaggingRequest instance which specifies the bucket
* name and object key.
*
* @return An instance of OSSTask. On successful execution, `task.result` will
* contain an instance of `OSSGetObjectTaggingResult`,otherwise will contain
* an instance of NSError.
*
* for more information,please refer to https://help.aliyun.com/document_detail/114878.html
*/
- (OSSTask *)getObjectTagging:(OSSGetObjectTaggingRequest *)request;
/**
* You can call this operation to add tags to an object or update the tags added to
* the bucket. The object tagging feature uses a key-value pair to tag an object.
*
* @param request
* A OSSPutObjectTaggingRequest instance which specifies the bucket
* name、object key and tags.
*
* @return An instance of OSSTask. On successful execution, `task.result` will
* contain an instance of `OSSPutObjectTaggingResult`,otherwise will contain
* an instance of NSError.
*
* for more information,please refer to https://help.aliyun.com/document_detail/114855.html
*/
- (OSSTask *)putObjectTagging:(OSSPutObjectTaggingRequest *)request;
/**
* You can call this operation to delete the tags of a specified object.
*
* @param request
* A OSSDeleteObjectTaggingRequest instance which specifies the bucket
* name and object key.
*
* @return An instance of OSSTask. On successful execution, `task.result` will
* contain an instance of `OSSDeleteObjectTaggingResult`,otherwise will contain
* an instance of NSError.
*
* for more information,please refer to https://help.aliyun.com/document_detail/114879.html
*/
- (OSSTask *)deleteObjectTagging:(OSSDeleteObjectTaggingRequest *)request;
@end
@interface OSSClient (MultipartUpload)
/**
The corresponding RESTFul API: InitiateMultipartUpload
Initiates a multipart upload to get a upload Id. It's needed before starting uploading parts data.
The upload Id is used for subsequential operations such as aborting the upload, querying the uploaded parts, etc.
*/
- (OSSTask *)multipartUploadInit:(OSSInitMultipartUploadRequest *)request;
/**
The corresponding RESTFul API: UploadPart
After the multipart upload is initiated, this API could be called to upload the data to the target file with the upload Id.
Every uploaded part has a unique id called part number, which ranges from 1 to 10,000.
For a given upload Id, the part number identifies the specific range of the data in the whole file.
If the same part number is used for another upload, the existing data will be overwritten by the new upload.
Except the last part, all other part's minimal size is 100KB.
But no minimal size requirement on the last part.
*/
- (OSSTask *)uploadPart:(OSSUploadPartRequest *)request;
/**
The corresponding RESTFul API: CompleteMultipartUpload
This API is to complete the multipart upload after all parts data have been uploaded.
It must be provided with a valid part list (each part has the part number and ETag).
OSS will validate every part and then complete the multipart upload.
If any part is invalid (e.g. the part is updated by another part upload), this API will fail.
*/
- (OSSTask *)completeMultipartUpload:(OSSCompleteMultipartUploadRequest *)request;
/**
The corresponding RESTFul API: ListParts
Lists all uploaded parts of the specified upload id.
*/
- (OSSTask *)listParts:(OSSListPartsRequest *)request;
/**
The corresponding RESTFul API: ListMultipartUploads
Lists all multipart uploads with the specified bucket.
*/
- (OSSTask *)listMultipartUploads:(OSSListMultipartUploadsRequest *)request;
/**
The corresponding RESTFul API: AbortMultipartUpload
Aborts the multipart upload by the specified upload Id.
Once the multipart upload is aborted by this API, all parts data will be deleted and the upload Id is invalid anymore.
*/
- (OSSTask *)abortMultipartUpload:(OSSAbortMultipartUploadRequest *)request;
- (OSSTask *)abortResumableMultipartUpload:(OSSResumableUploadRequest *)request;
/**
Multipart upload API
*/
- (OSSTask *)multipartUpload:(OSSMultipartUploadRequest *)request;
/**
TODOTODO
Resumable upload API
This API wraps the multipart upload and also enables resuming upload by reading/writing the checkpoint data.
For a new file, multipartUploadInit() needs to be called first to get the upload Id. Then use this upload id to call this API to upload the data.
If the upload fails, checks the error messages:
If it's a recoverable error, then call this API again with the same upload Id to retry. The uploaded data will not be uploaded again.
Otherwise then you may need to recreates a new upload Id and call this method again.
Check out demo for the detail.
*/
- (OSSTask *)resumableUpload:(OSSResumableUploadRequest *)request;
/**
* multipart upload sequentially in order,support resume upload
*/
- (OSSTask *)sequentialMultipartUpload:(OSSResumableUploadRequest *)request;
@end
@interface OSSClient (PresignURL)
/**
Generates a signed URL for the object and anyone has this URL will get the GET permission on the object.
@bucketName object's bucket name
@objectKey Object name
@interval Expiration time in seconds. The URL could be specified with the expiration time to limit the access window on the object.
*/
- (OSSTask *)presignConstrainURLWithBucketName:(NSString *)bucketName
withObjectKey:(NSString *)objectKey
withExpirationInterval:(NSTimeInterval)interval;
/**
Generates a signed URL for the object and anyone has this URL will get the specified permission on the object.
@bucketName object's bucket name
@objectKey Object name
@interval Expiration time in seconds. The URL could be specified with the expiration time to limit the access window on the object.
@parameter it could specify allowed HTTP methods
*/
- (OSSTask *)presignConstrainURLWithBucketName:(NSString *)bucketName
withObjectKey:(NSString *)objectKey
withExpirationInterval:(NSTimeInterval)interval
withParameters:(NSDictionary *)parameters;
/**
Generates a signed URL for the object and anyone has this URL will get the specified permission on the object. currently only support get and head method.
@bucketName object's bucket name
@objectKey Object name
@httpMethod http method.currently only support get and head.
@interval Expiration time in seconds. The URL could be specified with the expiration time to limit the access window on the object.
@parameter it could specify allowed HTTP methods
*/
- (OSSTask *)presignConstrainURLWithBucketName:(NSString *)bucketName
withObjectKey:(NSString *)objectKey
httpMethod:(NSString *)method
withExpirationInterval:(NSTimeInterval)interval
withParameters:(NSDictionary *)parameters;
/// Generates a signed URL for the object and anyone has this URL will get the specified permission on the object.
/// @param bucketName object's bucket name
/// @param objectKey Object name
/// @param method http method.currently only support get and head.
/// @param interval Expiration time in seconds. The URL could be specified with the expiration time to limit the access window on the object.
/// @param parameters it could specify allowed HTTP methods
/// @param contentType Content-Type to url sign
/// @param contentMd5 Content-MD5 to url sign
- (OSSTask *)presignConstrainURLWithBucketName:(NSString *)bucketName
withObjectKey:(NSString *)objectKey
httpMethod:(NSString *)method
withExpirationInterval:(NSTimeInterval)interval
withParameters:(NSDictionary *)parameters
contentType:(nullable NSString *)contentType
contentMd5:(nullable NSString *)contentMd5;
/// Generates a signed URL for the object and anyone has this URL will get the specified permission on the object.
/// @param bucketName object's bucket name
/// @param objectKey Object name
/// @param method http method.currently only support get and head.
/// @param interval Expiration time in seconds. The URL could be specified with the expiration time to limit the access window on the object.
/// @param parameters it could specify allowed HTTP methods
/// @param headers Content Type, Content-MD5, and all HTTP headers prefixed with 'x-oss-*'
- (OSSTask *)presignConstrainURLWithBucketName:(NSString *)bucketName
withObjectKey:(NSString *)objectKey
httpMethod:(NSString *)method
withExpirationInterval:(NSTimeInterval)interval
withParameters:(NSDictionary *)parameters
withHeaders:(nullable NSDictionary *)headers;
/**
If the object's ACL is public read or public read-write, use this API to generate a signed url for sharing.
@bucketName Object's bucket name
@objectKey Object name
*/
- (OSSTask *)presignPublicURLWithBucketName:(NSString *)bucketName
withObjectKey:(NSString *)objectKey;
/** TODOTODO
If the object's ACL is public read or public read-write, use this API to generate a signed url for sharing.
@bucketName Object's bucket name
@objectKey Object name
@parameter the request parameters.
*/
- (OSSTask *)presignPublicURLWithBucketName:(NSString *)bucketName
withObjectKey:(NSString *)objectKey
withParameters:(NSDictionary *)parameters;
@end
@interface OSSClient (ImageService)
/*
* image persist action
* https://help.aliyun.com/document_detail/55811.html
*/
- (OSSTask *)imageActionPersist:(OSSImagePersistRequest *)request;
@end
@interface OSSClient (Utilities)
/**
Checks if the object exists
@bucketName Object's bucket name
@objectKey Object name
return YES Object exists
return NO && *error = nil Object does not exist
return NO && *error != nil Error occured.
*/
- (BOOL)doesObjectExistInBucket:(NSString *)bucketName
objectKey:(NSString *)objectKey
error:(const NSError **)error;
@end
@interface OSSClient (Callback)
- (OSSTask *)triggerCallBack:(OSSCallBackRequest *)request;
@end
NS_ASSUME_NONNULL_END

2269
Pods/AliyunOSSiOS/AliyunOSSSDK/OSSClient.m generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,85 @@
//
// OSSCompat.h
// oss_ios_sdk_new
//
// Created by zhouzhuo on 9/10/15.
// Copyright (c) 2015 aliyun.com. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "OSSService.h"
@class OSSCancellationTokenSource;
typedef OSSCancellationTokenSource OSSTaskHandler;
NS_ASSUME_NONNULL_BEGIN
@interface OSSClient (Compat)
/**
The old version's upload API.
Please use putObject instead.
*/
- (OSSTaskHandler *)uploadData:(NSData *)data
withContentType:(NSString *)contentType
withObjectMeta:(NSDictionary *)meta
toBucketName:(NSString *)bucketName
toObjectKey:(NSString *)objectKey
onCompleted:(void(^)(BOOL, NSError *))onCompleted
onProgress:(void(^)(float progress))onProgress;
/**
The old version's download API.
Please use getObject instead.
*/
- (OSSTaskHandler *)downloadToDataFromBucket:(NSString *)bucketName
objectKey:(NSString *)objectKey
onCompleted:(void(^)(NSData *, NSError *))onCompleted
onProgress:(void(^)(float progress))onProgress;
/**
The old version's upload API.
Please use putObject instead.
*/
- (OSSTaskHandler *)uploadFile:(NSString *)filePath
withContentType:(NSString *)contentType
withObjectMeta:(NSDictionary *)meta
toBucketName:(NSString *)bucketName
toObjectKey:(NSString *)objectKey
onCompleted:(void(^)(BOOL, NSError *))onCompleted
onProgress:(void(^)(float progress))onProgress;
/**
The old version's download API.
Please use getObject instead.
*/
- (OSSTaskHandler *)downloadToFileFromBucket:(NSString *)bucketName
objectKey:(NSString *)objectKey
toFile:(NSString *)filePath
onCompleted:(void(^)(BOOL, NSError *))onCompleted
onProgress:(void(^)(float progress))onProgress;
/**
The old version's upload API with resumable upload support.
Please use resumableUpload instead.
*/
- (OSSTaskHandler *)resumableUploadFile:(NSString *)filePath
withContentType:(NSString *)contentType
withObjectMeta:(NSDictionary *)meta
toBucketName:(NSString *)bucketName
toObjectKey:(NSString *)objectKey
onCompleted:(void(^)(BOOL, NSError *))onCompleted
onProgress:(void(^)(float progress))onProgress;
/**
The old version's delete API.
Please use deleteObject instead.
*/
- (void)deleteObjectInBucket:(NSString *)bucketName
objectKey:(NSString *)objectKey
onCompleted:(void(^)(BOOL, NSError *))onCompleted;
@end
NS_ASSUME_NONNULL_END

260
Pods/AliyunOSSiOS/AliyunOSSSDK/OSSCompat.m generated Normal file
View File

@@ -0,0 +1,260 @@
//
// OSSCompat.m
// oss_ios_sdk_new
//
// Created by zhouzhuo on 9/10/15.
// Copyright (c) 2015 aliyun.com. All rights reserved.
//
#import "OSSDefine.h"
#import "OSSCompat.h"
#import "OSSBolts.h"
#import "OSSModel.h"
@implementation OSSClient (Compat)
- (OSSTaskHandler *)uploadData:(NSData *)data
withContentType:(NSString *)contentType
withObjectMeta:(NSDictionary *)meta
toBucketName:(NSString *)bucketName
toObjectKey:(NSString *)objectKey
onCompleted:(void(^)(BOOL, NSError *))onCompleted
onProgress:(void(^)(float progress))onProgress {
OSSTaskHandler * bcts = [OSSCancellationTokenSource cancellationTokenSource];
[[[OSSTask taskWithResult:nil] continueWithExecutor:self.ossOperationExecutor withSuccessBlock:^id(OSSTask *task) {
OSSPutObjectRequest * put = [OSSPutObjectRequest new];
put.bucketName = bucketName;
put.objectKey = objectKey;
put.objectMeta = meta;
put.uploadingData = data;
put.contentType = contentType;
put.uploadProgress = ^(int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend) {
if (totalBytesExpectedToSend) {
onProgress((float)totalBytesSent / totalBytesExpectedToSend);
}
};
[bcts.token registerCancellationObserverWithBlock:^{
[put cancel];
}];
OSSTask * putTask = [self putObject:put];
[putTask waitUntilFinished];
onProgress(1.0f);
return putTask;
}] continueWithBlock:^id(OSSTask *task) {
if (task.error) {
onCompleted(NO, task.error);
} else {
onCompleted(YES, nil);
}
return nil;
}];
return bcts;
}
- (OSSTaskHandler *)downloadToDataFromBucket:(NSString *)bucketName
objectKey:(NSString *)objectKey
onCompleted:(void (^)(NSData *, NSError *))onCompleted
onProgress:(void (^)(float))onProgress {
OSSTaskHandler * bcts = [OSSCancellationTokenSource cancellationTokenSource];
[[[OSSTask taskWithResult:nil] continueWithExecutor:self.ossOperationExecutor withBlock:^id(OSSTask *task) {
OSSGetObjectRequest * get = [OSSGetObjectRequest new];
get.bucketName = bucketName;
get.objectKey = objectKey;
get.downloadProgress = ^(int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite) {
if (totalBytesExpectedToWrite) {
onProgress((float)totalBytesWritten / totalBytesExpectedToWrite);
}
};
[bcts.token registerCancellationObserverWithBlock:^{
[get cancel];
}];
OSSTask * getTask = [self getObject:get];
[getTask waitUntilFinished];
onProgress(1.0f);
return getTask;
}] continueWithBlock:^id(OSSTask *task) {
if (task.error) {
onCompleted(nil, task.error);
} else {
OSSGetObjectResult * result = task.result;
onCompleted(result.downloadedData, nil);
}
return nil;
}];
return bcts;
}
- (OSSTaskHandler *)downloadToFileFromBucket:(NSString *)bucketName
objectKey:(NSString *)objectKey
toFile:(NSString *)filePath
onCompleted:(void (^)(BOOL, NSError *))onCompleted
onProgress:(void (^)(float))onProgress {
OSSTaskHandler * bcts = [OSSCancellationTokenSource cancellationTokenSource];
[[[OSSTask taskWithResult:nil] continueWithExecutor:self.ossOperationExecutor withBlock:^id(OSSTask *task) {
OSSGetObjectRequest * get = [OSSGetObjectRequest new];
get.bucketName = bucketName;
get.objectKey = objectKey;
get.downloadToFileURL = [NSURL fileURLWithPath:filePath];
get.downloadProgress = ^(int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite) {
if (totalBytesExpectedToWrite) {
onProgress((float)totalBytesWritten / totalBytesExpectedToWrite);
}
};
[bcts.token registerCancellationObserverWithBlock:^{
[get cancel];
}];
OSSTask * getTask = [self getObject:get];
[getTask waitUntilFinished];
onProgress(1.0f);
return getTask;
}] continueWithBlock:^id(OSSTask *task) {
if (task.error) {
onCompleted(NO, task.error);
} else {
onCompleted(YES, nil);
}
return nil;
}];
return bcts;
}
- (void)deleteObjectInBucket:(NSString *)bucketName
objectKey:(NSString *)objectKey
onCompleted:(void (^)(BOOL, NSError *))onCompleted {
[[[OSSTask taskWithResult:nil] continueWithExecutor:self.ossOperationExecutor withBlock:^id(OSSTask *task) {
OSSDeleteObjectRequest * delete = [OSSDeleteObjectRequest new];
delete.bucketName = bucketName;
delete.objectKey = objectKey;
OSSTask * deleteTask = [self deleteObject:delete];
[deleteTask waitUntilFinished];
return deleteTask;
}] continueWithBlock:^id(OSSTask *task) {
if (task.error) {
onCompleted(NO, task.error);
} else {
onCompleted(YES, nil);
}
return nil;
}];
}
- (OSSTaskHandler *)uploadFile:(NSString *)filePath
withContentType:(NSString *)contentType
withObjectMeta:(NSDictionary *)meta
toBucketName:(NSString *)bucketName
toObjectKey:(NSString *)objectKey
onCompleted:(void (^)(BOOL, NSError *))onCompleted
onProgress:(void (^)(float))onProgress {
OSSTaskHandler * bcts = [OSSCancellationTokenSource cancellationTokenSource];
[[[OSSTask taskWithResult:nil] continueWithExecutor:self.ossOperationExecutor withSuccessBlock:^id(OSSTask *task) {
OSSPutObjectRequest * put = [OSSPutObjectRequest new];
put.bucketName = bucketName;
put.objectKey = objectKey;
put.objectMeta = meta;
put.uploadingFileURL = [NSURL fileURLWithPath:filePath];
put.contentType = contentType;
put.uploadProgress = ^(int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend) {
if (totalBytesExpectedToSend) {
onProgress((float)totalBytesSent / totalBytesExpectedToSend);
}
};
[bcts.token registerCancellationObserverWithBlock:^{
[put cancel];
}];
OSSTask * putTask = [self putObject:put];
[putTask waitUntilFinished];
onProgress(1.0f);
return putTask;
}] continueWithBlock:^id(OSSTask *task) {
if (task.error) {
onCompleted(NO, task.error);
} else {
onCompleted(YES, nil);
}
return nil;
}];
return bcts;
}
- (OSSTaskHandler *)resumableUploadFile:(NSString *)filePath
withContentType:(NSString *)contentType
withObjectMeta:(NSDictionary *)meta
toBucketName:(NSString *)bucketName
toObjectKey:(NSString *)objectKey
onCompleted:(void(^)(BOOL, NSError *))onComplete
onProgress:(void(^)(float progress))onProgress {
OSSTaskHandler * bcts = [OSSCancellationTokenSource cancellationTokenSource];
[[[OSSTask taskWithResult:nil] continueWithBlock:^id(OSSTask *task) {
NSURL * fileURL = [NSURL fileURLWithPath:filePath];
NSDate * lastModified;
NSError * error;
[fileURL getResourceValue:&lastModified forKey:NSURLContentModificationDateKey error:&error];
if (error) {
return [OSSTask taskWithError:error];
}
OSSResumableUploadRequest * resumableUpload = [OSSResumableUploadRequest new];
resumableUpload.bucketName = bucketName;
resumableUpload.deleteUploadIdOnCancelling = NO;//cancel not delete record file
resumableUpload.contentType = contentType;
resumableUpload.completeMetaHeader = meta;
NSString *cachesDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
resumableUpload.recordDirectoryPath = cachesDir; //default record file path
resumableUpload.uploadingFileURL = fileURL;
resumableUpload.objectKey = objectKey;
resumableUpload.uploadId = task.result;
resumableUpload.uploadingFileURL = [NSURL fileURLWithPath:filePath];
__weak OSSResumableUploadRequest * weakRef = resumableUpload;
resumableUpload.uploadProgress = ^(int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend) {
onProgress((float)totalBytesSent/totalBytesExpectedToSend);
if (bcts.token.isCancellationRequested || bcts.isCancellationRequested) {
[weakRef cancel];
}
OSSLogDebugNoFile(@"%lld %lld %lld", bytesSent, totalBytesSent, totalBytesExpectedToSend);
};
return [self resumableUpload:resumableUpload];
}] continueWithBlock:^id(OSSTask *task) {
if (task.cancelled) {
onComplete(NO, [NSError errorWithDomain:OSSClientErrorDomain
code:OSSClientErrorCodeTaskCancelled
userInfo:@{OSSErrorMessageTOKEN: @"This task is cancelled"}]);
} else if (task.error) {
onComplete(NO, task.error);
} else if (task.faulted) {
onComplete(NO, [NSError errorWithDomain:OSSClientErrorDomain
code:OSSClientErrorCodeExcpetionCatched
userInfo:@{OSSErrorMessageTOKEN: [NSString stringWithFormat:@"Catch exception - %@", task.exception]}]);
} else {
onComplete(YES, nil);
}
return nil;
}];
return bcts;
}
@end

View File

@@ -0,0 +1,144 @@
//
// OSSConstants.h
// AliyunOSSSDK
//
// Created by huaixu on 2018/1/22.
// Copyright © 2018年 aliyun. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
typedef NSString* _Nullable (^OSSCustomSignContentBlock) (NSString * contentToSign, NSError **error);
typedef NSData * _Nullable (^OSSResponseDecoderBlock) (NSData * data);
typedef void (^OSSNetworkingUploadProgressBlock) (int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend);
typedef void (^OSSNetworkingDownloadProgressBlock) (int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite);
typedef void (^OSSNetworkingRetryBlock) (void);
typedef void (^OSSNetworkingCompletionHandlerBlock) (id _Nullable responseObject, NSError * _Nullable error);
typedef void (^OSSNetworkingOnRecieveDataBlock) (NSData * data);
/**
The flag of verification about crc64
*/
typedef NS_ENUM(NSUInteger, OSSRequestCRCFlag) {
OSSRequestCRCUninitialized,
OSSRequestCRCOpen,
OSSRequestCRCClosed
};
/**
Retry type definition
*/
typedef NS_ENUM(NSInteger, OSSNetworkingRetryType) {
OSSNetworkingRetryTypeUnknown,
OSSNetworkingRetryTypeShouldRetry,
OSSNetworkingRetryTypeShouldNotRetry,
OSSNetworkingRetryTypeShouldRefreshCredentialsAndRetry,
OSSNetworkingRetryTypeShouldCorrectClockSkewAndRetry
};
/**
* @brief: The following constants are provided by OSSNetworking as possible operation types.
*/
typedef NS_ENUM(NSInteger, OSSOperationType) {
OSSOperationTypeGetService,
OSSOperationTypeCreateBucket,
OSSOperationTypeDeleteBucket,
OSSOperationTypeGetBucket,
OSSOperationTypeGetBucketInfo,
OSSOperationTypeGetBucketACL,
OSSOperationTypeHeadObject,
OSSOperationTypeGetObject,
OSSOperationTypeGetObjectACL,
OSSOperationTypePutObject,
OSSOperationTypePutObjectACL,
OSSOperationTypeAppendObject,
OSSOperationTypeDeleteObject,
OSSOperationTypeDeleteMultipleObjects,
OSSOperationTypeCopyObject,
OSSOperationTypeInitMultipartUpload,
OSSOperationTypeUploadPart,
OSSOperationTypeCompleteMultipartUpload,
OSSOperationTypeAbortMultipartUpload,
OSSOperationTypeListMultipart,
OSSOperationTypeListMultipartUploads,
OSSOperationTypeTriggerCallBack,
OSSOperationTypeImagePersist,
OSSOperationTypeRestoreObject,
OSSOperationTypePutSymlink,
OSSOperationTypeGetSymlink,
OSSOperationTypeGetObjectTagging,
OSSOperationTypePutObjectTagging,
OSSOperationTypeDeleteObjectTagging,
};
/**
* @brief: The following constants are provided by OSSClient as possible error codes.
*/
typedef NS_ENUM(NSInteger, OSSClientErrorCODE) {
OSSClientErrorCodeNetworkingFailWithResponseCode0,
OSSClientErrorCodeSignFailed,
OSSClientErrorCodeFileCantWrite,
OSSClientErrorCodeInvalidArgument,
OSSClientErrorCodeNilUploadid,
OSSClientErrorCodeTaskCancelled,
OSSClientErrorCodeNetworkError,
OSSClientErrorCodeInvalidCRC,
OSSClientErrorCodeCannotResumeUpload,
OSSClientErrorCodeExcpetionCatched,
OSSClientErrorCodeNotKnown,
OSSClientErrorCodeFileCantRead
};
typedef NS_ENUM(NSInteger, OSSXMLDictionaryAttributesMode)
{
OSSXMLDictionaryAttributesModePrefixed = 0, //default
OSSXMLDictionaryAttributesModeDictionary,
OSSXMLDictionaryAttributesModeUnprefixed,
OSSXMLDictionaryAttributesModeDiscard
};
typedef NS_ENUM(NSInteger, OSSXMLDictionaryNodeNameMode)
{
OSSXMLDictionaryNodeNameModeRootOnly = 0, //default
OSSXMLDictionaryNodeNameModeAlways,
OSSXMLDictionaryNodeNameModeNever
};
typedef NS_ENUM(NSInteger, OSSBucketStorageClass)
{
OSSBucketStorageClassStandard,
OSSBucketStorageClassIA,
OSSBucketStorageClassArchive
};
typedef NS_ENUM(NSInteger, OSSTerminationMode) {
OSSTerminationModeAll = 0,
OSSTerminationModeHasError
};
typedef NSString * OSSXMLDictionaryAttributeName NS_EXTENSIBLE_STRING_ENUM;
OBJC_EXTERN OSSXMLDictionaryAttributeName const OSSXMLDictionaryAttributesKey;
OBJC_EXTERN OSSXMLDictionaryAttributeName const OSSXMLDictionaryCommentsKey;
OBJC_EXTERN OSSXMLDictionaryAttributeName const OSSXMLDictionaryTextKey;
OBJC_EXTERN OSSXMLDictionaryAttributeName const OSSXMLDictionaryNodeNameKey;
OBJC_EXTERN OSSXMLDictionaryAttributeName const OSSXMLDictionaryAttributePrefix;
OBJC_EXTERN NSString * const OSSHTTPMethodHEAD;
OBJC_EXTERN NSString * const OSSHTTPMethodGET;
OBJC_EXTERN NSString * const OSSHTTPMethodPUT;
OBJC_EXTERN NSString * const OSSHTTPMethodPOST;
OBJC_EXTERN NSString * const OSSHTTPMethodDELETE;
typedef NS_ENUM(NSInteger, OSSSignVersion)
{
OSSSignVersionV1,
OSSSignVersionV4
};
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,21 @@
//
// OSSConstants.m
// AliyunOSSSDK
//
// Created by huaixu on 2018/1/22.
// Copyright © 2018 aliyun. All rights reserved.
//
#import "OSSConstants.h"
NSString * const OSSXMLDictionaryAttributesKey = @"__attributes";
NSString * const OSSXMLDictionaryCommentsKey = @"__comments";
NSString * const OSSXMLDictionaryTextKey = @"__text";
NSString * const OSSXMLDictionaryNodeNameKey = @"__name";
NSString * const OSSXMLDictionaryAttributePrefix = @"_";
NSString * const OSSHTTPMethodHEAD = @"HEAD";
NSString * const OSSHTTPMethodGET = @"GET";
NSString * const OSSHTTPMethodPUT = @"PUT";
NSString * const OSSHTTPMethodPOST = @"POST";
NSString * const OSSHTTPMethodDELETE = @"DELETE";

108
Pods/AliyunOSSiOS/AliyunOSSSDK/OSSDefine.h generated Normal file
View File

@@ -0,0 +1,108 @@
//
// OSSDefine.h
// AliyunOSSiOS
//
// Created by zhouzhuo on 5/1/16.
// Copyright © 2016 zhouzhuo. All rights reserved.
//
#import <Foundation/Foundation.h>
#ifndef OSSDefine_h
#define OSSDefine_h
#if TARGET_OS_IOS
#define OSSUAPrefix @"aliyun-sdk-ios"
#elif TARGET_OS_OSX
#define OSSUAPrefix @"aliyun-sdk-mac"
#endif
#define OSSSDKVersion @"2.11.0"
#define OSSListBucketResultXMLTOKEN @"ListBucketResult"
#define OSSNameXMLTOKEN @"Name"
#define OSSDelimiterXMLTOKEN @"Delimiter"
#define OSSMarkerXMLTOKEN @"Marker"
#define OSSKeyMarkerXMLTOKEN @"KeyMarker"
#define OSSNextMarkerXMLTOKEN @"NextMarker"
#define OSSNextKeyMarkerXMLTOKEN @"NextKeyMarker"
#define OSSUploadIdMarkerXMLTOKEN @"UploadIdMarker"
#define OSSNextUploadIdMarkerXMLTOKEN @"NextUploadIdMarker"
#define OSSMaxKeysXMLTOKEN @"MaxKeys"
#define OSSMaxUploadsXMLTOKEN @"MaxUploads"
#define OSSIsTruncatedXMLTOKEN @"IsTruncated"
#define OSSContentsXMLTOKEN @"Contents"
#define OSSUploadXMLTOKEN @"Upload"
#define OSSKeyXMLTOKEN @"Key"
#define OSSLastModifiedXMLTOKEN @"LastModified"
#define OSSETagXMLTOKEN @"ETag"
#define OSSTypeXMLTOKEN @"Type"
#define OSSSizeXMLTOKEN @"Size"
#define OSSStorageClassXMLTOKEN @"StorageClass"
#define OSSCommonPrefixesXMLTOKEN @"CommonPrefixes"
#define OSSOwnerXMLTOKEN @"Owner"
#define OSSAccessControlListXMLTOKEN @"AccessControlList"
#define OSSGrantXMLTOKEN @"Grant"
#define OSSIDXMLTOKEN @"ID"
#define OSSDisplayNameXMLTOKEN @"DisplayName"
#define OSSBucketsXMLTOKEN @"Buckets"
#define OSSBucketXMLTOKEN @"Bucket"
#define OSSCreationDate @"CreationDate"
#define OSSPrefixXMLTOKEN @"Prefix"
#define OSSUploadIdXMLTOKEN @"UploadId"
#define OSSLocationXMLTOKEN @"Location"
#define OSSNextPartNumberMarkerXMLTOKEN @"NextPartNumberMarker"
#define OSSMaxPartsXMLTOKEN @"MaxParts"
#define OSSPartXMLTOKEN @"Part"
#define OSSPartNumberXMLTOKEN @"PartNumber"
#define OSSClientErrorDomain @"com.aliyun.oss.clientError"
#define OSSServerErrorDomain @"com.aliyun.oss.serverError"
#define OSSErrorMessageTOKEN @"ErrorMessage"
#define OSSNetworkTaskMetrics @"NetworkTaskMetrics"
#define OSSHttpHeaderContentDisposition @"Content-Disposition"
#define OSSHttpHeaderXOSSCallback @"x-oss-callback"
#define OSSHttpHeaderXOSSCallbackVar @"x-oss-callback-var"
#define OSSHttpHeaderContentEncoding @"Content-Encoding"
#define OSSHttpHeaderContentType @"Content-Type"
#define OSSHttpHeaderContentMD5 @"Content-MD5"
#define OSSHttpHeaderCacheControl @"Cache-Control"
#define OSSHttpHeaderExpires @"Expires"
#define OSSHttpHeaderHashSHA1 @"x-oss-hash-sha1"
#define OSSHttpHeaderBucketACL @"x-oss-acl"
#define OSSHttpHeaderObjectACL @"x-oss-object-acl"
#define OSSHttpHeaderCopySource @"x-oss-copy-source"
#define OSSHttpHeaderSymlinkTarget @"x-oss-symlink-target"
#define OSSHttpHeaderDate @"Date"
#define OSSHttpHeaderDateEx @"x-oss-date"
#define OSSHttpHeaderSecurityToken @"x-oss-security-token"
#define OSSHttpHeaderAuthorization @"Authorization"
#define OSSHttpHeaderHost @"Host"
#define OSSHttpHeaderContentSha256 @"x-oss-content-sha256"
#define OSSRequestParameterExpires @"Expires"
#define OSSRequestParameterAccessKeyId @"OSSAccessKeyId"
#define OSSRequestParameterSignature @"Signature"
#define OSSHttpQueryProcess @"x-oss-process"
#define OSSPrefix @"x-oss-"
#define OSSDefaultRetryCount 3
#define OSSDefaultMaxConcurrentNum 5
#define OSSDefaultTimeoutForRequestInSecond 15
#define OSSDefaultTimeoutForResourceInSecond 7 * 24 * 60 * 60
#define OSSDefaultThreadNum 5
#define OSSAuthorizationPrefix @"OSS "
#define OSSProductDefault @"oss"
#define OSSProductCloudBox @"oss-cloudbox"
#define OSSContentStringToSign @"stringToSign"
#define OSSContentDate @"date"
#define OSSContentAlgorithm @"algorithm"
#define OSSContentRegion @"region"
#define OSSContentProduct @"product"
#endif /* OSSDefine_h */

View File

@@ -0,0 +1,31 @@
//
// OSSDeleteMultipleObjectsRequest.h
// AliyunOSSSDK
//
// Created by huaixu on 2018/1/26.
// Copyright © 2018年 aliyun. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "OSSRequest.h"
NS_ASSUME_NONNULL_BEGIN
@interface OSSDeleteMultipleObjectsRequest : OSSRequest
@property (nonatomic, copy) NSString *bucketName;
@property (nonatomic, copy) NSArray<NSString *> *keys;
/**
invalid value is @"url"
*/
@property (nonatomic, copy, nullable) NSString *encodingType;
/**
whether to show verbose result,the default value is YES.
*/
@property (nonatomic, assign) BOOL quiet;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,22 @@
//
// OSSDeleteMultipleObjectsRequest.m
// AliyunOSSSDK
//
// Created by huaixu on 2018/1/26.
// Copyright © 2018 aliyun. All rights reserved.
//
#import "OSSDeleteMultipleObjectsRequest.h"
@implementation OSSDeleteMultipleObjectsRequest
- (instancetype)init
{
self = [super init];
if (self) {
_quiet = YES;
}
return self;
}
@end

View File

@@ -0,0 +1,17 @@
//
// OSSDeleteMultipleObjectsResult.h
// AliyunOSSSDK
//
// Created by huaixu on 2018/1/26.
// Copyright © 2018年 aliyun. All rights reserved.
//
#import "OSSResult.h"
@interface OSSDeleteMultipleObjectsResult : OSSResult
@property (nonatomic, copy) NSArray<NSString *> *deletedObjects;
@property (nonatomic, copy) NSString *encodingType;
@end

View File

@@ -0,0 +1,13 @@
//
// OSSDeleteMultipleObjectsResult.m
// AliyunOSSSDK
//
// Created by huaixu on 2018/1/26.
// Copyright © 2018 aliyun. All rights reserved.
//
#import "OSSDeleteMultipleObjectsResult.h"
@implementation OSSDeleteMultipleObjectsResult
@end

View File

@@ -0,0 +1,23 @@
//
// OSSDeleteObjectTaggingRequest.h
// AliyunOSSSDK
//
// Created by ws on 2021/5/25.
// Copyright © 2021 aliyun. All rights reserved.
//
#import "OSSRequest.h"
NS_ASSUME_NONNULL_BEGIN
@interface OSSDeleteObjectTaggingRequest : OSSRequest
/* bucket name */
@property (nonatomic, copy) NSString *bucketName;
/* object name */
@property (nonatomic, copy) NSString *objectKey;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,17 @@
//
// OSSDeleteObjectTaggingRequest.m
// AliyunOSSSDK
//
// Created by ws on 2021/5/25.
// Copyright © 2021 aliyun. All rights reserved.
//
#import "OSSDeleteObjectTaggingRequest.h"
@implementation OSSDeleteObjectTaggingRequest
- (NSDictionary *)requestParams {
return @{@"tagging": @""};
}
@end

View File

@@ -0,0 +1,17 @@
//
// OSSDeleteObjectTaggingResult.h
// AliyunOSSSDK
//
// Created by ws on 2021/5/25.
// Copyright © 2021 aliyun. All rights reserved.
//
#import "OSSResult.h"
NS_ASSUME_NONNULL_BEGIN
@interface OSSDeleteObjectTaggingResult : OSSResult
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,13 @@
//
// OSSDeleteObjectTaggingResult.m
// AliyunOSSSDK
//
// Created by ws on 2022/8/4.
// Copyright © 2022 aliyun. All rights reserved.
//
#import "OSSDeleteObjectTaggingResult.h"
@implementation OSSDeleteObjectTaggingResult
@end

View File

@@ -0,0 +1,75 @@
// Software License Agreement (BSD License)
//
// Copyright (c) 2010-2016, Deusty, LLC
// All rights reserved.
//
// Redistribution and use of this software in source and binary forms,
// with or without modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Neither the name of Deusty nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific
// prior written permission of Deusty, LLC.
/**
* Welcome to CocoaLumberjack!
*
* The project page has a wealth of documentation if you have any questions.
*
* If you're new to the project you may wish to read "Getting Started" at:
* Documentation/GettingStarted.md
*
* Otherwise, here is a quick refresher.
* There are three steps to using the macros:
*
* Step 1:
* Import the header in your implementation or prefix file:
*
* #import <CocoaLumberjack/CocoaLumberjack.h>
*
* Step 2:
* Define your logging level in your implementation file:
*
* // Log levels: off, error, warn, info, verbose
* static const DDLogLevel ddLogLevel = DDLogLevelVerbose;
*
* Step 2 [3rd party frameworks]:
*
* Define your LOG_LEVEL_DEF to a different variable/function than ddLogLevel:
*
* // #undef LOG_LEVEL_DEF // Undefine first only if needed
* #define LOG_LEVEL_DEF myLibLogLevel
*
* Define your logging level in your implementation file:
*
* // Log levels: off, error, warn, info, verbose
* static const DDLogLevel myLibLogLevel = DDLogLevelVerbose;
*
* Step 3:
* Replace your NSLog statements with DDLog statements according to the severity of the message.
*
* NSLog(@"Fatal error, no dohickey found!"); -> OSSLogError(@"Fatal error, no dohickey found!");
*
* DDLog works exactly the same as NSLog.
* This means you can pass it multiple variables just like NSLog.
**/
#import <Foundation/Foundation.h>
// Disable legacy macros
#ifndef OSSDD_LEGACY_MACROS
#define OSSDD_LEGACY_MACROS 0
#endif
// Core
#import "OSSDDLog.h"
// Main macros
#import "OSSLogMacros.h"
// Loggers
#import "OSSFileLogger.h"
#import "OSSNSLogger.h"

View File

@@ -0,0 +1,860 @@
// Software License Agreement (BSD License)
//
// Copyright (c) 2010-2016, Deusty, LLC
// All rights reserved.
//
// Redistribution and use of this software in source and binary forms,
// with or without modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Neither the name of Deusty nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific
// prior written permission of Deusty, LLC.
#import <Foundation/Foundation.h>
// Enable 1.9.x legacy macros if imported directly
#ifndef OSSDD_LEGACY_MACROS
#define OSSDD_LEGACY_MACROS 1
#endif
#if OS_OBJECT_USE_OBJC
#define DISPATCH_QUEUE_REFERENCE_TYPE strong
#else
#define DISPATCH_QUEUE_REFERENCE_TYPE assign
#endif
@class OSSDDLogMessage;
@class OSSDDLoggerInformation;
@protocol OSSDDLogger;
@protocol OSSDDLogFormatter;
/**
* Define the standard options.
*
* We default to only 4 levels because it makes it easier for beginners
* to make the transition to a logging framework.
*
* More advanced users may choose to completely customize the levels (and level names) to suite their needs.
* For more information on this see the "Custom Log Levels" page:
* Documentation/CustomLogLevels.md
*
* Advanced users may also notice that we're using a bitmask.
* This is to allow for custom fine grained logging:
* Documentation/FineGrainedLogging.md
*
* -- Flags --
*
* Typically you will use the LOG_LEVELS (see below), but the flags may be used directly in certain situations.
* For example, say you have a lot of warning log messages, and you wanted to disable them.
* However, you still needed to see your error and info log messages.
* You could accomplish that with the following:
*
* static const DDLogLevel ddLogLevel = DDLogFlagError | DDLogFlagInfo;
*
* When LOG_LEVEL_DEF is defined as ddLogLevel.
*
* Flags may also be consulted when writing custom log formatters,
* as the DDLogMessage class captures the individual flag that caused the log message to fire.
*
* -- Levels --
*
* Log levels are simply the proper bitmask of the flags.
*
* -- Booleans --
*
* The booleans may be used when your logging code involves more than one line.
* For example:
*
* if (LOG_VERBOSE) {
* for (id sprocket in sprockets)
* DDLogVerbose(@"sprocket: %@", [sprocket description])
* }
*
* -- Async --
*
* Defines the default asynchronous options.
* The default philosophy for asynchronous logging is very simple:
*
* Log messages with errors should be executed synchronously.
* After all, an error just occurred. The application could be unstable.
*
* All other log messages, such as debug output, are executed asynchronously.
* After all, if it wasn't an error, then it was just informational output,
* or something the application was easily able to recover from.
*
* -- Changes --
*
* You are strongly discouraged from modifying this file.
* If you do, you make it more difficult on yourself to merge future bug fixes and improvements from the project.
* Instead, create your own MyLogging.h or ApplicationNameLogging.h or CompanyLogging.h
*
* For an example of customizing your logging experience, see the "Custom Log Levels" page:
* Documentation/CustomLogLevels.md
**/
/**
* Flags accompany each log. They are used together with levels to filter out logs.
*/
typedef NS_OPTIONS(NSUInteger, OSSDDLogFlag){
/**
* 0...00001 DDLogFlagError
*/
OSSDDLogFlagError = (1 << 0),
/**
* 0...00010 DDLogFlagWarning
*/
OSSDDLogFlagWarning = (1 << 1),
/**
* 0...00100 DDLogFlagInfo
*/
OSSDDLogFlagInfo = (1 << 2),
/**
* 0...01000 DDLogFlagDebug
*/
OSSDDLogFlagDebug = (1 << 3),
/**
* 0...10000 DDLogFlagVerbose
*/
OSSDDLogFlagVerbose = (1 << 4)
};
/**
* Log levels are used to filter out logs. Used together with flags.
*/
typedef NS_ENUM(NSUInteger, OSSDDLogLevel){
/**
* No logs
*/
OSSDDLogLevelOff = 0,
/**
* Error logs only
*/
OSSDDLogLevelError = (OSSDDLogFlagError),
/**
* Error and warning logs
*/
OSSDDLogLevelWarning = (OSSDDLogLevelError | OSSDDLogFlagWarning),
/**
* Error, warning and info logs
*/
OSSDDLogLevelInfo = (OSSDDLogLevelWarning | OSSDDLogFlagInfo),
/**
* Error, warning, info and debug logs
*/
OSSDDLogLevelDebug = (OSSDDLogLevelInfo | OSSDDLogFlagDebug),
/**
* Error, warning, info, debug and verbose logs
*/
OSSDDLogLevelVerbose = (OSSDDLogLevelDebug | OSSDDLogFlagVerbose),
/**
* All logs (1...11111)
*/
OSSDDLogLevelAll = NSUIntegerMax
};
NS_ASSUME_NONNULL_BEGIN
/**
* Extracts just the file name, no path or extension
*
* @param filePath input file path
* @param copy YES if we want the result to be copied
*
* @return the file name
*/
NSString * __nullable OSSDDExtractFileNameWithoutExtension(const char *filePath, BOOL copy);
/**
* The THIS_FILE macro gives you an NSString of the file name.
* For simplicity and clarity, the file name does not include the full path or file extension.
*
* For example: DDLogWarn(@"%@: Unable to find thingy", THIS_FILE) -> @"MyViewController: Unable to find thingy"
**/
#define THIS_FILE (DDExtractFileNameWithoutExtension(__FILE__, NO))
/**
* The THIS_METHOD macro gives you the name of the current objective-c method.
*
* For example: DDLogWarn(@"%@ - Requires non-nil strings", THIS_METHOD) -> @"setMake:model: requires non-nil strings"
*
* Note: This does NOT work in straight C functions (non objective-c).
* Instead you should use the predefined __FUNCTION__ macro.
**/
#define THIS_METHOD NSStringFromSelector(_cmd)
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* The main class, exposes all logging mechanisms, loggers, ...
* For most of the users, this class is hidden behind the logging functions like `DDLogInfo`
*/
@interface OSSDDLog : NSObject
/**
* Returns the singleton `DDLog`.
* The instance is used by `DDLog` class methods.
*/
@property (class, nonatomic, strong, readonly) OSSDDLog *sharedInstance;
/**
* Provides access to the underlying logging queue.
* This may be helpful to Logger classes for things like thread synchronization.
**/
@property (class, nonatomic, DISPATCH_QUEUE_REFERENCE_TYPE, readonly) dispatch_queue_t loggingQueue;
/**
* Logging Primitive.
*
* This method is used by the macros or logging functions.
* It is suggested you stick with the macros as they're easier to use.
*
* @param asynchronous YES if the logging is done async, NO if you want to force sync
* @param level the log level
* @param flag the log flag
* @param context the context (if any is defined)
* @param file the current file
* @param function the current function
* @param line the current code line
* @param tag potential tag
* @param format the log format
*/
+ (void)log:(BOOL)asynchronous
level:(OSSDDLogLevel)level
flag:(OSSDDLogFlag)flag
context:(NSInteger)context
file:(const char *)file
function:(const char *)function
line:(NSUInteger)line
tag:(id __nullable)tag
format:(NSString *)format, ... NS_FORMAT_FUNCTION(9,10);
/**
* Logging Primitive.
*
* This method is used by the macros or logging functions.
* It is suggested you stick with the macros as they're easier to use.
*
* @param asynchronous YES if the logging is done async, NO if you want to force sync
* @param level the log level
* @param flag the log flag
* @param context the context (if any is defined)
* @param file the current file
* @param function the current function
* @param line the current code line
* @param tag potential tag
* @param format the log format
*/
- (void)log:(BOOL)asynchronous
level:(OSSDDLogLevel)level
flag:(OSSDDLogFlag)flag
context:(NSInteger)context
file:(const char *)file
function:(const char *)function
line:(NSUInteger)line
tag:(id __nullable)tag
format:(NSString *)format, ... NS_FORMAT_FUNCTION(9,10);
/**
* Logging Primitive.
*
* This method can be used if you have a prepared va_list.
* Similar to `log:level:flag:context:file:function:line:tag:format:...`
*
* @param asynchronous YES if the logging is done async, NO if you want to force sync
* @param level the log level
* @param flag the log flag
* @param context the context (if any is defined)
* @param file the current file
* @param function the current function
* @param line the current code line
* @param tag potential tag
* @param format the log format
* @param argList the arguments list as a va_list
*/
+ (void)log:(BOOL)asynchronous
level:(OSSDDLogLevel)level
flag:(OSSDDLogFlag)flag
context:(NSInteger)context
file:(const char *)file
function:(const char *)function
line:(NSUInteger)line
tag:(id __nullable)tag
format:(NSString *)format
args:(va_list)argList NS_SWIFT_NAME(log(asynchronous:level:flag:context:file:function:line:tag:format:arguments:));
/**
* Logging Primitive.
*
* This method can be used if you have a prepared va_list.
* Similar to `log:level:flag:context:file:function:line:tag:format:...`
*
* @param asynchronous YES if the logging is done async, NO if you want to force sync
* @param level the log level
* @param flag the log flag
* @param context the context (if any is defined)
* @param file the current file
* @param function the current function
* @param line the current code line
* @param tag potential tag
* @param format the log format
* @param argList the arguments list as a va_list
*/
- (void)log:(BOOL)asynchronous
level:(OSSDDLogLevel)level
flag:(OSSDDLogFlag)flag
context:(NSInteger)context
file:(const char *)file
function:(const char *)function
line:(NSUInteger)line
tag:(id __nullable)tag
format:(NSString *)format
args:(va_list)argList NS_SWIFT_NAME(log(asynchronous:level:flag:context:file:function:line:tag:format:arguments:));
/**
* Logging Primitive.
*
* This method can be used if you manualy prepared DDLogMessage.
*
* @param asynchronous YES if the logging is done async, NO if you want to force sync
* @param logMessage the log message stored in a `DDLogMessage` model object
*/
+ (void)log:(BOOL)asynchronous
message:(OSSDDLogMessage *)logMessage NS_SWIFT_NAME(log(asynchronous:message:));
/**
* Logging Primitive.
*
* This method can be used if you manualy prepared DDLogMessage.
*
* @param asynchronous YES if the logging is done async, NO if you want to force sync
* @param logMessage the log message stored in a `DDLogMessage` model object
*/
- (void)log:(BOOL)asynchronous
message:(OSSDDLogMessage *)logMessage NS_SWIFT_NAME(log(asynchronous:message:));
/**
* Since logging can be asynchronous, there may be times when you want to flush the logs.
* The framework invokes this automatically when the application quits.
**/
+ (void)flushLog;
/**
* Since logging can be asynchronous, there may be times when you want to flush the logs.
* The framework invokes this automatically when the application quits.
**/
- (void)flushLog;
/**
* Loggers
*
* In order for your log statements to go somewhere, you should create and add a logger.
*
* You can add multiple loggers in order to direct your log statements to multiple places.
* And each logger can be configured separately.
* So you could have, for example, verbose logging to the console, but a concise log file with only warnings & errors.
**/
/**
* Adds the logger to the system.
*
* This is equivalent to invoking `[DDLog addLogger:logger withLogLevel:DDLogLevelAll]`.
**/
+ (void)addLogger:(id <OSSDDLogger>)logger;
/**
* Adds the logger to the system.
*
* This is equivalent to invoking `[DDLog addLogger:logger withLogLevel:DDLogLevelAll]`.
**/
- (void)addLogger:(id <OSSDDLogger>)logger;
/**
* Adds the logger to the system.
*
* The level that you provide here is a preemptive filter (for performance).
* That is, the level specified here will be used to filter out logMessages so that
* the logger is never even invoked for the messages.
*
* More information:
* When you issue a log statement, the logging framework iterates over each logger,
* and checks to see if it should forward the logMessage to the logger.
* This check is done using the level parameter passed to this method.
*
* For example:
*
* `[DDLog addLogger:consoleLogger withLogLevel:DDLogLevelVerbose];`
* `[DDLog addLogger:fileLogger withLogLevel:DDLogLevelWarning];`
*
* `DDLogError(@"oh no");` => gets forwarded to consoleLogger & fileLogger
* `DDLogInfo(@"hi");` => gets forwarded to consoleLogger only
*
* It is important to remember that Lumberjack uses a BITMASK.
* Many developers & third party frameworks may define extra log levels & flags.
* For example:
*
* `#define SOME_FRAMEWORK_LOG_FLAG_TRACE (1 << 6) // 0...1000000`
*
* So if you specify `DDLogLevelVerbose` to this method, you won't see the framework's trace messages.
*
* `(SOME_FRAMEWORK_LOG_FLAG_TRACE & DDLogLevelVerbose) => (01000000 & 00011111) => NO`
*
* Consider passing `DDLogLevelAll` to this method, which has all bits set.
* You can also use the exclusive-or bitwise operator to get a bitmask that has all flags set,
* except the ones you explicitly don't want. For example, if you wanted everything except verbose & debug:
*
* `((DDLogLevelAll ^ DDLogLevelVerbose) | DDLogLevelInfo)`
**/
+ (void)addLogger:(id <OSSDDLogger>)logger withLevel:(OSSDDLogLevel)level;
/**
* Adds the logger to the system.
*
* The level that you provide here is a preemptive filter (for performance).
* That is, the level specified here will be used to filter out logMessages so that
* the logger is never even invoked for the messages.
*
* More information:
* When you issue a log statement, the logging framework iterates over each logger,
* and checks to see if it should forward the logMessage to the logger.
* This check is done using the level parameter passed to this method.
*
* For example:
*
* `[DDLog addLogger:consoleLogger withLogLevel:DDLogLevelVerbose];`
* `[DDLog addLogger:fileLogger withLogLevel:DDLogLevelWarning];`
*
* `DDLogError(@"oh no");` => gets forwarded to consoleLogger & fileLogger
* `DDLogInfo(@"hi");` => gets forwarded to consoleLogger only
*
* It is important to remember that Lumberjack uses a BITMASK.
* Many developers & third party frameworks may define extra log levels & flags.
* For example:
*
* `#define SOME_FRAMEWORK_LOG_FLAG_TRACE (1 << 6) // 0...1000000`
*
* So if you specify `DDLogLevelVerbose` to this method, you won't see the framework's trace messages.
*
* `(SOME_FRAMEWORK_LOG_FLAG_TRACE & DDLogLevelVerbose) => (01000000 & 00011111) => NO`
*
* Consider passing `DDLogLevelAll` to this method, which has all bits set.
* You can also use the exclusive-or bitwise operator to get a bitmask that has all flags set,
* except the ones you explicitly don't want. For example, if you wanted everything except verbose & debug:
*
* `((DDLogLevelAll ^ DDLogLevelVerbose) | DDLogLevelInfo)`
**/
- (void)addLogger:(id <OSSDDLogger>)logger withLevel:(OSSDDLogLevel)level;
/**
* Remove the logger from the system
*/
+ (void)removeLogger:(id <OSSDDLogger>)logger;
/**
* Remove the logger from the system
*/
- (void)removeLogger:(id <OSSDDLogger>)logger;
/**
* Remove all the current loggers
*/
+ (void)removeAllLoggers;
/**
* Remove all the current loggers
*/
- (void)removeAllLoggers;
/**
* Return all the current loggers
*/
@property (class, nonatomic, copy, readonly) NSArray<id<OSSDDLogger>> *allLoggers;
/**
* Return all the current loggers
*/
@property (nonatomic, copy, readonly) NSArray<id<OSSDDLogger>> *allLoggers;
/**
* Return all the current loggers with their level (aka DDLoggerInformation).
*/
@property (class, nonatomic, copy, readonly) NSArray<OSSDDLoggerInformation *> *allLoggersWithLevel;
/**
* Return all the current loggers with their level (aka DDLoggerInformation).
*/
@property (nonatomic, copy, readonly) NSArray<OSSDDLoggerInformation *> *allLoggersWithLevel;
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* This protocol describes a basic logger behavior.
* Basically, it can log messages, store a logFormatter plus a bunch of optional behaviors.
* (i.e. flush, get its loggerQueue, get its name, ...
*/
@protocol OSSDDLogger <NSObject>
/**
* The log message method
*
* @param logMessage the message (model)
*/
- (void)logMessage:(OSSDDLogMessage *)logMessage NS_SWIFT_NAME(log(message:));
/**
* Formatters may optionally be added to any logger.
*
* If no formatter is set, the logger simply logs the message as it is given in logMessage,
* or it may use its own built in formatting style.
**/
@property (nonatomic, strong) id <OSSDDLogFormatter> logFormatter;
@optional
/**
* Since logging is asynchronous, adding and removing loggers is also asynchronous.
* In other words, the loggers are added and removed at appropriate times with regards to log messages.
*
* - Loggers will not receive log messages that were executed prior to when they were added.
* - Loggers will not receive log messages that were executed after they were removed.
*
* These methods are executed in the logging thread/queue.
* This is the same thread/queue that will execute every logMessage: invocation.
* Loggers may use these methods for thread synchronization or other setup/teardown tasks.
**/
- (void)didAddLogger;
/**
* Since logging is asynchronous, adding and removing loggers is also asynchronous.
* In other words, the loggers are added and removed at appropriate times with regards to log messages.
*
* - Loggers will not receive log messages that were executed prior to when they were added.
* - Loggers will not receive log messages that were executed after they were removed.
*
* These methods are executed in the logging thread/queue given in parameter.
* This is the same thread/queue that will execute every logMessage: invocation.
* Loggers may use the queue parameter to set specific values on the queue with dispatch_set_specific() function.
**/
- (void)didAddLoggerInQueue:(dispatch_queue_t)queue;
/**
* See the above description for `didAddLoger`
*/
- (void)willRemoveLogger;
/**
* Some loggers may buffer IO for optimization purposes.
* For example, a database logger may only save occasionaly as the disk IO is slow.
* In such loggers, this method should be implemented to flush any pending IO.
*
* This allows invocations of DDLog's flushLog method to be propogated to loggers that need it.
*
* Note that DDLog's flushLog method is invoked automatically when the application quits,
* and it may be also invoked manually by the developer prior to application crashes, or other such reasons.
**/
- (void)flush;
/**
* Each logger is executed concurrently with respect to the other loggers.
* Thus, a dedicated dispatch queue is used for each logger.
* Logger implementations may optionally choose to provide their own dispatch queue.
**/
@property (nonatomic, DISPATCH_QUEUE_REFERENCE_TYPE, readonly) dispatch_queue_t loggerQueue;
/**
* If the logger implementation does not choose to provide its own queue,
* one will automatically be created for it.
* The created queue will receive its name from this method.
* This may be helpful for debugging or profiling reasons.
**/
@property (nonatomic, readonly) NSString *loggerName;
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* This protocol describes the behavior of a log formatter
*/
@protocol OSSDDLogFormatter <NSObject>
@required
/**
* Formatters may optionally be added to any logger.
* This allows for increased flexibility in the logging environment.
* For example, log messages for log files may be formatted differently than log messages for the console.
*
* For more information about formatters, see the "Custom Formatters" page:
* Documentation/CustomFormatters.md
*
* The formatter may also optionally filter the log message by returning nil,
* in which case the logger will not log the message.
**/
- (NSString * __nullable)formatLogMessage:(OSSDDLogMessage *)logMessage NS_SWIFT_NAME(format(message:));
@optional
/**
* A single formatter instance can be added to multiple loggers.
* These methods provides hooks to notify the formatter of when it's added/removed.
*
* This is primarily for thread-safety.
* If a formatter is explicitly not thread-safe, it may wish to throw an exception if added to multiple loggers.
* Or if a formatter has potentially thread-unsafe code (e.g. NSDateFormatter),
* it could possibly use these hooks to switch to thread-safe versions of the code.
**/
- (void)didAddToLogger:(id <OSSDDLogger>)logger;
/**
* A single formatter instance can be added to multiple loggers.
* These methods provides hooks to notify the formatter of when it's added/removed.
*
* This is primarily for thread-safety.
* If a formatter is explicitly not thread-safe, it may wish to throw an exception if added to multiple loggers.
* Or if a formatter has potentially thread-unsafe code (e.g. NSDateFormatter),
* it could possibly use these hooks to switch to thread-safe versions of the code or use dispatch_set_specific()
.* to add its own specific values.
**/
- (void)didAddToLogger:(id <OSSDDLogger>)logger inQueue:(dispatch_queue_t)queue;
/**
* See the above description for `didAddToLogger:`
*/
- (void)willRemoveFromLogger:(id <OSSDDLogger>)logger;
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* This protocol describes a dynamic logging component
*/
@protocol OSSDDRegisteredDynamicLogging
/**
* Implement these methods to allow a file's log level to be managed from a central location.
*
* This is useful if you'd like to be able to change log levels for various parts
* of your code from within the running application.
*
* Imagine pulling up the settings for your application,
* and being able to configure the logging level on a per file basis.
*
* The implementation can be very straight-forward:
*
* ```
* + (int)ddLogLevel
* {
* return ddLogLevel;
* }
*
* + (void)ddSetLogLevel:(DDLogLevel)level
* {
* ddLogLevel = level;
* }
* ```
**/
@property (class, nonatomic, readwrite, setter=ddSetLogLevel:) OSSDDLogLevel ossLogLevel;
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef NS_DESIGNATED_INITIALIZER
#define NS_DESIGNATED_INITIALIZER
#endif
/**
* Log message options, allow copying certain log elements
*/
typedef NS_OPTIONS(NSInteger, OSSDDLogMessageOptions){
/**
* Use this to use a copy of the file path
*/
OSSDDLogMessageCopyFile = 1 << 0,
/**
* Use this to use a copy of the function name
*/
OSSDDLogMessageCopyFunction = 1 << 1,
/**
* Use this to use avoid a copy of the message
*/
OSSDDLogMessageDontCopyMessage = 1 << 2
};
/**
* The `DDLogMessage` class encapsulates information about the log message.
* If you write custom loggers or formatters, you will be dealing with objects of this class.
**/
@interface OSSDDLogMessage : NSObject <NSCopying>
{
// Direct accessors to be used only for performance
@public
NSString *_message;
OSSDDLogLevel _level;
OSSDDLogFlag _flag;
NSInteger _context;
NSString *_file;
NSString *_fileName;
NSString *_function;
NSUInteger _line;
id _tag;
OSSDDLogMessageOptions _options;
NSDate *_timestamp;
NSString *_threadID;
NSString *_threadName;
NSString *_queueLabel;
}
/**
* Default `init` for empty messages.
*/
- (instancetype)init NS_DESIGNATED_INITIALIZER;
/**
* Standard init method for a log message object.
* Used by the logging primitives. (And the macros use the logging primitives.)
*
* If you find need to manually create logMessage objects, there is one thing you should be aware of:
*
* If no flags are passed, the method expects the file and function parameters to be string literals.
* That is, it expects the given strings to exist for the duration of the object's lifetime,
* and it expects the given strings to be immutable.
* In other words, it does not copy these strings, it simply points to them.
* This is due to the fact that __FILE__ and __FUNCTION__ are usually used to specify these parameters,
* so it makes sense to optimize and skip the unnecessary allocations.
* However, if you need them to be copied you may use the options parameter to specify this.
*
* @param message the message
* @param level the log level
* @param flag the log flag
* @param context the context (if any is defined)
* @param file the current file
* @param function the current function
* @param line the current code line
* @param tag potential tag
* @param options a bitmask which supports DDLogMessageCopyFile and DDLogMessageCopyFunction.
* @param timestamp the log timestamp
*
* @return a new instance of a log message model object
*/
- (instancetype)initWithMessage:(NSString *)message
level:(OSSDDLogLevel)level
flag:(OSSDDLogFlag)flag
context:(NSInteger)context
file:(NSString *)file
function:(NSString * __nullable)function
line:(NSUInteger)line
tag:(id __nullable)tag
options:(OSSDDLogMessageOptions)options
timestamp:(NSDate * __nullable)timestamp NS_DESIGNATED_INITIALIZER;
/**
* Read-only properties
**/
/**
* The log message
*/
@property (readonly, nonatomic) NSString *message;
@property (readonly, nonatomic) OSSDDLogLevel level;
@property (readonly, nonatomic) OSSDDLogFlag flag;
@property (readonly, nonatomic) NSInteger context;
@property (readonly, nonatomic) NSString *file;
@property (readonly, nonatomic) NSString *fileName;
@property (readonly, nonatomic) NSString * __nullable function;
@property (readonly, nonatomic) NSUInteger line;
@property (readonly, nonatomic) id __nullable tag;
@property (readonly, nonatomic) OSSDDLogMessageOptions options;
@property (readonly, nonatomic) NSDate *timestamp;
@property (readonly, nonatomic) NSString *threadID; // ID as it appears in NSLog calculated from the machThreadID
@property (readonly, nonatomic) NSString *threadName;
@property (readonly, nonatomic) NSString *queueLabel;
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* The `DDLogger` protocol specifies that an optional formatter can be added to a logger.
* Most (but not all) loggers will want to support formatters.
*
* However, writting getters and setters in a thread safe manner,
* while still maintaining maximum speed for the logging process, is a difficult task.
*
* To do it right, the implementation of the getter/setter has strict requiremenets:
* - Must NOT require the `logMessage:` method to acquire a lock.
* - Must NOT require the `logMessage:` method to access an atomic property (also a lock of sorts).
*
* To simplify things, an abstract logger is provided that implements the getter and setter.
*
* Logger implementations may simply extend this class,
* and they can ACCESS THE FORMATTER VARIABLE DIRECTLY from within their `logMessage:` method!
**/
@interface OSSDDAbstractLogger : NSObject <OSSDDLogger>
{
// Direct accessors to be used only for performance
@public
id <OSSDDLogFormatter> _logFormatter;
dispatch_queue_t _loggerQueue;
}
@property (nonatomic, strong, nullable) id <OSSDDLogFormatter> logFormatter;
@property (nonatomic, DISPATCH_QUEUE_REFERENCE_TYPE) dispatch_queue_t loggerQueue;
// For thread-safety assertions
/**
* Return YES if the current logger uses a global queue for logging
*/
@property (nonatomic, readonly, getter=isOnGlobalLoggingQueue) BOOL onGlobalLoggingQueue;
/**
* Return YES if the current logger uses the internal designated queue for logging
*/
@property (nonatomic, readonly, getter=isOnInternalLoggerQueue) BOOL onInternalLoggerQueue;
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@interface OSSDDLoggerInformation : NSObject
@property (nonatomic, readonly) id <OSSDDLogger> logger;
@property (nonatomic, readonly) OSSDDLogLevel level;
+ (OSSDDLoggerInformation *)informationWithLogger:(id <OSSDDLogger>)logger
andLevel:(OSSDDLogLevel)level;
@end
NS_ASSUME_NONNULL_END

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,509 @@
// Software License Agreement (BSD License)
//
// Copyright (c) 2010-2016, Deusty, LLC
// All rights reserved.
//
// Redistribution and use of this software in source and binary forms,
// with or without modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Neither the name of Deusty nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific
// prior written permission of Deusty, LLC.
// Disable legacy macros
#ifndef DD_LEGACY_MACROS
#define DD_LEGACY_MACROS 0
#endif
#import "OSSDDLog.h"
@class OSSDDLogFileInfo;
/**
* This class provides a logger to write log statements to a file.
**/
// Default configuration and safety/sanity values.
//
// maximumFileSize -> kDDDefaultLogMaxFileSize
// rollingFrequency -> kDDDefaultLogRollingFrequency
// maximumNumberOfLogFiles -> kDDDefaultLogMaxNumLogFiles
// logFilesDiskQuota -> kDDDefaultLogFilesDiskQuota
//
// You should carefully consider the proper configuration values for your application.
extern unsigned long long const osskDDDefaultLogMaxFileSize;
extern NSTimeInterval const osskDDDefaultLogRollingFrequency;
extern NSUInteger const osskDDDefaultLogMaxNumLogFiles;
extern unsigned long long const osskDDDefaultLogFilesDiskQuota;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* The LogFileManager protocol is designed to allow you to control all aspects of your log files.
*
* The primary purpose of this is to allow you to do something with the log files after they have been rolled.
* Perhaps you want to compress them to save disk space.
* Perhaps you want to upload them to an FTP server.
* Perhaps you want to run some analytics on the file.
*
* A default LogFileManager is, of course, provided.
* The default LogFileManager simply deletes old log files according to the maximumNumberOfLogFiles property.
*
* This protocol provides various methods to fetch the list of log files.
*
* There are two variants: sorted and unsorted.
* If sorting is not necessary, the unsorted variant is obviously faster.
* The sorted variant will return an array sorted by when the log files were created,
* with the most recently created log file at index 0, and the oldest log file at the end of the array.
*
* You can fetch only the log file paths (full path including name), log file names (name only),
* or an array of `DDLogFileInfo` objects.
* The `DDLogFileInfo` class is documented below, and provides a handy wrapper that
* gives you easy access to various file attributes such as the creation date or the file size.
*/
@protocol OSSDDLogFileManager <NSObject>
@required
// Public properties
/**
* The maximum number of archived log files to keep on disk.
* For example, if this property is set to 3,
* then the LogFileManager will only keep 3 archived log files (plus the current active log file) on disk.
* Once the active log file is rolled/archived, then the oldest of the existing 3 rolled/archived log files is deleted.
*
* You may optionally disable this option by setting it to zero.
**/
@property (readwrite, assign, atomic) NSUInteger maximumNumberOfLogFiles;
/**
* The maximum space that logs can take. On rolling logfile all old logfiles that exceed logFilesDiskQuota will
* be deleted.
*
* You may optionally disable this option by setting it to zero.
**/
@property (readwrite, assign, atomic) unsigned long long logFilesDiskQuota;
// Public methods
/**
* Returns the logs directory (path)
*/
@property (nonatomic, readonly, copy) NSString *logsDirectory;
/**
* Returns an array of `NSString` objects,
* each of which is the filePath to an existing log file on disk.
**/
@property (nonatomic, readonly, strong) NSArray<NSString *> *unsortedLogFilePaths;
/**
* Returns an array of `NSString` objects,
* each of which is the fileName of an existing log file on disk.
**/
@property (nonatomic, readonly, strong) NSArray<NSString *> *unsortedLogFileNames;
/**
* Returns an array of `DDLogFileInfo` objects,
* each representing an existing log file on disk,
* and containing important information about the log file such as it's modification date and size.
**/
@property (nonatomic, readonly, strong) NSArray<OSSDDLogFileInfo *> *unsortedLogFileInfos;
/**
* Just like the `unsortedLogFilePaths` method, but sorts the array.
* The items in the array are sorted by creation date.
* The first item in the array will be the most recently created log file.
**/
@property (nonatomic, readonly, strong) NSArray<NSString *> *sortedLogFilePaths;
/**
* Just like the `unsortedLogFileNames` method, but sorts the array.
* The items in the array are sorted by creation date.
* The first item in the array will be the most recently created log file.
**/
@property (nonatomic, readonly, strong) NSArray<NSString *> *sortedLogFileNames;
/**
* Just like the `unsortedLogFileInfos` method, but sorts the array.
* The items in the array are sorted by creation date.
* The first item in the array will be the most recently created log file.
**/
@property (nonatomic, readonly, strong) NSArray<OSSDDLogFileInfo *> *sortedLogFileInfos;
// Private methods (only to be used by DDFileLogger)
/**
* Generates a new unique log file path, and creates the corresponding log file.
**/
- (NSString *)createNewLogFile;
@optional
// Notifications from DDFileLogger
/**
* Called when a log file was archieved
*/
- (void)didArchiveLogFile:(NSString *)logFilePath NS_SWIFT_NAME(didArchiveLogFile(atPath:));
/**
* Called when the roll action was executed and the log was archieved
*/
- (void)didRollAndArchiveLogFile:(NSString *)logFilePath NS_SWIFT_NAME(didRollAndArchiveLogFile(atPath:));
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Default log file manager.
*
* All log files are placed inside the logsDirectory.
* If a specific logsDirectory isn't specified, the default directory is used.
* On Mac, this is in `~/Library/Logs/<Application Name>`.
* On iPhone, this is in `~/Library/Caches/Logs`.
*
* Log files are named `"<bundle identifier> <date> <time>.log"`
* Example: `com.organization.myapp 2013-12-03 17-14.log`
*
* Archived log files are automatically deleted according to the `maximumNumberOfLogFiles` property.
**/
@interface OSSDDLogFileManagerDefault : NSObject <OSSDDLogFileManager>
/**
* Default initializer
*/
- (instancetype)init;
/**
* Designated initialized, requires the logs directory
*/
- (instancetype)initWithLogsDirectory:(NSString *)logsDirectory NS_DESIGNATED_INITIALIZER;
#if TARGET_OS_IPHONE
/*
* Calling this constructor you can override the default "automagically" chosen NSFileProtection level.
* Useful if you are writing a command line utility / CydiaSubstrate addon for iOS that has no NSBundle
* or like SpringBoard no BackgroundModes key in the NSBundle:
* iPhone:~ root# cycript -p SpringBoard
* cy# [NSBundle mainBundle]
* #"NSBundle </System/Library/CoreServices/SpringBoard.app> (loaded)"
* cy# [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIBackgroundModes"];
* null
* cy#
**/
- (instancetype)initWithLogsDirectory:(NSString *)logsDirectory defaultFileProtectionLevel:(NSFileProtectionType)fileProtectionLevel;
#endif
/*
* Methods to override.
*
* Log files are named `"<bundle identifier> <date> <time>.log"`
* Example: `com.organization.myapp 2013-12-03 17-14.log`
*
* If you wish to change default filename, you can override following two methods.
* - `newLogFileName` method would be called on new logfile creation.
* - `isLogFile:` method would be called to filter logfiles from all other files in logsDirectory.
* You have to parse given filename and return YES if it is logFile.
*
* **NOTE**
* `newLogFileName` returns filename. If appropriate file already exists, number would be added
* to filename before extension. You have to handle this case in isLogFile: method.
*
* Example:
* - newLogFileName returns `"com.organization.myapp 2013-12-03.log"`,
* file `"com.organization.myapp 2013-12-03.log"` would be created.
* - after some time `"com.organization.myapp 2013-12-03.log"` is archived
* - newLogFileName again returns `"com.organization.myapp 2013-12-03.log"`,
* file `"com.organization.myapp 2013-12-03 2.log"` would be created.
* - after some time `"com.organization.myapp 2013-12-03 1.log"` is archived
* - newLogFileName again returns `"com.organization.myapp 2013-12-03.log"`,
* file `"com.organization.myapp 2013-12-03 3.log"` would be created.
**/
/**
* Generates log file name with default format `"<bundle identifier> <date> <time>.log"`
* Example: `MobileSafari 2013-12-03 17-14.log`
*
* You can change it by overriding `newLogFileName` and `isLogFile:` methods.
**/
@property (readonly, copy) NSString *newLogFileName;
/**
* Default log file name is `"<bundle identifier> <date> <time>.log"`.
* Example: `MobileSafari 2013-12-03 17-14.log`
*
* You can change it by overriding `newLogFileName` and `isLogFile:` methods.
**/
- (BOOL)isLogFile:(NSString *)fileName NS_SWIFT_NAME(isLogFile(withName:));
/* Inherited from DDLogFileManager protocol:
@property (readwrite, assign, atomic) NSUInteger maximumNumberOfLogFiles;
@property (readwrite, assign, atomic) NSUInteger logFilesDiskQuota;
- (NSString *)logsDirectory;
- (NSArray *)unsortedLogFilePaths;
- (NSArray *)unsortedLogFileNames;
- (NSArray *)unsortedLogFileInfos;
- (NSArray *)sortedLogFilePaths;
- (NSArray *)sortedLogFileNames;
- (NSArray *)sortedLogFileInfos;
*/
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Most users will want file log messages to be prepended with the date and time.
* Rather than forcing the majority of users to write their own formatter,
* we will supply a logical default formatter.
* Users can easily replace this formatter with their own by invoking the `setLogFormatter:` method.
* It can also be removed by calling `setLogFormatter:`, and passing a nil parameter.
*
* In addition to the convenience of having a logical default formatter,
* it will also provide a template that makes it easy for developers to copy and change.
**/
@interface OSSDDLogFileFormatterDefault : NSObject <OSSDDLogFormatter>
/**
* Default initializer
*/
- (instancetype)init;
/**
* Designated initializer, requires a date formatter
*/
- (instancetype)initWithDateFormatter:(NSDateFormatter *)dateFormatter NS_DESIGNATED_INITIALIZER;
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* The standard implementation for a file logger
*/
@interface OSSDDFileLogger : OSSDDAbstractLogger <OSSDDLogger> {
OSSDDLogFileInfo *_currentLogFileInfo;
}
/**
* Default initializer
*/
- (instancetype)init;
/**
* Designated initializer, requires a `DDLogFileManager` instance
*/
- (instancetype)initWithLogFileManager:(id <OSSDDLogFileManager>)logFileManager NS_DESIGNATED_INITIALIZER;
/**
* Called when the logger is about to write message. Call super before your implementation.
*/
- (void)willLogMessage NS_REQUIRES_SUPER;
/**
* Called when the logger wrote message. Call super after your implementation.
*/
- (void)didLogMessage NS_REQUIRES_SUPER;
/**
* Called when the logger checks archive or not current log file.
* Override this method to exdend standart behavior. By default returns NO.
*/
- (BOOL)shouldArchiveRecentLogFileInfo:(OSSDDLogFileInfo *)recentLogFileInfo;
/**
* Log File Rolling:
*
* `maximumFileSize`:
* The approximate maximum size (in bytes) to allow log files to grow.
* If a log file is larger than this value after a log statement is appended,
* then the log file is rolled.
*
* `rollingFrequency`
* How often to roll the log file.
* The frequency is given as an `NSTimeInterval`, which is a double that specifies the interval in seconds.
* Once the log file gets to be this old, it is rolled.
*
* `doNotReuseLogFiles`
* When set, will always create a new log file at application launch.
*
* Both the `maximumFileSize` and the `rollingFrequency` are used to manage rolling.
* Whichever occurs first will cause the log file to be rolled.
*
* For example:
* The `rollingFrequency` is 24 hours,
* but the log file surpasses the `maximumFileSize` after only 20 hours.
* The log file will be rolled at that 20 hour mark.
* A new log file will be created, and the 24 hour timer will be restarted.
*
* You may optionally disable rolling due to filesize by setting `maximumFileSize` to zero.
* If you do so, rolling is based solely on `rollingFrequency`.
*
* You may optionally disable rolling due to time by setting `rollingFrequency` to zero (or any non-positive number).
* If you do so, rolling is based solely on `maximumFileSize`.
*
* If you disable both `maximumFileSize` and `rollingFrequency`, then the log file won't ever be rolled.
* This is strongly discouraged.
**/
@property (readwrite, assign) unsigned long long maximumFileSize;
/**
* See description for `maximumFileSize`
*/
@property (readwrite, assign) NSTimeInterval rollingFrequency;
/**
* See description for `maximumFileSize`
*/
@property (readwrite, assign, atomic) BOOL doNotReuseLogFiles;
/**
* The DDLogFileManager instance can be used to retrieve the list of log files,
* and configure the maximum number of archived log files to keep.
*
* @see DDLogFileManager.maximumNumberOfLogFiles
**/
@property (strong, nonatomic, readonly) id <OSSDDLogFileManager> logFileManager;
/**
* When using a custom formatter you can set the `logMessage` method not to append
* `\n` character after each output. This allows for some greater flexibility with
* custom formatters. Default value is YES.
**/
@property (nonatomic, readwrite, assign) BOOL automaticallyAppendNewlineForCustomFormatters;
/**
* You can optionally force the current log file to be rolled with this method.
* CompletionBlock will be called on main queue.
*/
- (void)rollLogFileWithCompletionBlock:(void (^)(void))completionBlock NS_SWIFT_NAME(rollLogFile(withCompletion:));
/**
* Method is deprecated.
* @deprecated Use `rollLogFileWithCompletionBlock:` method instead.
*/
- (void)rollLogFile __attribute((deprecated));
// Inherited from DDAbstractLogger
// - (id <DDLogFormatter>)logFormatter;
// - (void)setLogFormatter:(id <DDLogFormatter>)formatter;
/**
* Returns the log file that should be used.
* If there is an existing log file that is suitable,
* within the constraints of `maximumFileSize` and `rollingFrequency`, then it is returned.
*
* Otherwise a new file is created and returned.
**/
@property (nonatomic, readonly, strong) OSSDDLogFileInfo *currentLogFileInfo;
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* `DDLogFileInfo` is a simple class that provides access to various file attributes.
* It provides good performance as it only fetches the information if requested,
* and it caches the information to prevent duplicate fetches.
*
* It was designed to provide quick snapshots of the current state of log files,
* and to help sort log files in an array.
*
* This class does not monitor the files, or update it's cached attribute values if the file changes on disk.
* This is not what the class was designed for.
*
* If you absolutely must get updated values,
* you can invoke the reset method which will clear the cache.
**/
@interface OSSDDLogFileInfo : NSObject
@property (strong, nonatomic, readonly) NSString *filePath;
@property (strong, nonatomic, readonly) NSString *fileName;
#if FOUNDATION_SWIFT_SDK_EPOCH_AT_LEAST(8)
@property (strong, nonatomic, readonly) NSDictionary<NSFileAttributeKey, id> *fileAttributes;
#else
@property (strong, nonatomic, readonly) NSDictionary<NSString *, id> *fileAttributes;
#endif
@property (strong, nonatomic, readonly) NSDate *creationDate;
@property (strong, nonatomic, readonly) NSDate *modificationDate;
@property (nonatomic, readonly) unsigned long long fileSize;
@property (nonatomic, readonly) NSTimeInterval age;
@property (nonatomic, readwrite) BOOL isArchived;
+ (instancetype)logFileWithPath:(NSString *)filePath NS_SWIFT_UNAVAILABLE("Use init(filePath:)");
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithFilePath:(NSString *)filePath NS_DESIGNATED_INITIALIZER;
- (void)reset;
- (void)renameFile:(NSString *)newFileName NS_SWIFT_NAME(renameFile(to:));
#if TARGET_IPHONE_SIMULATOR
// So here's the situation.
// Extended attributes are perfect for what we're trying to do here (marking files as archived).
// This is exactly what extended attributes were designed for.
//
// But Apple screws us over on the simulator.
// Everytime you build-and-go, they copy the application into a new folder on the hard drive,
// and as part of the process they strip extended attributes from our log files.
// Normally, a copy of a file preserves extended attributes.
// So obviously Apple has gone to great lengths to piss us off.
//
// Thus we use a slightly different tactic for marking log files as archived in the simulator.
// That way it "just works" and there's no confusion when testing.
//
// The difference in method names is indicative of the difference in functionality.
// On the simulator we add an attribute by appending a filename extension.
//
// For example:
// "mylog.txt" -> "mylog.archived.txt"
// "mylog" -> "mylog.archived"
- (BOOL)hasExtensionAttributeWithName:(NSString *)attrName;
- (void)addExtensionAttributeWithName:(NSString *)attrName;
- (void)removeExtensionAttributeWithName:(NSString *)attrName;
#else /* if TARGET_IPHONE_SIMULATOR */
// Normal use of extended attributes used everywhere else,
// such as on Macs and on iPhone devices.
- (BOOL)hasExtendedAttributeWithName:(NSString *)attrName;
- (void)addExtendedAttributeWithName:(NSString *)attrName;
- (void)removeExtendedAttributeWithName:(NSString *)attrName;
#endif /* if TARGET_IPHONE_SIMULATOR */
@end

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,82 @@
// Software License Agreement (BSD License)
//
// Copyright (c) 2010-2016, Deusty, LLC
// All rights reserved.
//
// Redistribution and use of this software in source and binary forms,
// with or without modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Neither the name of Deusty nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific
// prior written permission of Deusty, LLC.
// Disable legacy macros
#ifndef OSSDD_LEGACY_MACROS
#define OSSDD_LEGACY_MACROS 0
#endif
#import "OSSDDLog.h"
/**
* The constant/variable/method responsible for controlling the current log level.
**/
#ifndef OSSLOG_LEVEL_DEF
#define OSSLOG_LEVEL_DEF ossLogLevel
#endif
/**
* Whether async should be used by log messages, excluding error messages that are always sent sync.
**/
#ifndef OSSLOG_ASYNC_ENABLED
#define OSSLOG_ASYNC_ENABLED YES
#endif
/**
* These are the two macros that all other macros below compile into.
* These big multiline macros makes all the other macros easier to read.
**/
#define OSSLOG_MACRO(isAsynchronous, lvl, flg, ctx, atag, fnct, frmt, ...) \
[OSSDDLog log : isAsynchronous \
level : lvl \
flag : flg \
context : ctx \
file : __FILE__ \
function : fnct \
line : __LINE__ \
tag : atag \
format : (frmt), ## __VA_ARGS__]
/**
* Define version of the macro that only execute if the log level is above the threshold.
* The compiled versions essentially look like this:
*
* if (logFlagForThisLogMsg & ddLogLevel) { execute log message }
*
* When LOG_LEVEL_DEF is defined as ddLogLevel.
*
* As shown further below, Lumberjack actually uses a bitmask as opposed to primitive log levels.
* This allows for a great amount of flexibility and some pretty advanced fine grained logging techniques.
*
* Note that when compiler optimizations are enabled (as they are for your release builds),
* the log messages above your logging threshold will automatically be compiled out.
*
* (If the compiler sees LOG_LEVEL_DEF/ddLogLevel declared as a constant, the compiler simply checks to see
* if the 'if' statement would execute, and if not it strips it from the binary.)
*
* We also define shorthand versions for asynchronous and synchronous logging.
**/
#define OSSLOG_MAYBE(async, lvl, flg, ctx, tag, fnct, frmt, ...) \
do { if(lvl & flg) OSSLOG_MACRO(async, lvl, flg, ctx, tag, fnct, frmt, ##__VA_ARGS__); } while(0)
/**
* Ready to use log macros with no context or tag.
**/
#define OSSDDLogError(frmt, ...) OSSLOG_MAYBE(NO, OSSLOG_LEVEL_DEF, OSSDDLogFlagError, 0, nil, __PRETTY_FUNCTION__, frmt, ##__VA_ARGS__)
#define OSSDDLogWarn(frmt, ...) OSSLOG_MAYBE(OSSLOG_ASYNC_ENABLED, OSSLOG_LEVEL_DEF, OSSDDLogFlagWarning, 0, nil, __PRETTY_FUNCTION__, frmt, ##__VA_ARGS__)
#define OSSDDLogInfo(frmt, ...) OSSLOG_MAYBE(OSSLOG_ASYNC_ENABLED, OSSLOG_LEVEL_DEF, OSSDDLogFlagInfo, 0, nil, __PRETTY_FUNCTION__, frmt, ##__VA_ARGS__)
#define OSSDDLogDebug(frmt, ...) OSSLOG_MAYBE(OSSLOG_ASYNC_ENABLED, OSSLOG_LEVEL_DEF, OSSDDLogFlagDebug, 0, nil, __PRETTY_FUNCTION__, frmt, ##__VA_ARGS__)
#define OSSDDLogVerbose(frmt, ...) OSSLOG_MAYBE(OSSLOG_ASYNC_ENABLED, OSSLOG_LEVEL_DEF, OSSDDLogFlagVerbose, 0, nil, __PRETTY_FUNCTION__, frmt, ##__VA_ARGS__)

View File

@@ -0,0 +1,14 @@
//
// OSSNSLogger.h
// AliyunOSSiOS
//
// Created by jingdan on 2017/10/24.
// Copyright © 2017年 zhouzhuo. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "OSSDDLog.h"
@interface OSSNSLogger : OSSDDAbstractLogger <OSSDDLogger>
@property (class, readonly, strong) OSSNSLogger *sharedInstance;
@end

View File

@@ -0,0 +1,32 @@
//
// OSSNSLogger.m
// AliyunOSSiOS
//
// Created by jingdan on 2017/10/24.
// Copyright © 2017 zhouzhuo. All rights reserved.
//
#import "OSSNSLogger.h"
static OSSNSLogger *sharedInstance;
@implementation OSSNSLogger
+ (instancetype)sharedInstance {
static dispatch_once_t OSSNSLoggerOnceToken;
dispatch_once(&OSSNSLoggerOnceToken, ^{
sharedInstance = [[[self class] alloc] init];
});
return sharedInstance;
}
- (void)logMessage:(OSSDDLogMessage *)logMessage {
NSString * message = _logFormatter ? [_logFormatter formatLogMessage:logMessage] : logMessage->_message;
if (message) {
NSLog(@"%@",message);
}
}
@end

View File

@@ -0,0 +1,64 @@
/*
Copyright (C) 2016 Apple Inc. All Rights Reserved.
See LICENSE.txt for this samples licensing information
Abstract:
Basic demonstration of how to use the SystemConfiguration Reachablity APIs.
*/
#import <Foundation/Foundation.h>
#import <SystemConfiguration/SystemConfiguration.h>
#import <netinet/in.h>
typedef enum : NSInteger {
OSSNotReachable = 0,
OSSReachableViaWiFi,
OSSReachableViaWWAN
} OSSNetworkStatus;
#pragma mark IPv6 Support
//Reachability fully support IPv6. For full details, see ReadMe.md.
extern NSString *ossReachabilityChangedNotification;
@interface OSSReachability : NSObject
/*!
* Use to check the reachability of a given host name.
*/
+ (instancetype)reachabilityWithHostName:(NSString *)hostName;
/*!
* Use to check the reachability of a given IP address.
*/
+ (instancetype)reachabilityWithAddress:(const struct sockaddr *)hostAddress;
/*!
* Checks whether the default route is available. Should be used by applications that do not connect to a particular host.
*/
+ (instancetype)reachabilityForInternetConnection;
#pragma mark reachabilityForLocalWiFi
//reachabilityForLocalWiFi has been removed from the sample. See ReadMe.md for more information.
//+ (instancetype)reachabilityForLocalWiFi;
/*!
* Start listening for reachability notifications on the current run loop.
*/
- (BOOL)startNotifier;
- (void)stopNotifier;
- (OSSNetworkStatus)currentReachabilityStatus;
/*!
* WWAN may be available, but not active until a connection has been established. WiFi may require a connection for VPN on Demand.
*/
- (BOOL)connectionRequired;
@end

View File

@@ -0,0 +1,248 @@
/*
Copyright (C) 2016 Apple Inc. All Rights Reserved.
See LICENSE.txt for this samples licensing information
Abstract:
Basic demonstration of how to use the SystemConfiguration Reachablity APIs.
*/
#import <arpa/inet.h>
#import <ifaddrs.h>
#import <netdb.h>
#import <sys/socket.h>
#import <netinet/in.h>
#import <CoreFoundation/CoreFoundation.h>
#import "OSSReachability.h"
#pragma mark IPv6 Support
//Reachability fully support IPv6. For full details, see ReadMe.md.
NSString *ossReachabilityChangedNotification = @"ossNetworkReachabilityChangedNotification";
#ifndef kShouldPrintReachabilityFlags
#if TARGET_OS_IOS
#define kShouldPrintReachabilityFlags 1
#else
#define kShouldPrintReachabilityFlags 0
#endif
#endif
#pragma mark - Supporting functions
static void PrintReachabilityFlags(SCNetworkReachabilityFlags flags, const char* comment)
{
#if kShouldPrintReachabilityFlags
NSLog(@"Reachability Flag Status: %c%c %c%c%c%c%c%c%c %s\n",
(flags & kSCNetworkReachabilityFlagsIsWWAN) ? 'W' : '-',
(flags & kSCNetworkReachabilityFlagsReachable) ? 'R' : '-',
(flags & kSCNetworkReachabilityFlagsTransientConnection) ? 't' : '-',
(flags & kSCNetworkReachabilityFlagsConnectionRequired) ? 'c' : '-',
(flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) ? 'C' : '-',
(flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-',
(flags & kSCNetworkReachabilityFlagsConnectionOnDemand) ? 'D' : '-',
(flags & kSCNetworkReachabilityFlagsIsLocalAddress) ? 'l' : '-',
(flags & kSCNetworkReachabilityFlagsIsDirect) ? 'd' : '-',
comment
);
#endif
}
static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info)
{
#pragma unused (target, flags)
NSCAssert(info != NULL, @"info was NULL in ReachabilityCallback");
NSCAssert([(__bridge NSObject*) info isKindOfClass: [OSSReachability class]], @"info was wrong class in ReachabilityCallback");
OSSReachability* noteObject = (__bridge OSSReachability *)info;
// Post a notification to notify the client that the network reachability changed.
[[NSNotificationCenter defaultCenter] postNotificationName: ossReachabilityChangedNotification object: noteObject];
}
#pragma mark - Reachability implementation
@implementation OSSReachability
{
SCNetworkReachabilityRef _reachabilityRef;
}
+ (instancetype)reachabilityWithHostName:(NSString *)hostName
{
OSSReachability* returnValue = NULL;
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]);
if (reachability != NULL)
{
returnValue= [[self alloc] init];
if (returnValue != NULL)
{
returnValue->_reachabilityRef = reachability;
}
else {
CFRelease(reachability);
}
}
return returnValue;
}
+ (instancetype)reachabilityWithAddress:(const struct sockaddr *)hostAddress
{
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, hostAddress);
OSSReachability* returnValue = NULL;
if (reachability != NULL)
{
returnValue = [[self alloc] init];
if (returnValue != NULL)
{
returnValue->_reachabilityRef = reachability;
}
else {
CFRelease(reachability);
}
}
return returnValue;
}
+ (instancetype)reachabilityForInternetConnection
{
struct sockaddr_in zeroAddress;
bzero(&zeroAddress, sizeof(zeroAddress));
zeroAddress.sin_len = sizeof(zeroAddress);
zeroAddress.sin_family = AF_INET;
return [self reachabilityWithAddress: (const struct sockaddr *) &zeroAddress];
}
#pragma mark reachabilityForLocalWiFi
//reachabilityForLocalWiFi has been removed from the sample. See ReadMe.md for more information.
//+ (instancetype)reachabilityForLocalWiFi
#pragma mark - Start and stop notifier
- (BOOL)startNotifier
{
BOOL returnValue = NO;
SCNetworkReachabilityContext context = {0, (__bridge void *)(self), NULL, NULL, NULL};
if (SCNetworkReachabilitySetCallback(_reachabilityRef, ReachabilityCallback, &context))
{
if (SCNetworkReachabilityScheduleWithRunLoop(_reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode))
{
returnValue = YES;
}
}
return returnValue;
}
- (void)stopNotifier
{
if (_reachabilityRef != NULL)
{
SCNetworkReachabilityUnscheduleFromRunLoop(_reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
}
}
- (void)dealloc
{
[self stopNotifier];
if (_reachabilityRef != NULL)
{
CFRelease(_reachabilityRef);
}
}
#pragma mark - Network Flag Handling
- (OSSNetworkStatus)networkStatusForFlags:(SCNetworkReachabilityFlags)flags
{
PrintReachabilityFlags(flags, "networkStatusForFlags");
if ((flags & kSCNetworkReachabilityFlagsReachable) == 0)
{
// The target host is not reachable.
return OSSNotReachable;
}
OSSNetworkStatus returnValue = OSSNotReachable;
if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0)
{
/*
If the target host is reachable and no connection is required then we'll assume (for now) that you're on Wi-Fi...
*/
returnValue = OSSReachableViaWiFi;
}
if ((((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) ||
(flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0))
{
/*
... and the connection is on-demand (or on-traffic) if the calling application is using the CFSocketStream or higher APIs...
*/
if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0)
{
/*
... and no [user] intervention is needed...
*/
returnValue = OSSReachableViaWiFi;
}
}
#if TARGET_OS_IOS
if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN)
{
/*
... but WWAN connections are OK if the calling application is using the CFNetwork APIs.
*/
returnValue = OSSReachableViaWWAN;
}
#endif
return returnValue;
}
- (BOOL)connectionRequired
{
NSAssert(_reachabilityRef != NULL, @"connectionRequired called with NULL reachabilityRef");
SCNetworkReachabilityFlags flags;
if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags))
{
return (flags & kSCNetworkReachabilityFlagsConnectionRequired);
}
return NO;
}
- (OSSNetworkStatus)currentReachabilityStatus
{
NSAssert(_reachabilityRef != NULL, @"currentOSSNetworkStatus called with NULL SCNetworkReachabilityRef");
OSSNetworkStatus returnValue = OSSNotReachable;
SCNetworkReachabilityFlags flags;
if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags))
{
returnValue = [self networkStatusForFlags:flags];
}
return returnValue;
}
@end

View File

@@ -0,0 +1,15 @@
//
// OSSGetBucketInfoRequest.h
// AliyunOSSSDK
//
// Created by huaixu on 2018/7/10.
// Copyright © 2018年 aliyun. All rights reserved.
//
#import "OSSRequest.h"
@interface OSSGetBucketInfoRequest : OSSRequest
@property (nonatomic, copy) NSString *bucketName;
@end

View File

@@ -0,0 +1,17 @@
//
// OSSGetBucketInfoRequest.m
// AliyunOSSSDK
//
// Created by huaixu on 2018/7/10.
// Copyright © 2018 aliyun. All rights reserved.
//
#import "OSSGetBucketInfoRequest.h"
@implementation OSSGetBucketInfoRequest
- (NSDictionary *)requestParams {
return @{@"bucketInfo": @""};
}
@end

View File

@@ -0,0 +1,57 @@
//
// OSSGetBucketInfoResult.h
// AliyunOSSSDK
//
// Created by huaixu on 2018/7/10.
// Copyright © 2018年 aliyun. All rights reserved.
//
#import "OSSResult.h"
@interface OSSBucketOwner : NSObject
@property (nonatomic, copy) NSString *userName;
@property (nonatomic, copy) NSString *userId;
@end
@interface OSSAccessControlList : NSObject
@property (nonatomic, copy) NSString *grant;
@end
@interface OSSGetBucketInfoResult : OSSResult
/// Created date.
@property (nonatomic, copy) NSString *creationDate;
/// Bucket name.
@property (nonatomic, copy) NSString *bucketName;
/// Bucket location.
@property (nonatomic, copy) NSString *location;
/// Storage class (Standard, IA, Archive)
@property (nonatomic, copy) NSString *storageClass;
/**
Internal endpoint. It could be accessed within AliCloud under the same
location.
*/
@property (nonatomic, copy) NSString *intranetEndpoint;
/**
External endpoint.It could be accessed from anywhere.
*/
@property (nonatomic, copy) NSString *extranetEndpoint;
/// Bucket owner.
@property (nonatomic, strong) OSSBucketOwner *owner;
@property (nonatomic, strong) OSSAccessControlList *acl;
@end

View File

@@ -0,0 +1,23 @@
//
// OSSGetBucketInfoResult.m
// AliyunOSSSDK
//
// Created by huaixu on 2018/7/10.
// Copyright © 2018 aliyun. All rights reserved.
//
#import "OSSGetBucketInfoResult.h"
@implementation OSSBucketOwner
@end
@implementation OSSAccessControlList
@end
@implementation OSSGetBucketInfoResult
@end

View File

@@ -0,0 +1,26 @@
//
// OSSGetObjectACLRequest.h
// AliyunOSSSDK
//
// Created by huaixu on 2018/1/26.
// Copyright © 2018年 aliyun. All rights reserved.
//
#import "OSSRequest.h"
NS_ASSUME_NONNULL_BEGIN
@interface OSSGetObjectACLRequest : OSSRequest
/**
the bucket's name which object stored
*/
@property (nonatomic, copy) NSString *bucketName;
/**
the name of object
*/
@property (nonatomic, copy) NSString *objectName;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,13 @@
//
// OSSGetObjectACLRequest.m
// AliyunOSSSDK
//
// Created by huaixu on 2018/1/26.
// Copyright © 2018 aliyun. All rights reserved.
//
#import "OSSGetObjectACLRequest.h"
@implementation OSSGetObjectACLRequest
@end

View File

@@ -0,0 +1,19 @@
//
// OSSGetObjectACLResult.h
// AliyunOSSSDK
//
// Created by huaixu on 2018/1/26.
// Copyright © 2018年 aliyun. All rights reserved.
//
#import "OSSResult.h"
@interface OSSGetObjectACLResult : OSSResult
/**
the ACL of object,valid values: @"private",@"public-read",@"public-read-write".
if object's ACL inherit from bucket,it will return @"default".
*/
@property (nonatomic, copy) NSString *grant;
@end

View File

@@ -0,0 +1,13 @@
//
// OSSGetObjectACLResult.m
// AliyunOSSSDK
//
// Created by huaixu on 2018/1/26.
// Copyright © 2018 aliyun. All rights reserved.
//
#import "OSSGetObjectACLResult.h"
@implementation OSSGetObjectACLResult
@end

View File

@@ -0,0 +1,23 @@
//
// GetObjectTaggingRequest.h
// AliyunOSSSDK
//
// Created by ws on 2021/5/25.
// Copyright © 2021 aliyun. All rights reserved.
//
#import "OSSRequest.h"
NS_ASSUME_NONNULL_BEGIN
@interface OSSGetObjectTaggingRequest : OSSRequest
/* bucket name */
@property (nonatomic, copy) NSString *bucketName;
/* object name */
@property (nonatomic, copy) NSString *objectKey;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,17 @@
//
// GetObjectTaggingRequest.m
// AliyunOSSSDK
//
// Created by ws on 2021/5/25.
// Copyright © 2021 aliyun. All rights reserved.
//
#import "OSSGetObjectTaggingRequest.h"
@implementation OSSGetObjectTaggingRequest
- (NSDictionary *)requestParams {
return @{@"tagging": @""};
}
@end

View File

@@ -0,0 +1,19 @@
//
// GetObjectTaggingResult.h
// AliyunOSSSDK
//
// Created by ws on 2021/5/25.
// Copyright © 2021 aliyun. All rights reserved.
//
#import "OSSResult.h"
NS_ASSUME_NONNULL_BEGIN
@interface OSSGetObjectTaggingResult : OSSResult
@property (nonatomic, strong) NSDictionary *tags;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,13 @@
//
// GetObjectTaggingResult.m
// AliyunOSSSDK
//
// Created by ws on 2021/5/25.
// Copyright © 2021 aliyun. All rights reserved.
//
#import "OSSGetObjectTaggingResult.h"
@implementation OSSGetObjectTaggingResult
@end

View File

@@ -0,0 +1,17 @@
//
// OSSGetSymlinkRequest.h
// AliyunOSSSDK
//
// Created by huaixu on 2018/8/1.
// Copyright © 2018年 aliyun. All rights reserved.
//
#import "OSSRequest.h"
@interface OSSGetSymlinkRequest : OSSRequest
@property (nonatomic, copy) NSString *bucketName;
@property (nonatomic, copy) NSString *objectKey;
@end

View File

@@ -0,0 +1,17 @@
//
// OSSGetSymlinkRequest.m
// AliyunOSSSDK
//
// Created by huaixu on 2018/8/1.
// Copyright © 2018 aliyun. All rights reserved.
//
#import "OSSGetSymlinkRequest.h"
@implementation OSSGetSymlinkRequest
- (NSDictionary *)requestParams {
return @{@"symlink": @""};
}
@end

View File

@@ -0,0 +1,13 @@
//
// OSSGetSymlinkResult.h
// AliyunOSSSDK
//
// Created by huaixu on 2018/8/1.
// Copyright © 2018年 aliyun. All rights reserved.
//
#import "OSSResult.h"
@interface OSSGetSymlinkResult : OSSResult
@end

View File

@@ -0,0 +1,13 @@
//
// OSSGetSymlinkResult.m
// AliyunOSSSDK
//
// Created by huaixu on 2018/8/1.
// Copyright © 2018 aliyun. All rights reserved.
//
#import "OSSGetSymlinkResult.h"
@implementation OSSGetSymlinkResult
@end

View File

@@ -0,0 +1,39 @@
//
// OSSHttpResponseParser.h
// AliyunOSSSDK
//
// Created by huaixu on 2018/1/22.
// Copyright © 2018年 aliyun. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "OSSConstants.h"
#import "OSSTask.h"
NS_ASSUME_NONNULL_BEGIN
/**
HTTP response parser
*/
@interface OSSHttpResponseParser : NSObject
@property (nonatomic, copy) OSSNetworkingOnRecieveDataBlock onRecieveBlock;
@property (nonatomic, strong) NSURL *downloadingFileURL;
/**
* A Boolean value that determines whether verfifying crc64.
When set to YES, it will verify crc64 when transmission is completed normally.
The default value of this property is NO.
*/
@property (nonatomic, assign) BOOL crc64Verifiable;
- (instancetype)initForOperationType:(OSSOperationType)operationType;
- (void)consumeHttpResponse:(NSHTTPURLResponse *)response;
- (OSSTask *)consumeHttpResponseBody:(NSData *)data;
- (nullable id)constructResultObject;
- (void)reset;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,704 @@
//
// OSSHttpResponseParser.m
// AliyunOSSSDK
//
// Created by huaixu on 2018/1/22.
// Copyright © 2018 aliyun. All rights reserved.
//
#import "OSSHttpResponseParser.h"
#import "NSMutableData+OSS_CRC.h"
#import "OSSXMLDictionary.h"
#import "OSSDefine.h"
#import "OSSModel.h"
#import "OSSUtil.h"
#import "OSSLog.h"
#import "OSSGetObjectACLResult.h"
#import "OSSDeleteMultipleObjectsResult.h"
#import "OSSGetBucketInfoResult.h"
#import "OSSRestoreObjectResult.h"
#import "OSSPutSymlinkResult.h"
#import "OSSGetSymlinkResult.h"
#import "OSSGetObjectTaggingResult.h"
#import "OSSPutObjectTaggingResult.h"
#import "OSSDeleteObjectTaggingResult.h"
@implementation OSSHttpResponseParser {
OSSOperationType _operationTypeForThisParser;
NSFileHandle * _fileHandle;
NSMutableData * _collectingData;
NSHTTPURLResponse * _response;
uint64_t _crc64ecma;
}
- (void)reset {
_collectingData = nil;
_fileHandle = nil;
_response = nil;
}
- (instancetype)initForOperationType:(OSSOperationType)operationType {
if (self = [super init]) {
_operationTypeForThisParser = operationType;
}
return self;
}
- (void)consumeHttpResponse:(NSHTTPURLResponse *)response {
_response = response;
}
- (OSSTask *)consumeHttpResponseBody:(NSData *)data
{
if (_crc64Verifiable&&(_operationTypeForThisParser == OSSOperationTypeGetObject))
{
NSMutableData *mutableData = [NSMutableData dataWithData:data];
if (_crc64ecma != 0)
{
_crc64ecma = [OSSUtil crc64ForCombineCRC1:_crc64ecma
CRC2:[mutableData oss_crc64]
length:mutableData.length];
}else
{
_crc64ecma = [mutableData oss_crc64];
}
}
if (self.onRecieveBlock) {
self.onRecieveBlock(data);
return [OSSTask taskWithResult:nil];
}
NSError * error;
if (self.downloadingFileURL)
{
if (!_fileHandle)
{
NSFileManager * fm = [NSFileManager defaultManager];
NSString * dirName = [[self.downloadingFileURL path] stringByDeletingLastPathComponent];
if (![fm fileExistsAtPath:dirName])
{
[fm createDirectoryAtPath:dirName withIntermediateDirectories:YES attributes:nil error:&error];
}
if (![fm fileExistsAtPath:dirName] || error)
{
return [OSSTask taskWithError:[NSError errorWithDomain:OSSClientErrorDomain
code:OSSClientErrorCodeFileCantWrite
userInfo:@{OSSErrorMessageTOKEN: [NSString stringWithFormat:@"Can't create dir at %@", dirName]}]];
}
[fm createFileAtPath:[self.downloadingFileURL path] contents:nil attributes:nil];
if (![fm fileExistsAtPath:[self.downloadingFileURL path]])
{
return [OSSTask taskWithError:[NSError errorWithDomain:OSSClientErrorDomain
code:OSSClientErrorCodeFileCantWrite
userInfo:@{OSSErrorMessageTOKEN: [NSString stringWithFormat:@"Can't create file at %@", [self.downloadingFileURL path]]}]];
}
_fileHandle = [NSFileHandle fileHandleForWritingToURL:self.downloadingFileURL error:&error];
if (error)
{
return [OSSTask taskWithError:[NSError errorWithDomain:OSSClientErrorDomain
code:OSSClientErrorCodeFileCantWrite
userInfo:[error userInfo]]];
}
[_fileHandle writeData:data];
} else
{
@try {
[_fileHandle writeData:data];
}
@catch (NSException *exception) {
return [OSSTask taskWithError:[NSError errorWithDomain:OSSServerErrorDomain
code:OSSClientErrorCodeFileCantWrite
userInfo:@{OSSErrorMessageTOKEN: [exception description]}]];
}
}
} else
{
if (!_collectingData)
{
_collectingData = [[NSMutableData alloc] initWithData:data];
}
else
{
[_collectingData appendData:data];
}
}
return [OSSTask taskWithResult:nil];
}
- (void)parseResponseHeader:(NSHTTPURLResponse *)response toResultObject:(OSSResult *)result
{
result.httpResponseCode = [_response statusCode];
result.httpResponseHeaderFields = [NSDictionary dictionaryWithDictionary:[_response allHeaderFields]];
[[_response allHeaderFields] enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
NSString * keyString = (NSString *)key;
if ([keyString isEqualToString:@"x-oss-request-id"])
{
result.requestId = obj;
}
else if ([keyString isEqualToString:@"x-oss-hash-crc64ecma"])
{
result.remoteCRC64ecma = obj;
}
}];
}
- (NSDictionary *)parseResponseHeaderToGetMeta:(NSHTTPURLResponse *)response
{
NSMutableDictionary * meta = [NSMutableDictionary new];
/* define a constant array to contain all meta header name */
static NSArray * OSSObjectMetaFieldNames = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
OSSObjectMetaFieldNames = @[@"Content-Type", @"Content-Length", @"Etag", @"Last-Modified", @"x-oss-request-id", @"x-oss-object-type",
@"If-Modified-Since", @"If-Unmodified-Since", @"If-Match", @"If-None-Match"];
});
/****************************************************************/
[[_response allHeaderFields] enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
NSString * keyString = (NSString *)key;
if ([OSSObjectMetaFieldNames containsObject:keyString] || [keyString hasPrefix:@"x-oss-meta"]) {
[meta setObject:obj forKey:key];
}
}];
return meta;
}
- (nullable id)constructResultObject
{
if (self.onRecieveBlock)
{
return nil;
}
switch (_operationTypeForThisParser)
{
case OSSOperationTypeGetService:
{
OSSGetServiceResult * getServiceResult = [OSSGetServiceResult new];
if (_response)
{
[self parseResponseHeader:_response toResultObject:getServiceResult];
}
if (_collectingData)
{
NSDictionary * parseDict = [NSDictionary oss_dictionaryWithXMLData:_collectingData];
OSSLogVerbose(@"Get service dict: %@", parseDict);
if (parseDict)
{
getServiceResult.ownerId = [[parseDict objectForKey:OSSOwnerXMLTOKEN] objectForKey:OSSIDXMLTOKEN];
getServiceResult.ownerDispName = [[parseDict objectForKey:OSSOwnerXMLTOKEN] objectForKey:OSSDisplayNameXMLTOKEN];
getServiceResult.prefix = [parseDict objectForKey:OSSPrefixXMLTOKEN];
getServiceResult.marker = [parseDict objectForKey:OSSMarkerXMLTOKEN];
getServiceResult.maxKeys = [[parseDict objectForKey:OSSMaxKeysXMLTOKEN] intValue];
getServiceResult.isTruncated = [[parseDict objectForKey:OSSIsTruncatedXMLTOKEN] boolValue];
getServiceResult.nextMarker = [parseDict objectForKey:OSSNextMarkerXMLTOKEN];
id bucketObject = [[parseDict objectForKey:OSSBucketsXMLTOKEN] objectForKey:OSSBucketXMLTOKEN];
if ([bucketObject isKindOfClass:[NSArray class]]) {
getServiceResult.buckets = bucketObject;
} else if ([bucketObject isKindOfClass:[NSDictionary class]]) {
NSArray * arr = [NSArray arrayWithObject:bucketObject];
getServiceResult.buckets = arr;
} else {
getServiceResult.buckets = nil;
}
}
}
return getServiceResult;
}
case OSSOperationTypeCreateBucket:
{
OSSCreateBucketResult * createBucketResult = [OSSCreateBucketResult new];
if (_response)
{
[self parseResponseHeader:_response toResultObject:createBucketResult];
[_response.allHeaderFields enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
if ([((NSString *)key) isEqualToString:@"Location"]) {
createBucketResult.location = obj;
*stop = YES;
}
}];
}
return createBucketResult;
}
case OSSOperationTypeGetBucketACL:
{
OSSGetBucketACLResult * getBucketACLResult = [OSSGetBucketACLResult new];
if (_response)
{
[self parseResponseHeader:_response toResultObject:getBucketACLResult];
}
if (_collectingData)
{
NSDictionary * parseDict = [NSDictionary oss_dictionaryWithXMLData:_collectingData];
OSSLogVerbose(@"Get service dict: %@", parseDict);
if (parseDict)
{
getBucketACLResult.aclGranted = [[parseDict objectForKey:OSSAccessControlListXMLTOKEN] objectForKey:OSSGrantXMLTOKEN];
}
}
return getBucketACLResult;
}
case OSSOperationTypeDeleteBucket:
{
OSSDeleteBucketResult * deleteBucketResult = [OSSDeleteBucketResult new];
if (_response) {
[self parseResponseHeader:_response toResultObject:deleteBucketResult];
}
return deleteBucketResult;
}
case OSSOperationTypeGetBucket:
{
OSSGetBucketResult * getBucketResult = [OSSGetBucketResult new];
if (_response) {
[self parseResponseHeader:_response toResultObject:getBucketResult];
}
if (_collectingData) {
NSDictionary * parsedDict = [NSDictionary oss_dictionaryWithXMLData:_collectingData];
OSSLogVerbose(@"Get bucket dict: %@", parsedDict);
if (parsedDict) {
getBucketResult.bucketName = [parsedDict objectForKey:OSSNameXMLTOKEN];
getBucketResult.prefix = [parsedDict objectForKey:OSSPrefixXMLTOKEN];
getBucketResult.marker = [parsedDict objectForKey:OSSMarkerXMLTOKEN];
getBucketResult.nextMarker = [parsedDict objectForKey:OSSNextMarkerXMLTOKEN];
getBucketResult.maxKeys = (int32_t)[[parsedDict objectForKey:OSSMaxKeysXMLTOKEN] integerValue];
getBucketResult.delimiter = [parsedDict objectForKey:OSSDelimiterXMLTOKEN];
getBucketResult.isTruncated = [[parsedDict objectForKey:OSSIsTruncatedXMLTOKEN] boolValue];
id contentObject = [parsedDict objectForKey:OSSContentsXMLTOKEN];
if ([contentObject isKindOfClass:[NSArray class]]) {
getBucketResult.contents = contentObject;
} else if ([contentObject isKindOfClass:[NSDictionary class]]) {
NSArray * arr = [NSArray arrayWithObject:contentObject];
getBucketResult.contents = arr;
} else {
getBucketResult.contents = nil;
}
NSMutableArray * commentPrefixesArr = [NSMutableArray new];
id commentPrefixes = [parsedDict objectForKey:OSSCommonPrefixesXMLTOKEN];
if ([commentPrefixes isKindOfClass:[NSArray class]]) {
for (NSDictionary * prefix in commentPrefixes) {
[commentPrefixesArr addObject:[prefix objectForKey:@"Prefix"]];
}
} else if ([commentPrefixes isKindOfClass:[NSDictionary class]]) {
[commentPrefixesArr addObject:[(NSDictionary *)commentPrefixes objectForKey:@"Prefix"]];
} else {
commentPrefixesArr = nil;
}
getBucketResult.commentPrefixes = commentPrefixesArr;
}
}
return getBucketResult;
}
case OSSOperationTypeListMultipartUploads:
{
OSSListMultipartUploadsResult * listMultipartUploadsResult = [OSSListMultipartUploadsResult new];
if (_response) {
[self parseResponseHeader:_response toResultObject:listMultipartUploadsResult];
}
if (_collectingData) {
NSDictionary * parsedDict = [NSDictionary oss_dictionaryWithXMLData:_collectingData];
OSSLogVerbose(@"List multipart uploads dict: %@", parsedDict);
if (parsedDict) {
listMultipartUploadsResult.bucketName = [parsedDict objectForKey:OSSBucketXMLTOKEN];
listMultipartUploadsResult.prefix = [parsedDict objectForKey:OSSPrefixXMLTOKEN];
listMultipartUploadsResult.uploadIdMarker = [parsedDict objectForKey:OSSUploadIdMarkerXMLTOKEN];
listMultipartUploadsResult.nextUploadIdMarker = [parsedDict objectForKey:OSSUploadIdMarkerXMLTOKEN];
listMultipartUploadsResult.keyMarker = [parsedDict objectForKey:OSSKeyMarkerXMLTOKEN];
listMultipartUploadsResult.nextKeyMarker = [parsedDict objectForKey:OSSNextKeyMarkerXMLTOKEN];
listMultipartUploadsResult.maxUploads = (int32_t)[[parsedDict objectForKey:OSSMaxUploadsXMLTOKEN] integerValue];
listMultipartUploadsResult.delimiter = [parsedDict objectForKey:OSSDelimiterXMLTOKEN];
listMultipartUploadsResult.isTruncated = [[parsedDict objectForKey:OSSIsTruncatedXMLTOKEN] boolValue];
id contentObject = [parsedDict objectForKey:OSSUploadXMLTOKEN];
if ([contentObject isKindOfClass:[NSArray class]]) {
listMultipartUploadsResult.uploads = contentObject;
} else if ([contentObject isKindOfClass:[NSDictionary class]]) {
NSArray * arr = [NSArray arrayWithObject:contentObject];
listMultipartUploadsResult.uploads = arr;
} else {
listMultipartUploadsResult.uploads = nil;
}
NSMutableArray * commentPrefixesArr = [NSMutableArray new];
id commentPrefixes = [parsedDict objectForKey:OSSCommonPrefixesXMLTOKEN];
if ([commentPrefixes isKindOfClass:[NSArray class]]) {
for (NSDictionary * prefix in commentPrefixes) {
[commentPrefixesArr addObject:[prefix objectForKey:@"Prefix"]];
}
} else if ([commentPrefixes isKindOfClass:[NSDictionary class]]) {
[commentPrefixesArr addObject:[(NSDictionary *)commentPrefixes objectForKey:@"Prefix"]];
} else {
commentPrefixesArr = nil;
}
listMultipartUploadsResult.commonPrefixes = commentPrefixesArr;
}
}
return listMultipartUploadsResult;
}
case OSSOperationTypeHeadObject:
{
OSSHeadObjectResult * headObjectResult = [OSSHeadObjectResult new];
if (_response)
{
[self parseResponseHeader:_response toResultObject:headObjectResult];
headObjectResult.objectMeta = [self parseResponseHeaderToGetMeta:_response];
}
return headObjectResult;
}
case OSSOperationTypeGetObject:
{
OSSGetObjectResult * getObejctResult = [OSSGetObjectResult new];
OSSLogDebug(@"GetObjectResponse: %@", _response);
if (_response)
{
[self parseResponseHeader:_response toResultObject:getObejctResult];
getObejctResult.objectMeta = [self parseResponseHeaderToGetMeta:_response];
if (_crc64ecma != 0)
{
getObejctResult.localCRC64ecma = [NSString stringWithFormat:@"%llu",_crc64ecma];
}
}
if (_fileHandle) {
[_fileHandle closeFile];
}
if (_collectingData) {
getObejctResult.downloadedData = _collectingData;
}
return getObejctResult;
}
case OSSOperationTypeGetObjectACL:
{
OSSGetObjectACLResult * getObjectACLResult = [OSSGetObjectACLResult new];
OSSLogDebug(@"GetObjectResponse: %@", _response);
if (_response)
{
[self parseResponseHeader:_response toResultObject:getObjectACLResult];
}
if (_collectingData) {
NSDictionary * parseDict = [NSDictionary oss_dictionaryWithXMLData:_collectingData];
OSSLogVerbose(@"Get service dict: %@", parseDict);
getObjectACLResult.grant = parseDict[@"AccessControlList"][@"Grant"];
}
return getObjectACLResult;
}
case OSSOperationTypePutObject:
{
OSSPutObjectResult * putObjectResult = [OSSPutObjectResult new];
if (_response)
{
[self parseResponseHeader:_response toResultObject:putObjectResult];
[_response.allHeaderFields enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
if ([((NSString *)key) isEqualToString:@"Etag"]) {
putObjectResult.eTag = obj;
*stop = YES;
}
}];
}
if (_collectingData) {
putObjectResult.serverReturnJsonString = [[NSString alloc] initWithData:_collectingData encoding:NSUTF8StringEncoding];
}
return putObjectResult;
}
case OSSOperationTypeAppendObject:
{
OSSAppendObjectResult * appendObjectResult = [OSSAppendObjectResult new];
if (_response) {
[self parseResponseHeader:_response toResultObject:appendObjectResult];
[_response.allHeaderFields enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
if ([((NSString *)key) isEqualToString:@"Etag"]) {
appendObjectResult.eTag = obj;
}
if ([((NSString *)key) isEqualToString:@"x-oss-next-append-position"]) {
appendObjectResult.xOssNextAppendPosition = [((NSString *)obj) longLongValue];
}
}];
}
return appendObjectResult;
}
case OSSOperationTypeDeleteObject: {
OSSDeleteObjectResult * deleteObjectResult = [OSSDeleteObjectResult new];
if (_response) {
[self parseResponseHeader:_response toResultObject:deleteObjectResult];
}
return deleteObjectResult;
}
case OSSOperationTypeDeleteMultipleObjects: {
OSSDeleteMultipleObjectsResult * deleteObjectResult = [OSSDeleteMultipleObjectsResult new];
if (_response) {
[self parseResponseHeader:_response toResultObject:deleteObjectResult];
}
if (_collectingData) {
NSDictionary *dict = [NSDictionary oss_dictionaryWithXMLData:_collectingData];
deleteObjectResult.encodingType = dict[@"EncodingType"];
deleteObjectResult.deletedObjects = dict[@"Deleted"];
}
return deleteObjectResult;
}
case OSSOperationTypePutObjectACL: {
OSSPutObjectACLResult * putObjectACLResult = [OSSPutObjectACLResult new];
if (_response) {
[self parseResponseHeader:_response toResultObject:putObjectACLResult];
}
return putObjectACLResult;
}
case OSSOperationTypeCopyObject: {
OSSCopyObjectResult * copyObjectResult = [OSSCopyObjectResult new];
if (_response) {
[self parseResponseHeader:_response toResultObject:copyObjectResult];
}
if (_collectingData) {
OSSLogVerbose(@"copy object dict: %@", [NSDictionary oss_dictionaryWithXMLData:_collectingData]);
NSDictionary * parsedDict = [NSDictionary oss_dictionaryWithXMLData:_collectingData];
if (parsedDict) {
copyObjectResult.lastModifed = [parsedDict objectForKey:OSSLastModifiedXMLTOKEN];
copyObjectResult.eTag = [parsedDict objectForKey:OSSETagXMLTOKEN];
}
}
return copyObjectResult;
}
case OSSOperationTypeInitMultipartUpload: {
OSSInitMultipartUploadResult * initMultipartUploadResult = [OSSInitMultipartUploadResult new];
if (_response) {
[self parseResponseHeader:_response toResultObject:initMultipartUploadResult];
}
if (_collectingData) {
NSDictionary * parsedDict = [NSDictionary oss_dictionaryWithXMLData:_collectingData];
OSSLogVerbose(@"init multipart upload result: %@", parsedDict);
if (parsedDict) {
initMultipartUploadResult.uploadId = [parsedDict objectForKey:OSSUploadIdXMLTOKEN];
}
}
return initMultipartUploadResult;
}
case OSSOperationTypeUploadPart: {
OSSUploadPartResult * uploadPartResult = [OSSUploadPartResult new];
if (_response) {
[self parseResponseHeader:_response toResultObject:uploadPartResult];
[_response.allHeaderFields enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
if ([((NSString *)key) isEqualToString:@"Etag"]) {
uploadPartResult.eTag = obj;
*stop = YES;
}
}];
}
return uploadPartResult;
}
case OSSOperationTypeCompleteMultipartUpload: {
OSSCompleteMultipartUploadResult * completeMultipartUploadResult = [OSSCompleteMultipartUploadResult new];
if (_response) {
[self parseResponseHeader:_response toResultObject:completeMultipartUploadResult];
}
if (_collectingData) {
if ([[[_response.allHeaderFields objectForKey:OSSHttpHeaderContentType] description] isEqual:@"application/xml"]) {
OSSLogVerbose(@"complete multipart upload result: %@", [NSDictionary oss_dictionaryWithXMLData:_collectingData]);
NSDictionary * parsedDict = [NSDictionary oss_dictionaryWithXMLData:_collectingData];
if (parsedDict) {
completeMultipartUploadResult.location = [parsedDict objectForKey:OSSLocationXMLTOKEN];
completeMultipartUploadResult.eTag = [parsedDict objectForKey:OSSETagXMLTOKEN];
}
} else {
completeMultipartUploadResult.serverReturnJsonString = [[NSString alloc] initWithData:_collectingData encoding:NSUTF8StringEncoding];
}
}
return completeMultipartUploadResult;
}
case OSSOperationTypeListMultipart: {
OSSListPartsResult * listPartsReuslt = [OSSListPartsResult new];
if (_response) {
[self parseResponseHeader:_response toResultObject:listPartsReuslt];
}
if (_collectingData) {
NSDictionary * parsedDict = [NSDictionary oss_dictionaryWithXMLData:_collectingData];
OSSLogVerbose(@"list multipart upload result: %@", parsedDict);
if (parsedDict) {
listPartsReuslt.nextPartNumberMarker = [[parsedDict objectForKey:OSSNextPartNumberMarkerXMLTOKEN] intValue];
listPartsReuslt.maxParts = [[parsedDict objectForKey:OSSMaxPartsXMLTOKEN] intValue];
listPartsReuslt.isTruncated = [[parsedDict objectForKey:OSSIsTruncatedXMLTOKEN] boolValue];
id partsObject = [parsedDict objectForKey:OSSPartXMLTOKEN];
if ([partsObject isKindOfClass:[NSArray class]]) {
listPartsReuslt.parts = partsObject;
} else if ([partsObject isKindOfClass:[NSDictionary class]]) {
NSArray * arr = [NSArray arrayWithObject:partsObject];
listPartsReuslt.parts = arr;
} else {
listPartsReuslt.parts = nil;
}
}
}
return listPartsReuslt;
}
case OSSOperationTypeAbortMultipartUpload: {
OSSAbortMultipartUploadResult * abortMultipartUploadResult = [OSSAbortMultipartUploadResult new];
if (_response) {
[self parseResponseHeader:_response toResultObject:abortMultipartUploadResult];
}
return abortMultipartUploadResult;
}
case OSSOperationTypeTriggerCallBack: {
OSSCallBackResult *callbackResult = [OSSCallBackResult new];
if (_response) {
[self parseResponseHeader:_response toResultObject:callbackResult];
}
if (_collectingData) {
if ([[[_response.allHeaderFields objectForKey:OSSHttpHeaderContentType] description] isEqual:@"application/xml"]) {
NSDictionary * parsedDict = [NSDictionary oss_dictionaryWithXMLData:_collectingData];
OSSLogVerbose(@"callback trigger result<xml>: %@", parsedDict);
callbackResult.serverReturnXML = parsedDict;
} else if ([[[_response.allHeaderFields objectForKey:OSSHttpHeaderContentType] description] isEqual:@"application/json"]) {
callbackResult.serverReturnJsonString = [[NSString alloc] initWithData:_collectingData encoding:NSUTF8StringEncoding];
OSSLogVerbose(@"callback trigger result<json>: %@", callbackResult.serverReturnJsonString);
}
}
return callbackResult;
}
case OSSOperationTypeImagePersist: {
OSSImagePersistResult *imagePersistResult = [OSSImagePersistResult new];
if (_response) {
[self parseResponseHeader:_response toResultObject:imagePersistResult];
}
return imagePersistResult;
}
case OSSOperationTypeGetBucketInfo: {
OSSGetBucketInfoResult *bucketInfoResult = [[OSSGetBucketInfoResult alloc] init];
if (_collectingData)
{
NSDictionary * parseDict = [NSDictionary oss_dictionaryWithXMLData:_collectingData];
if ([parseDict valueForKey:@"Bucket"])
{
NSDictionary *result = [parseDict valueForKey:@"Bucket"];
OSSLogVerbose(@"Get bucketInfo dict: %@", parseDict);
bucketInfoResult.bucketName = [result valueForKey:@"Name"];
bucketInfoResult.storageClass = [result valueForKey:@"StorageClass"];
bucketInfoResult.location = [result valueForKey:@"Location"];
bucketInfoResult.intranetEndpoint = [result valueForKey:@"IntranetEndpoint"];
bucketInfoResult.extranetEndpoint = [result valueForKey:@"ExtranetEndpoint"];
bucketInfoResult.creationDate = [result valueForKey:@"CreationDate"];
if ([result valueForKey:@"Owner"]) {
bucketInfoResult.owner = [[OSSBucketOwner alloc] init];
bucketInfoResult.owner.userName = [[result valueForKey:@"Owner"] valueForKey:@"DisplayName"];
bucketInfoResult.owner.userId = [[result valueForKey:@"Owner"] valueForKey:@"ID"];
}
if ([result valueForKey:@"AccessControlList"]) {
bucketInfoResult.acl = [OSSAccessControlList new];
bucketInfoResult.acl.grant = [[result valueForKey:@"AccessControlList"] valueForKey:@"Grant"];
}
}
}
if (_response) {
[self parseResponseHeader:_response toResultObject:bucketInfoResult];
}
return bucketInfoResult;
}
case OSSOperationTypeRestoreObject: {
OSSRestoreObjectResult * restoreObjectResult = [OSSRestoreObjectResult new];
if (_response) {
[self parseResponseHeader:_response toResultObject:restoreObjectResult];
}
return restoreObjectResult;
}
case OSSOperationTypePutSymlink: {
OSSPutSymlinkResult * putSymlinkResult = [OSSPutSymlinkResult new];
if (_response) {
[self parseResponseHeader:_response toResultObject:putSymlinkResult];
}
return putSymlinkResult;
}
case OSSOperationTypeGetSymlink: {
OSSGetSymlinkResult * getSymlinkResult = [OSSGetSymlinkResult new];
if (_response) {
[self parseResponseHeader:_response toResultObject:getSymlinkResult];
}
return getSymlinkResult;
}
case OSSOperationTypeGetObjectTagging: {
OSSGetObjectTaggingResult *result = [OSSGetObjectTaggingResult new];
NSMutableDictionary *tags = [NSMutableDictionary dictionary];
if (_collectingData)
{
NSDictionary * parseDict = [NSDictionary oss_dictionaryWithXMLData:_collectingData];
NSDictionary *tagSet = [parseDict objectForKey:@"TagSet"];
if (tagSet) {
if ([tagSet[@"Tag"] isKindOfClass:[NSArray class]]) {
for (NSDictionary * tag in tagSet[@"Tag"]) {
NSString *key = tag[@"Key"];
NSString *value = tag[@"Value"];
if (key && value) {
[tags setObject:value forKey:key];
}
}
} else if ([tagSet[@"Tag"] isKindOfClass:[NSDictionary class]]) {
NSString *key = tagSet[@"Tag"][@"Key"];
NSString *value = tagSet[@"Tag"][@"Value"];
if (key && value) {
[tags setObject:value forKey:key];
}
}
}
}
result.tags = tags;
if (_response) {
[self parseResponseHeader:_response toResultObject:result];
}
return result;
}
case OSSOperationTypePutObjectTagging: {
OSSPutObjectTaggingResult *result = [OSSPutObjectTaggingResult new];
if (_response) {
[self parseResponseHeader:_response toResultObject:result];
}
return result;
}
case OSSOperationTypeDeleteObjectTagging: {
OSSDeleteObjectTaggingResult *result = [OSSDeleteObjectTaggingResult new];
if (_response) {
[self parseResponseHeader:_response toResultObject:result];
}
return result;
}
default: {
OSSLogError(@"unknown operation type");
break;
}
}
return nil;
}
@end

View File

@@ -0,0 +1,16 @@
//
// OSSHttpdns.h
// AliyunOSSiOS
//
// Created by zhouzhuo on 5/1/16.
// Copyright © 2016 zhouzhuo. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface OSSHttpdns : NSObject
+ (instancetype)sharedInstance;
- (NSString *)asynGetIpByHost:(NSString *)host;
@end

View File

@@ -0,0 +1,147 @@
//
// OSSHttpdns.m
// AliyunOSSiOS
//
// Created by zhouzhuo on 5/1/16.
// Copyright © 2016 zhouzhuo. All rights reserved.
//
#import "OSSLog.h"
#import "OSSHttpdns.h"
#import "OSSIPv6Adapter.h"
NSString * const OSS_HTTPDNS_SERVER_IP = @"203.107.1.1";
NSString * const OSS_HTTPDNS_SERVER_PORT = @"80";
NSString * const ACCOUNT_ID = @"181345";
NSTimeInterval const MAX_ENDURABLE_EXPIRED_TIME_IN_SECOND = 60; // The DNS entry's expiration time in seconds. After it expires, the entry is invalid.
NSTimeInterval const PRERESOLVE_IN_ADVANCE_IN_SECOND = 10; // Once the remaining valid time of an DNS entry is less than this number, issue a DNS request to prefetch the data.
@interface IpObject : NSObject
@property (nonatomic, copy) NSString * ip;
@property (nonatomic, assign) NSTimeInterval expiredTime;
@end
@implementation IpObject
@end
@implementation OSSHttpdns {
NSMutableDictionary * gHostIpMap;
NSMutableSet * penddingSet;
}
+ (instancetype)sharedInstance {
static OSSHttpdns * sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [OSSHttpdns new];
});
return sharedInstance;
}
- (instancetype)init {
if (self = [super init]) {
gHostIpMap = [NSMutableDictionary new];
penddingSet = [NSMutableSet new];
}
return self;
}
/**
* OSS SDK specific
*
* @param host it needs strictly follow the domain's format, such as oss-cn-hangzhou.aliyuncs.com
*
* @return an ip in the ip list of the resolved host.
*/
- (NSString *)asynGetIpByHost:(NSString *)host {
IpObject * ipObject = [gHostIpMap objectForKey:host];
if (!ipObject) {
// if the host is not resolved, asynchronously resolve it and return nil
[self resolveHost:host];
return nil;
} else if ([[NSDate date] timeIntervalSince1970] - ipObject.expiredTime > MAX_ENDURABLE_EXPIRED_TIME_IN_SECOND) {
// If the entry is expired, asynchronously resolve it and return nil.
[self resolveHost:host];
return nil;
} else if (ipObject.expiredTime -[[NSDate date] timeIntervalSince1970] < PRERESOLVE_IN_ADVANCE_IN_SECOND) {
// If the entry is about to expire, asynchronously resolve it and return the current value.
[self resolveHost:host];
return ipObject.ip;
} else {
// returns the current result.
return ipObject.ip;
}
}
/**
* resolve the host asynchronously
* If the host is being resolved, the call will be skipped.
*
* @param host the host to resolve
*/
- (void)resolveHost:(NSString *)host {
@synchronized (self) {
if ([penddingSet containsObject:host]) {
return;
} else {
[penddingSet addObject:host];
}
}
NSURL * url = [NSURL URLWithString:[NSString stringWithFormat:@"https://%@/%@/d?host=%@", [[OSSIPv6Adapter getInstance] handleIpv4Address:OSS_HTTPDNS_SERVER_IP], ACCOUNT_ID, host]];
NSURLSession * session = [NSURLSession sharedSession];
NSURLSessionDataTask * dataTask = [session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
IpObject * ipObject = nil;
NSUInteger statusCode = ((NSHTTPURLResponse *)response).statusCode;
if (statusCode != 200) {
OSSLogError(@"Httpdns resolve host: %@ failed, responseCode: %lu", host, (unsigned long)statusCode);
} else {
NSError *error = nil;
NSDictionary *json = nil;
if (data != nil){
json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
}
if (error != nil || json == nil){
return;
}
NSTimeInterval expiredTime = [[NSDate new] timeIntervalSince1970] + [[json objectForKey:@"ttl"] longLongValue];
NSArray *ips = [json objectForKey:@"ips"];
if (ips == nil || [ips count] == 0) {
OSSLogError(@"Httpdns resolve host: %@ failed, ip list empty.", host);
} else {
NSString * ip = ips[0];
ipObject = [IpObject new];
ipObject.expiredTime = expiredTime;
ipObject.ip = ip;
OSSLogDebug(@"Httpdns resolve host: %@ success, ip: %@, expiredTime: %lf", host, ipObject.ip, ipObject.expiredTime);
}
}
@synchronized (self) {
if (ipObject) {
gHostIpMap[host] = ipObject;
}
[penddingSet removeObject:host];
}
}];
[dataTask resume];
}
@end

View File

@@ -0,0 +1,114 @@
/*
* Copyright (c) 2000-2015 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. The rights granted to you under the License
* may not be used to create, or enable the creation or redistribution of,
* unlawful or unlicensed copies of an Apple operating system, or to
* circumvent, violate, or enable the circumvention or violation of, any
* terms of an Apple operating system software license agreement.
*
* Please obtain a copy of the License at
* https://www.opensource.apple.com/apsl/ and read it before using this file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
/*
* Copyright (c) 1980, 1986, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)route.h 8.3 (Berkeley) 4/19/94
* $FreeBSD: src/sys/net/route.h,v 1.36.2.1 2000/08/16 06:14:23 jayanth Exp $
*/
#ifndef AlicloudIPv6Adapter_h
#define AlicloudIPv6Adapter_h
#import <Foundation/Foundation.h>
@interface OSSIPv6Adapter : NSObject
+ (instancetype)getInstance;
/**
* @brief Checks if it's a IPv6-only network. If it's true, it's IPv6-only.
*
* @return return YES for IPv6-only network,otherWise return NO
*/
- (BOOL)isIPv6OnlyNetwork;
/**
* @brief Refresh the IPV6-only check
*
* @return return YES for IPv6-only network,otherWise return NO
*/
- (BOOL)reResolveIPv6OnlyStatus;
/**
* @brief Adapts the IPv4 address into IPv6 format under IPv6-only network.
* For example:
42.156.220.114 -> 64:ff9b::2a9c:dc72
* @param addr
* ip address
*
* @return return an IPv6 address
*/
- (NSString *)handleIpv4Address:(NSString *)addr;
/**
* @brief Checks if it's an IPv4 address.
*
* @return return YES while addr is an IPv4 address,otherwise return NO
*/
- (BOOL)isIPv4Address:(NSString *)addr;
/**
* @brief Checks if it's an IPv6 address
*
* @return return YES while addr is an IPv6 address,otherwise return NO
*/
- (BOOL)isIPv6Address:(NSString *)addr;
@end
#endif /* OSSIPv6Adapter_h */

View File

@@ -0,0 +1,196 @@
//
// OSSIPv6Adapter.m
//
// Created by lingkun on 16/5/16.
// Copyright © 2016 Ali. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "OSSIPv6Adapter.h"
#import "OSSIPv6PrefixResolver.h"
#import "OSSLog.h"
#include <arpa/inet.h>
#include <dns.h>
#include <err.h>
#include <ifaddrs.h>
#include <net/if.h>
#include <netdb.h>
#include <netinet/in.h>
#include <resolv.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#if TARGET_OS_IOS
#import <UIKit/UIApplication.h>
#elif TARGET_OS_OSX
#import <AppKit/NSApplication.h>
#endif
#define UNKNOWN_STACK 0
#define SUPPORT_IPV4_STACK 1
#define SUPPORT_IPV6_STACK 2
#define ROUNDUP_LEN(a) \
((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
#define TypeEN "en0"
#define IOS_9_VERSION @"9.0"
@implementation OSSIPv6Adapter
{
BOOL isIPv6Only;
BOOL isIPv6OnlyResolved;
}
- (instancetype)init {
if (self = [super init]) {
isIPv6Only = NO;
isIPv6OnlyResolved = NO;
NSString *notificationName;
#if TARGET_OS_IOS
notificationName = UIApplicationDidBecomeActiveNotification;
#elif TARGET_OS_OSX
notificationName = NSApplicationDidBecomeActiveNotification;
#endif
// When App switches to active status, refresh the IPv6-only check.
NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
[defaultCenter addObserver:self
selector:@selector(appDidBecomeActiveFunc)
name:notificationName
object:nil];
}
return self;
}
+ (instancetype)getInstance {
static id singletonInstance = nil;
static dispatch_once_t once_token;
dispatch_once(&once_token, ^{
if (!singletonInstance) {
singletonInstance = [[super allocWithZone:NULL] init];
}
});
return singletonInstance;
}
- (BOOL)isIPv6OnlyNetwork {
@synchronized(self) {
if (isIPv6OnlyResolved) {
return isIPv6Only;
}
OSSLogDebug(@"Start resolved network to see if in IPv6-Only env.");
int localStack = 0;
localStack = SUPPORT_IPV4_STACK | SUPPORT_IPV6_STACK;
localStack &= [self getDNSServersIpStack];
if (localStack & SUPPORT_IPV4_STACK) {
// support IPv4
isIPv6Only = NO;
} else if (localStack & SUPPORT_IPV6_STACK) {
// IPv6-Only
isIPv6Only = YES;
[[OSSIPv6PrefixResolver getInstance] updateIPv6Prefix];
} else {
OSSLogDebug(@"[%s]: Error.", __FUNCTION__);
isIPv6Only = NO;
}
isIPv6OnlyResolved = YES;
if (isIPv6Only) {
OSSLogDebug(@"[%s]: IPv6-Only network now.", __FUNCTION__);
} else {
OSSLogDebug(@"[%s]: Not IPv6-Only network now.", __FUNCTION__);
}
return isIPv6Only;
}
}
- (void)appDidBecomeActiveFunc {
OSSLogDebug(@"[%s]: App become active, refresh IPv6-Only status.", __FUNCTION__);
[self reResolveIPv6OnlyStatus];
}
- (BOOL)reResolveIPv6OnlyStatus {
isIPv6OnlyResolved = NO;
return [self isIPv6OnlyNetwork];
}
- (NSString *)handleIpv4Address:(NSString *)addr {
if (addr == nil || addr.length == 0) {
return nil;
}
if ([self isIPv6Address:addr]) return [NSString stringWithFormat:@"[%@]", addr];
NSString *convertedAddr;
if ([self isIPv6OnlyNetwork]) {
convertedAddr = [[OSSIPv6PrefixResolver getInstance] convertIPv4toIPv6:addr];
return [NSString stringWithFormat:@"[%@]", convertedAddr];
} else {
convertedAddr = addr;
}
return convertedAddr;
}
/**
* @brief Looks up the DNS server stack and returns the flag combinations of SUPPORT_IPV4_STACK and SUPPORT_IPV6_STACK.
*
* @return the flag combinations of SUPPORT_IPV4_STACK and SUPPORT_IPV6_STACK
*/
- (int)getDNSServersIpStack {
int dns_stack = 0;
res_state res = malloc(sizeof(struct __res_state));
int result = res_ninit(res);
if (result == 0) {
union res_9_sockaddr_union *addr_union = malloc(res->nscount * sizeof(union res_9_sockaddr_union));
res_getservers(res, addr_union, res->nscount);
for (int i = 0; i < res->nscount; i++) {
if (addr_union[i].sin.sin_family == AF_INET) {
char ip[INET_ADDRSTRLEN];
if (inet_ntop(AF_INET, &(addr_union[i].sin.sin_addr), ip, INET_ADDRSTRLEN)) {
dns_stack |= SUPPORT_IPV4_STACK;
}
} else if (addr_union[i].sin6.sin6_family == AF_INET6) {
char ip[INET6_ADDRSTRLEN];
if (inet_ntop(AF_INET6, &(addr_union[i].sin6.sin6_addr), ip, INET6_ADDRSTRLEN)) {
dns_stack |= SUPPORT_IPV6_STACK;
}
} else {
OSSLogDebug(@"%s: Undefined family.", __FUNCTION__);
}
}
free(addr_union);
}
res_ndestroy(res);
free(res);
return dns_stack;
}
- (BOOL)isIPv4Address:(NSString *)addr {
if (addr == nil) {
return NO;
}
const char *utf8 = [addr UTF8String];
// Check valid IPv4.
struct in_addr dst;
int success = inet_pton(AF_INET, utf8, &(dst.s_addr));
return success == 1;
}
- (BOOL)isIPv6Address:(NSString *)addr {
if (addr == nil) {
return NO;
}
const char *utf8 = [addr UTF8String];
// Check valid IPv6.
struct in6_addr dst6;
int success = inet_pton(AF_INET6, utf8, &dst6);
return (success == 1);
}
@end

View File

@@ -0,0 +1,23 @@
//
// OSSIPv6PrefixResolver.h
//
// Created by lingkun on 16/5/16.
// Edit by zhouzhuo on 16/5/22
// Copyright © 2016 Ali. All rights reserved.
//
#ifndef AlicloudIPv6PrefixResolver_h
#define AlicloudIPv6PrefixResolver_h
#import <Foundation/Foundation.h>
@interface OSSIPv6PrefixResolver : NSObject
+ (instancetype)getInstance;
- (void)updateIPv6Prefix;
- (NSString *)convertIPv4toIPv6:(NSString *)ipv4;
@end
#endif /* OSSIPv6PrefixResolver_h */

View File

@@ -0,0 +1,205 @@
//
// OSSIPv6PrefixResolver.m
//
// Created by lingkun on 16/5/16.
// Edit by zhouzhuo on 2016/5/22
// Copyright © 2016 Ali. All rights reserved.
#import "OSSIPv6PrefixResolver.h"
#import "OSSLog.h"
#import <Foundation/Foundation.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
static const __uint8_t NS_PREFIX_32[4] = {0x20, 0x01, 0x0d, 0xb8};
static const __uint8_t NS_PREFIX_40[5] = {0x20, 0x01, 0x0d, 0xb8, 0x01};
static const __uint8_t NS_PREFIX_48[6] = {0x20, 0x01, 0x0d, 0xb8, 0x01, 0x22};
static const __uint8_t NS_PREFIX_56[7] = {0x20, 0x01, 0x0d, 0xb8, 0x01, 0x22, 0x03};
static const __uint8_t NS_PREFIX_64[8] = {0x20, 0x01, 0x0d, 0xb8, 0x01, 0x22, 0x03, 0x44};
static const __uint8_t NS_PREFIX_96[12] = {0x20, 0x01, 0x0d, 0xb8, 0x01, 0x22, 0x03, 0x44, 0x00, 0x00, 0x00, 0x00};
static const __uint8_t WK_PREFIX_96[12] = {0x00, 0x64, 0xff, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static const __uint8_t* V6_PREFIX_CONTENT_TABLE[7] = {
WK_PREFIX_96,
NS_PREFIX_32,
NS_PREFIX_40,
NS_PREFIX_48,
NS_PREFIX_56,
NS_PREFIX_64,
NS_PREFIX_96};
static const __uint8_t V6_PREFIX_SIZE_TABLE[7] = {
sizeof(WK_PREFIX_96)/sizeof(__uint8_t),
sizeof(NS_PREFIX_32)/sizeof(__uint8_t),
sizeof(NS_PREFIX_40)/sizeof(__uint8_t),
sizeof(NS_PREFIX_48)/sizeof(__uint8_t),
sizeof(NS_PREFIX_56)/sizeof(__uint8_t),
sizeof(NS_PREFIX_64)/sizeof(__uint8_t),
sizeof(NS_PREFIX_96)/sizeof(__uint8_t)};
static const __uint8_t V6_PREFIX_TABLE_SIZE = 7;
typedef enum {
IPv6PrefixUnResolved = 0,
IPv6PrefixResolving,
IPv6PrefixResolved
} IPv6PrefixResolveStatus;
@implementation OSSIPv6PrefixResolver {
IPv6PrefixResolveStatus ipv6PrefixResolveStatus;
__uint8_t *ipv6Prefix;
int prefixLen;
}
- (instancetype)init {
if (self = [super init]) {
ipv6PrefixResolveStatus = IPv6PrefixUnResolved;
ipv6Prefix = (__uint8_t *)V6_PREFIX_CONTENT_TABLE[0];
prefixLen = V6_PREFIX_SIZE_TABLE[0];
}
return self;
}
+ (instancetype)getInstance {
static id singletonInstance = nil;
static dispatch_once_t once_token;
dispatch_once(&once_token, ^{
if (!singletonInstance) {
singletonInstance = [[super allocWithZone:NULL] init];
}
});
return singletonInstance;
}
/**
* @brief Updates IPv6 Prefix
*/
- (void)updateIPv6Prefix {
@synchronized(self) {
ipv6PrefixResolveStatus = IPv6PrefixUnResolved;
[self resolveIPv6Prefix:ipv6Prefix];
}
}
- (BOOL)isIPv6Prefix:(__uint8_t *)v6Prefix
withPrefixLen:(int)pLen
withIP:(__uint8_t *)ip
withIPLen:(int)ipLen {
for (int i = 0; i < pLen && i < ipLen; i++) {
if (*(v6Prefix + i) != *(ip + i)) {
return NO;
}
}
return YES;
}
- (__uint8_t)resolveIPv6Prefix:(__uint8_t *)prefix {
if ( !prefix ) {
return 0;
}
__uint8_t len = prefixLen;
memcpy(prefix, ipv6Prefix, prefixLen);
@synchronized(self) {
if (ipv6PrefixResolveStatus==IPv6PrefixUnResolved ) {
ipv6PrefixResolveStatus = IPv6PrefixResolving;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
struct addrinfo hints, *addr;
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_INET6;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_DEFAULT;
if (0 != getaddrinfo("ipv4only.arpa", "http", &hints, &addr)) {
ipv6PrefixResolveStatus = IPv6PrefixUnResolved;
return;
}
if (addr && AF_INET6 == addr->ai_addr->sa_family) {
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)(addr->ai_addr);
if ( !addr6 ) {
ipv6PrefixResolveStatus = IPv6PrefixUnResolved;
return;
}
__uint8_t* u8 = addr6->sin6_addr.__u6_addr.__u6_addr8;
for (__uint8_t i=0; i < V6_PREFIX_TABLE_SIZE; i++) {
if ([self isIPv6Prefix:(__uint8_t *)V6_PREFIX_CONTENT_TABLE[i]
withPrefixLen:V6_PREFIX_SIZE_TABLE[i]
withIP:u8
withIPLen:16]) {
ipv6Prefix = (__uint8_t *)V6_PREFIX_CONTENT_TABLE[i];
prefixLen = V6_PREFIX_SIZE_TABLE[i];
ipv6PrefixResolveStatus = IPv6PrefixResolved;
break;
}
}
ipv6PrefixResolveStatus = IPv6PrefixUnResolved;
}
});
}
}
return len;
}
- (NSString *)convertIPv4toIPv6:(NSString *)ipv4 {
if ([ipv4 length] <= 0) {
return nil;
}
__uint8_t ipv6[16] = {0x00};
__uint8_t length = [self resolveIPv6Prefix:ipv6];
if (length <= 0) {
return nil;
}
in_addr_t addr_v4 = inet_addr([ipv4 UTF8String]);
// length
if (length==4 || length==12) { //32 bits or 96 bits
ipv6[length+0] |= (__uint8_t)(addr_v4>>0 & 0xff);
ipv6[length+1] |= (__uint8_t)(addr_v4>>8 & 0xff);
ipv6[length+2] |= (__uint8_t)(addr_v4>>16 & 0xff);
ipv6[length+3] |= (__uint8_t)(addr_v4>>24 & 0xff);
}
else if (length == 5) { //40 bits :a.b.c.0.d
ipv6[length+0] |= (__uint8_t)(addr_v4>>0 & 0xff);
ipv6[length+1] |= (__uint8_t)(addr_v4>>8 & 0xff);
ipv6[length+2] |= (__uint8_t)(addr_v4>>16 & 0xff);
ipv6[length+4] |= (__uint8_t)(addr_v4>>24 & 0xff);
}
else if (length == 6) { //48 bits :a.b.0.c.d
ipv6[length+0] |= (__uint8_t)(addr_v4>>0 & 0xff);
ipv6[length+1] |= (__uint8_t)(addr_v4>>8 & 0xff);
ipv6[length+3] |= (__uint8_t)(addr_v4>>16 & 0xff);
ipv6[length+4] |= (__uint8_t)(addr_v4>>24 & 0xff);
}
else if (length == 7) { //56 bits :a.0.b.c.d
ipv6[length+0] |= (__uint8_t)(addr_v4>>0 & 0xff);
ipv6[length+2] |= (__uint8_t)(addr_v4>>8 & 0xff);
ipv6[length+3] |= (__uint8_t)(addr_v4>>16 & 0xff);
ipv6[length+4] |= (__uint8_t)(addr_v4>>24 & 0xff);
}
else if (length == 8) { //64 bits :0.a.b.c.d
ipv6[length+1] |= (__uint8_t)(addr_v4>>0 & 0xff);
ipv6[length+2] |= (__uint8_t)(addr_v4>>8 & 0xff);
ipv6[length+3] |= (__uint8_t)(addr_v4>>16 & 0xff);
ipv6[length+4] |= (__uint8_t)(addr_v4>>24 & 0xff);
}
// constructs the IPv6 structure
char addr_text[ MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) ];
if(inet_ntop(AF_INET6, ipv6, addr_text, INET6_ADDRSTRLEN)) {
NSString *ret = [NSString stringWithUTF8String:addr_text];
return ret;
}
return nil;
}
@end

View File

@@ -0,0 +1,22 @@
//
// OSSInputStreamHelper.h
// AliyunOSSSDK
//
// Created by 怀叙 on 2017/12/7.
// Copyright © 2017年 阿里云. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface OSSInputStreamHelper : NSObject
@property (nonatomic, assign) uint64_t crc64;
- (instancetype)initWithFileAtPath:(nonnull NSString *)path;
- (instancetype)initWithURL:(nonnull NSURL *)URL;
- (void)syncReadBuffers;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,80 @@
//
// OSSInputStreamHelper.m
// AliyunOSSSDK
//
// Created by 怀 on 2017/12/7.
// Copyright © 2017 . All rights reserved.
//
#import "OSSInputStreamHelper.h"
#import "OSSLog.h"
#import "aos_crc64.h"
@interface OSSInputStreamHelper ()
{
NSInputStream *_inputStream;
CFAbsoluteTime _startTime;
dispatch_semaphore_t _semaphore;
}
@end
@implementation OSSInputStreamHelper
- (instancetype)initWithFileAtPath:(nonnull NSString *)path
{
self = [super init];
if (self) {
_crc64 = 0;
_inputStream = [NSInputStream inputStreamWithFileAtPath:path];
_semaphore = dispatch_semaphore_create(1);
}
return self;
}
- (instancetype)initWithURL:(nonnull NSURL *)URL
{
self = [super init];
if (self) {
_crc64 = 0;
_inputStream = [NSInputStream inputStreamWithURL:URL];
_semaphore = dispatch_semaphore_create(1);
}
return self;
}
- (void)syncReadBuffers
{
dispatch_semaphore_wait(_semaphore, DISPATCH_TIME_FOREVER);
_startTime = CFAbsoluteTimeGetCurrent();
[_inputStream open];
NSInteger length = 1;
while (length > 0)
{
@autoreleasepool{
uint8_t streamData[1024 * 4];
length = [_inputStream read:streamData maxLength:1024 * 4];
if (length > 0) {
_crc64 = aos_crc64(_crc64, streamData, length);
}
}
}
if (length < 0) {
OSSLogError(@"there is an error when reading buffer from file!");
}
[_inputStream close];
CFAbsoluteTime duration = CFAbsoluteTimeGetCurrent() - _startTime;
OSSLogDebug(@"read file cost time is :%f",duration);
dispatch_semaphore_signal(_semaphore);
}
- (uint64_t)crc64
{
return _crc64;
}
@end

54
Pods/AliyunOSSiOS/AliyunOSSSDK/OSSLog.h generated Normal file
View File

@@ -0,0 +1,54 @@
//
// OSSLog.h
// oss_ios_sdk
//
// Created by zhouzhuo on 8/16/15.
// Copyright (c) 2015 aliyun.com. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "OSSCocoaLumberjack.h"
static const OSSDDLogLevel ossLogLevel = OSSDDLogLevelAll;
// colorful log configuration
// see https://github.com/robbiehanson/XcodeColors
#define XCODE_COLORS_ESCAPE @"\033["
#define XCODE_COLORS_RESET_FG XCODE_COLORS_ESCAPE @"fg;" // Clear any foreground color
#define XCODE_COLORS_RESET_BG XCODE_COLORS_ESCAPE @"bg;" // Clear any background color
#define XCODE_COLORS_RESET XCODE_COLORS_ESCAPE @";" // Clear any foreground or background color
#define OSSLogVerbose(frmt, ...)\
if ([OSSLog isLogEnable]) {\
OSSDDLogVerbose(@"[Verbose]: %@", [NSString stringWithFormat:(frmt), ##__VA_ARGS__]);\
}
#define OSSLogDebug(frmt, ...)\
if ([OSSLog isLogEnable]) {\
OSSDDLogDebug(@"[Debug]: %@", [NSString stringWithFormat:(frmt), ##__VA_ARGS__]);\
}
#define OSSLogDebugNoFile(frmt, ...)\
if ([OSSLog isLogEnable]) {\
NSLog(@"[Debug]: %@", [NSString stringWithFormat:(frmt), ##__VA_ARGS__]);\
}
#define OSSLogError(frmt, ...)\
if ([OSSLog isLogEnable]) {\
OSSDDLogError(@"[Error]: %@", [NSString stringWithFormat:(frmt), ##__VA_ARGS__]);\
}
#define OSSLogWarn(frmt, ...)\
if ([OSSLog isLogEnable]) {\
OSSDDLogWarn(@"[Warning]: %@", [NSString stringWithFormat:(frmt), ##__VA_ARGS__]);\
}
static BOOL isEnable;
@interface OSSLog : NSObject
+ (void)enableLog;
+ (void)disableLog;
+ (BOOL)isLogEnable;
@end

31
Pods/AliyunOSSiOS/AliyunOSSSDK/OSSLog.m generated Normal file
View File

@@ -0,0 +1,31 @@
//
// OSSLog.m
// oss_ios_sdk
//
// Created by zhouzhuo on 8/16/15.
// Copyright (c) 2015 aliyun.com. All rights reserved.
//
#import "OSSLog.h"
#import "OSSUtil.h"
@implementation OSSLog
+ (void)enableLog {
if([OSSUtil hasPhoneFreeSpace]){
isEnable = YES;
[OSSDDLog removeAllLoggers];
[OSSDDLog addLogger:[OSSNSLogger sharedInstance]];
OSSDDFileLogger *fileLogger = [[OSSDDFileLogger alloc] init];
[OSSDDLog addLogger:fileLogger];
}
}
+ (void)disableLog {
isEnable = NO;
}
+ (BOOL)isLogEnable {
return isEnable;
}
@end

1538
Pods/AliyunOSSiOS/AliyunOSSSDK/OSSModel.h generated Normal file

File diff suppressed because it is too large Load Diff

805
Pods/AliyunOSSiOS/AliyunOSSSDK/OSSModel.m generated Normal file
View File

@@ -0,0 +1,805 @@
//
// OSSModel.m
// oss_ios_sdk
//
// Created by zhouzhuo on 8/16/15.
// Copyright (c) 2015 aliyun.com. All rights reserved.
//
#import "OSSDefine.h"
#import "OSSModel.h"
#import "OSSBolts.h"
#import "OSSUtil.h"
#import "OSSNetworking.h"
#import "OSSLog.h"
#import "OSSXMLDictionary.h"
#import "OSSSignerParams.h"
#import "OSSSignerBase.h"
#if TARGET_OS_IOS
#import <UIKit/UIDevice.h>
#import <UIKit/UIApplication.h>
#endif
#import "OSSAllRequestNeededMessage.h"
#import "OSSNetworkingRequestDelegate.h"
@implementation NSDictionary (OSS)
- (NSString *)base64JsonString {
NSError * error;
NSData * jsonData = [NSJSONSerialization dataWithJSONObject:self
options:0
error:&error];
if (!jsonData) {
return @"e30="; // base64("{}");
} else {
NSString * jsonStr = [[[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding] stringByReplacingOccurrencesOfString:@"\\/" withString:@"/"];
NSLog(@"callback json - %@", jsonStr);
return [[jsonStr dataUsingEncoding:NSUTF8StringEncoding] base64EncodedStringWithOptions:0];
}
}
@end
@implementation OSSSyncMutableDictionary
- (instancetype)init {
if (self = [super init]) {
_dictionary = [NSMutableDictionary dictionary];
_dispatchQueue = dispatch_queue_create("com.aliyun.aliyunsycmutabledictionary", DISPATCH_QUEUE_SERIAL);
}
return self;
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)addObserverForResetCurrentRetryCount {
#if TARGET_OS_IOS
NSString *notificationName = UIApplicationWillEnterForegroundNotification;
// When App switches to active status, refresh the IPv6-only check.
NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
[defaultCenter addObserver:self
selector:@selector(appWillEnterForeground)
name:notificationName
object:nil];
#endif
}
- (NSArray *)allKeys {
__block NSArray *allKeys = nil;
dispatch_sync(self.dispatchQueue, ^{
allKeys = [self.dictionary allKeys];
});
return allKeys;
}
- (id)objectForKey:(id)aKey {
__block id returnObject = nil;
dispatch_sync(self.dispatchQueue, ^{
returnObject = [self.dictionary objectForKey:aKey];
});
return returnObject;
}
- (void)setObject:(id)anObject forKey:(id <NSCopying>)aKey {
dispatch_sync(self.dispatchQueue, ^{
[self.dictionary oss_setObject:anObject forKey:aKey];
});
}
- (void)removeObjectForKey:(id)aKey {
dispatch_sync(self.dispatchQueue, ^{
[self.dictionary removeObjectForKey:aKey];
});
}
- (void)appWillEnterForeground {
dispatch_sync(self.dispatchQueue, ^{
for (NSString *key in self.dictionary.allKeys) {
OSSNetworkingRequestDelegate *delegate = self.dictionary[key];
delegate.currentRetryCount = 0;
}
});
}
@end
@implementation OSSFederationToken
- (NSString *)description
{
return [NSString stringWithFormat:@"OSSFederationToken<%p>:{AccessKeyId: %@\nAccessKeySecret: %@\nSecurityToken: %@\nExpiration: %@}", self, _tAccessKey, _tSecretKey, _tToken, _expirationTimeInGMTFormat];
}
- (BOOL)useSecurityToken {
return self.tToken != nil;
}
@end
@implementation OSSPlainTextAKSKPairCredentialProvider
- (instancetype)initWithPlainTextAccessKey:(nonnull NSString *)accessKey secretKey:(nonnull NSString *)secretKey {
if (self = [super init]) {
self.accessKey = [accessKey oss_trim];
self.secretKey = [secretKey oss_trim];
}
return self;
}
- (nullable NSString *)sign:(NSString *)content error:(NSError **)error {
if (![self.accessKey oss_isNotEmpty] || ![self.secretKey oss_isNotEmpty])
{
if (error != nil)
{
*error = [NSError errorWithDomain:OSSClientErrorDomain
code:OSSClientErrorCodeSignFailed
userInfo:@{OSSErrorMessageTOKEN: @"accessKey or secretKey can't be null"}];
}
return nil;
}
NSString * sign = [OSSUtil calBase64Sha1WithData:content withSecret:self.secretKey];
return [NSString stringWithFormat:@"OSS %@:%@", self.accessKey, sign];
}
@end
@implementation OSSCustomSignerCredentialProvider
- (instancetype)initWithImplementedSigner:(OSSCustomSignContentBlock)signContent
{
NSParameterAssert(signContent);
if (self = [super init])
{
_signContent = signContent;
}
return self;
}
- (NSString *)sign:(NSString *)content error:(NSError **)error
{
NSString * signature = @"";
@synchronized(self) {
signature = self.signContent(content, error);
}
if (*error) {
*error = [NSError errorWithDomain:OSSClientErrorDomain
code:OSSClientErrorCodeSignFailed
userInfo:[[NSDictionary alloc] initWithDictionary:[*error userInfo]]];
return nil;
}
return signature;
}
@end
@implementation OSSFederationCredentialProvider
- (instancetype)initWithFederationTokenGetter:(OSSGetFederationTokenBlock)federationTokenGetter {
if (self = [super init]) {
self.federationTokenGetter = federationTokenGetter;
}
return self;
}
- (nullable OSSFederationToken *)getToken:(NSError **)error {
OSSFederationToken * validToken = nil;
@synchronized(self) {
if (self.cachedToken == nil) {
self.cachedToken = self.federationTokenGetter();
} else {
if (self.cachedToken.expirationTimeInGMTFormat) {
NSDateFormatter * fm = [NSDateFormatter new];
fm.locale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"];
[fm setDateFormat:@"yyyy-MM-dd'T'HH:mm:ssZ"];
self.cachedToken.expirationTimeInMilliSecond = [[fm dateFromString:self.cachedToken.expirationTimeInGMTFormat] timeIntervalSince1970] * 1000;
self.cachedToken.expirationTimeInGMTFormat = nil;
OSSLogVerbose(@"Transform GMT date to expirationTimeInMilliSecond: %lld", self.cachedToken.expirationTimeInMilliSecond);
}
NSDate * expirationDate = [NSDate dateWithTimeIntervalSince1970:(NSTimeInterval)(self.cachedToken.expirationTimeInMilliSecond / 1000)];
NSTimeInterval interval = [expirationDate timeIntervalSinceDate:[NSDate oss_clockSkewFixedDate]];
/* if this token will be expired after less than 5 min, we abort it in case of when request arrived oss server,
it's expired already. */
if (interval < 5 * 60) {
OSSLogDebug(@"get federation token, but after %lf second it would be expired", interval);
self.cachedToken = self.federationTokenGetter();
}
}
validToken = self.cachedToken;
}
if (!validToken)
{
if (error != nil)
{
*error = [NSError errorWithDomain:OSSClientErrorDomain
code:OSSClientErrorCodeSignFailed
userInfo:@{OSSErrorMessageTOKEN: @"Can't get a federation token"}];
}
return nil;
}
return validToken;
}
@end
@implementation OSSStsTokenCredentialProvider
- (OSSFederationToken *)getToken {
OSSFederationToken * token = [OSSFederationToken new];
token.tAccessKey = self.accessKeyId;
token.tSecretKey = self.secretKeyId;
token.tToken = self.securityToken;
token.expirationTimeInMilliSecond = NSIntegerMax;
return token;
}
- (instancetype)initWithAccessKeyId:(NSString *)accessKeyId secretKeyId:(NSString *)secretKeyId securityToken:(NSString *)securityToken {
if (self = [super init]) {
self.accessKeyId = [accessKeyId oss_trim];
self.secretKeyId = [secretKeyId oss_trim];
self.securityToken = [securityToken oss_trim];
}
return self;
}
- (NSString *)sign:(NSString *)content error:(NSError **)error {
NSString * sign = [OSSUtil calBase64Sha1WithData:content withSecret:self.secretKeyId];
return [NSString stringWithFormat:@"OSS %@:%@", self.accessKeyId, sign];
}
@end
@implementation OSSAuthCredentialProvider
- (instancetype)initWithAuthServerUrl:(NSString *)authServerUrl
{
return [self initWithAuthServerUrl:authServerUrl responseDecoder:nil];
}
- (instancetype)initWithAuthServerUrl:(NSString *)authServerUrl responseDecoder:(nullable OSSResponseDecoderBlock)decoder
{
self = [super initWithFederationTokenGetter:^OSSFederationToken * {
NSURL * url = [NSURL URLWithString:self.authServerUrl];
NSURLRequest * request = [NSURLRequest requestWithURL:url];
OSSTaskCompletionSource * tcs = [OSSTaskCompletionSource taskCompletionSource];
NSURLSession * session = [NSURLSession sharedSession];
NSURLSessionTask * sessionTask = [session dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
[tcs setError:error];
return;
}
[tcs setResult:data];
}];
[sessionTask resume];
[tcs.task waitUntilFinished];
if (tcs.task.error) {
return nil;
} else {
NSData* data = tcs.task.result;
if(decoder){
data = decoder(data);
}
NSDictionary * object = [NSJSONSerialization JSONObjectWithData:data
options:kNilOptions
error:nil];
int statusCode = [[object objectForKey:@"StatusCode"] intValue];
if (statusCode == 200) {
OSSFederationToken * token = [OSSFederationToken new];
// All the entries below are mandatory.
token.tAccessKey = [object objectForKey:@"AccessKeyId"];
token.tSecretKey = [object objectForKey:@"AccessKeySecret"];
token.tToken = [object objectForKey:@"SecurityToken"];
token.expirationTimeInGMTFormat = [object objectForKey:@"Expiration"];
OSSLogDebug(@"token: %@ %@ %@ %@", token.tAccessKey, token.tSecretKey, token.tToken, [object objectForKey:@"Expiration"]);
return token;
}else{
return nil;
}
}
}];
if(self){
self.authServerUrl = authServerUrl;
}
return self;
}
@end
NSString * const BACKGROUND_SESSION_IDENTIFIER = @"com.aliyun.oss.backgroundsession";
@implementation OSSClientConfiguration
- (instancetype)init {
if (self = [super init]) {
self.maxRetryCount = OSSDefaultRetryCount;
self.maxConcurrentRequestCount = OSSDefaultMaxConcurrentNum;
self.enableBackgroundTransmitService = NO;
self.isHttpdnsEnable = NO;
self.backgroundSesseionIdentifier = BACKGROUND_SESSION_IDENTIFIER;
self.timeoutIntervalForRequest = OSSDefaultTimeoutForRequestInSecond;
self.timeoutIntervalForResource = OSSDefaultTimeoutForResourceInSecond;
self.isPathStyleAccessEnable = NO;
self.isCustomPathPrefixEnable = NO;
self.cnameExcludeList = @[];
self.isAllowUACarrySystemInfo = YES;
self.isFollowRedirectsEnable = YES;
// When the value <= 0, do not set HTTPMaximumConnectionsPerHost and use the default value of NSURLSessionConfiguration
self.HTTPMaximumConnectionsPerHost = 0;
self.isAllowResetRetryCount = NO;
self.isAllowNetworkMetricInfo = NO;
self.signVersion = OSSSignVersionV1;
}
return self;
}
- (void)setCnameExcludeList:(NSArray *)cnameExcludeList {
NSMutableArray * array = [NSMutableArray new];
[cnameExcludeList enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
NSString * host = [(NSString *)obj lowercaseString];
if ([host containsString:@"://"]) {
NSString * trimHost = [host substringFromIndex:[host rangeOfString:@"://"].location + 3];
[array addObject:trimHost];
} else {
[array addObject:host];
}
}];
_cnameExcludeList = array.copy;
}
@end
@implementation OSSSignerInterceptor
- (instancetype)initWithCredentialProvider:(id<OSSCredentialProvider>)credentialProvider {
if (self = [super init]) {
self.credentialProvider = credentialProvider;
}
return self;
}
- (OSSTask *)interceptRequestMessage:(OSSAllRequestNeededMessage *)requestMessage {
OSSLogVerbose(@"signing intercepting - ");
NSString *resource = @"/";
if (requestMessage.bucketName) {
resource = [NSString stringWithFormat:@"/%@/", requestMessage.bucketName];
}
if (requestMessage.objectKey) {
resource = [resource oss_stringByAppendingPathComponentForURL:requestMessage.objectKey];
}
OSSSignerParams *signerParams = [[OSSSignerParams alloc] init];
signerParams.region = self.region;
signerParams.cloudBoxId = self.cloudBoxId;
signerParams.resourcePath = resource;
signerParams.credentialProvider = self.credentialProvider;
id<OSSRequestSigner> requestSigner = [OSSSignerBase createRequestSignerWithSignerVersion:self.version
signerParams:signerParams];
return [requestSigner sign:requestMessage];
}
@end
@implementation OSSUASettingInterceptor
- (instancetype)initWithClientConfiguration:(OSSClientConfiguration *)clientConfiguration{
if (self = [super init]) {
self.clientConfiguration = clientConfiguration;
}
return self;
}
- (OSSTask *)interceptRequestMessage:(OSSAllRequestNeededMessage *)request {
NSString * userAgent = [self getUserAgent:self.clientConfiguration.userAgentMark];
[request.headerParams oss_setObject:userAgent forKey:@"User-Agent"];
return [OSSTask taskWithResult:nil];
}
- (NSString *)getUserAgent:(NSString *)customUserAgent {
static NSString * userAgent = nil;
static dispatch_once_t once;
NSString * tempUserAgent = nil;
dispatch_once(&once, ^{
NSString *localeIdentifier = [[NSLocale currentLocale] localeIdentifier];
#if TARGET_OS_IOS
if (self.clientConfiguration.isAllowUACarrySystemInfo) {
NSString *systemName = [[[UIDevice currentDevice] systemName] stringByReplacingOccurrencesOfString:@" " withString:@"-"];
NSString *systemVersion = [[UIDevice currentDevice] systemVersion];
userAgent = [NSString stringWithFormat:@"%@/%@(/%@/%@/%@)", OSSUAPrefix, OSSSDKVersion, systemName, systemVersion, localeIdentifier];
} else {
userAgent = [NSString stringWithFormat:@"%@/%@(/%@)", OSSUAPrefix, OSSSDKVersion, localeIdentifier];
}
#elif TARGET_OS_OSX
userAgent = [NSString stringWithFormat:@"%@/%@(/%@/%@/%@)", OSSUAPrefix, OSSSDKVersion, @"OSX", [NSProcessInfo processInfo].operatingSystemVersionString, localeIdentifier];
#endif
});
if(customUserAgent){
if(userAgent){
tempUserAgent = [[userAgent stringByAppendingString:@"/"] stringByAppendingString:customUserAgent];
}else{
tempUserAgent = customUserAgent;
}
}else{
tempUserAgent = userAgent;
}
return tempUserAgent;
}
@end
@implementation OSSTimeSkewedFixingInterceptor
- (OSSTask *)interceptRequestMessage:(OSSAllRequestNeededMessage *)request {
request.date = [[NSDate oss_clockSkewFixedDate] oss_asStringValue];
return [OSSTask taskWithResult:nil];
}
@end
@implementation OSSRange
- (instancetype)initWithStart:(int64_t)start withEnd:(int64_t)end {
if (self = [super init]) {
self.startPosition = start;
self.endPosition = end;
}
return self;
}
- (NSString *)toHeaderString {
NSString * rangeString = nil;
if (self.startPosition < 0 && self.endPosition < 0) {
rangeString = [NSString stringWithFormat:@"bytes=%lld-%lld", self.startPosition, self.endPosition];
} else if (self.startPosition < 0) {
rangeString = [NSString stringWithFormat:@"bytes=-%lld", self.endPosition];
} else if (self.endPosition < 0) {
rangeString = [NSString stringWithFormat:@"bytes=%lld-", self.startPosition];
} else {
rangeString = [NSString stringWithFormat:@"bytes=%lld-%lld", self.startPosition, self.endPosition];
}
return rangeString;
}
@end
#pragma mark request and result objects
@implementation OSSGetServiceRequest
- (NSDictionary *)requestParams {
NSMutableDictionary * params = [NSMutableDictionary dictionary];
[params oss_setObject:self.prefix forKey:@"prefix"];
[params oss_setObject:self.marker forKey:@"marker"];
if (self.maxKeys > 0) {
[params oss_setObject:[@(self.maxKeys) stringValue] forKey:@"max-keys"];
}
return [params copy];
}
@end
@implementation OSSGetServiceResult
@end
@implementation OSSCreateBucketRequest
- (instancetype)init
{
self = [super init];
if (self) {
_storageClass = OSSBucketStorageClassStandard;
}
return self;
}
- (NSString *)storageClassAsString {
NSString *storageClassString = nil;
switch (_storageClass) {
case OSSBucketStorageClassStandard:
storageClassString = @"Standard";
break;
case OSSBucketStorageClassIA:
storageClassString = @"IA";
break;
case OSSBucketStorageClassArchive:
storageClassString = @"Archive";
break;
default:
storageClassString = @"Unknown";
break;
}
return storageClassString;
}
@end
@implementation OSSCreateBucketResult
@end
@implementation OSSDeleteBucketRequest
@end
@implementation OSSDeleteBucketResult
@end
@implementation OSSGetBucketRequest
- (NSDictionary *)requestParams {
NSMutableDictionary * params = [NSMutableDictionary dictionary];
[params oss_setObject:self.delimiter forKey:@"delimiter"];
[params oss_setObject:self.prefix forKey:@"prefix"];
[params oss_setObject:self.marker forKey:@"marker"];
if (self.maxKeys > 0) {
[params oss_setObject:[@(self.maxKeys) stringValue] forKey:@"max-keys"];
}
return [params copy];
}
@end
@implementation OSSListMultipartUploadsRequest
- (NSDictionary *)requestParams {
NSMutableDictionary * params = [NSMutableDictionary dictionary];
[params oss_setObject:self.delimiter forKey:@"delimiter"];
[params oss_setObject:self.prefix forKey:@"prefix"];
[params oss_setObject:self.keyMarker forKey:@"key-marker"];
[params oss_setObject:self.uploadIdMarker forKey:@"upload-id-marker"];
[params oss_setObject:self.encodingType forKey:@"encoding-type"];
if (self.maxUploads > 0) {
[params oss_setObject:[@(self.maxUploads) stringValue] forKey:@"max-uploads"];
}
return [params copy];
}
@end
@implementation OSSListMultipartUploadsResult
@end
@implementation OSSGetBucketResult
@end
@implementation OSSGetBucketACLRequest
- (NSDictionary *)requestParams {
return @{@"acl": @""};
}
@end
@implementation OSSGetBucketACLResult
@end
@implementation OSSHeadObjectRequest
@end
@implementation OSSHeadObjectResult
@end
@implementation OSSGetObjectRequest
@end
@implementation OSSGetObjectResult
@end
@implementation OSSPutObjectACLRequest
- (instancetype)init
{
self = [super init];
if (self) {
_acl = @"default";
}
return self;
}
@end
@implementation OSSPutObjectACLResult
@end
@implementation OSSPutObjectRequest
- (instancetype)init {
if (self = [super init]) {
self.objectMeta = [NSDictionary new];
}
return self;
}
@end
@implementation OSSPutObjectResult
@end
@implementation OSSAppendObjectRequest
- (instancetype)init {
if (self = [super init]) {
self.objectMeta = [NSDictionary new];
}
return self;
}
@end
@implementation OSSAppendObjectResult
@end
@implementation OSSDeleteObjectRequest
@end
@implementation OSSDeleteObjectResult
@end
@implementation OSSCopyObjectRequest
- (instancetype)init {
if (self = [super init]) {
self.objectMeta = [NSDictionary new];
}
return self;
}
@end
@implementation OSSCopyObjectResult
@end
@implementation OSSInitMultipartUploadRequest
- (instancetype)init {
if (self = [super init]) {
self.objectMeta = [NSDictionary new];
}
return self;
}
@end
@implementation OSSInitMultipartUploadResult
@end
@implementation OSSUploadPartRequest
@end
@implementation OSSUploadPartResult
@end
@implementation OSSPartInfo
+ (instancetype)partInfoWithPartNum:(int32_t)partNum
eTag:(NSString *)eTag
size:(int64_t)size {
return [self partInfoWithPartNum:partNum
eTag:eTag
size:size
crc64:0];
}
+ (instancetype)partInfoWithPartNum:(int32_t)partNum eTag:(NSString *)eTag size:(int64_t)size crc64:(uint64_t)crc64
{
OSSPartInfo *parInfo = [OSSPartInfo new];
parInfo.partNum = partNum;
parInfo.eTag = eTag;
parInfo.size = size;
parInfo.crc64 = crc64;
return parInfo;
}
- (nonnull NSDictionary *)entityToDictionary
{
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setValue:@(_partNum) forKey:@"partNum"];
if (_eTag)
{
[dict setValue:_eTag forKey:@"eTag"];
}
[dict setValue:@(_size) forKey:@"size"];
[dict setValue:@(_crc64) forKey:@"crc64"];
return [dict copy];
}
- (NSString *)description
{
return [NSString stringWithFormat:@"OSSPartInfo<%p>:{partNum: %d,eTag: %@,partSize: %lld,crc64: %llu}",self,self.partNum,self.eTag,self.size,self.crc64];
}
#pragma marks - Protocol Methods
- (id)copyWithZone:(nullable NSZone *)zone
{
OSSPartInfo *instance = [[[self class] allocWithZone:zone] init];
instance.partNum = self.partNum;
instance.eTag = self.eTag;
instance.size = self.size;
instance.crc64 = self.crc64;
return instance;
}
@end
@implementation OSSCompleteMultipartUploadRequest
@end
@implementation OSSCompleteMultipartUploadResult
@end
@implementation OSSAbortMultipartUploadRequest
@end
@implementation OSSAbortMultipartUploadResult
@end
@implementation OSSListPartsRequest
@end
@implementation OSSListPartsResult
@end
@implementation OSSMultipartUploadRequest
- (instancetype)init {
if (self = [super init]) {
self.partSize = 256 * 1024;
self.threadNum = OSSDefaultThreadNum;
self.terminationMode = OSSTerminationModeAll;
}
return self;
}
- (void)cancel {
[super cancel];
}
@end
@implementation OSSResumableUploadRequest
- (instancetype)init {
if (self = [super init]) {
self.deleteUploadIdOnCancelling = YES;
self.partSize = 256 * 1024;
}
return self;
}
- (void)cancel {
[super cancel];
if(_runningChildrenRequest){
[_runningChildrenRequest cancel];
}
}
@end
@implementation OSSResumableUploadResult
@end
@implementation OSSCallBackRequest
@end
@implementation OSSCallBackResult
@end
@implementation OSSImagePersistRequest
@end
@implementation OSSImagePersistResult
@end

View File

@@ -0,0 +1,49 @@
//
// OSSNetworking.h
// oss_ios_sdk
//
// Created by zhouzhuo on 8/16/15.
// Copyright (c) 2015 aliyun.com. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "OSSModel.h"
@class OSSSyncMutableDictionary;
@class OSSNetworkingRequestDelegate;
@class OSSExecutor;
/**
Network parameters
*/
@interface OSSNetworkingConfiguration : NSObject
@property (nonatomic, assign) uint32_t maxRetryCount;
@property (nonatomic, assign) uint32_t maxConcurrentRequestCount;
@property (nonatomic, assign) BOOL enableBackgroundTransmitService;
@property (nonatomic, strong) NSString * backgroundSessionIdentifier;
@property (nonatomic, assign) NSTimeInterval timeoutIntervalForRequest;
@property (nonatomic, assign) NSTimeInterval timeoutIntervalForResource;
@property (nonatomic, strong) NSString * proxyHost;
@property (nonatomic, strong) NSNumber * proxyPort;
@property (nonatomic, assign) BOOL enableFollowRedirects;
@property (nonatomic, assign) BOOL enableNetworkMetricInfo;
@property (nonatomic, assign) uint32_t HTTPMaximumConnectionsPerHost;
@property (nonatomic, assign) BOOL enableResetRetryCount;
@end
/**
The network interface which OSSClient uses for network read and write operations.
*/
@interface OSSNetworking : NSObject <NSURLSessionDelegate, NSURLSessionDataDelegate>
@property (nonatomic, strong) NSURLSession * session;
@property (nonatomic, assign) BOOL isUsingBackgroundSession;
@property (nonatomic, strong) OSSSyncMutableDictionary * sessionDelagateManager;
@property (nonatomic, strong) OSSNetworkingConfiguration * configuration;
@property (nonatomic, strong) OSSExecutor * taskExecutor;
- (instancetype)initWithConfiguration:(OSSNetworkingConfiguration *)configuration;
- (OSSTask *)sendRequest:(OSSNetworkingRequestDelegate *)request;
@end

View File

@@ -0,0 +1,555 @@
//
// OSSNetworking.m
// oss_ios_sdk
//
// Created by zhouzhuo on 8/16/15.
// Copyright (c) 2015 aliyun.com. All rights reserved.
//
#import "OSSDefine.h"
#import "OSSNetworking.h"
#import "OSSBolts.h"
#import "OSSModel.h"
#import "OSSUtil.h"
#import "OSSLog.h"
#import "OSSXMLDictionary.h"
#import "OSSInputStreamHelper.h"
#import "OSSNetworkingRequestDelegate.h"
#import "OSSURLRequestRetryHandler.h"
#import "OSSHttpResponseParser.h"
@implementation OSSNetworkingConfiguration
@end
@implementation OSSNetworking
- (instancetype)initWithConfiguration:(OSSNetworkingConfiguration *)configuration {
if (self = [super init]) {
self.configuration = configuration;
NSURLSessionConfiguration * conf = nil;
NSOperationQueue *delegateQueue = [NSOperationQueue new];
if (configuration.enableBackgroundTransmitService) {
conf = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:self.configuration.backgroundSessionIdentifier];
} else {
conf = [NSURLSessionConfiguration defaultSessionConfiguration];
}
conf.URLCache = nil;
if (configuration.timeoutIntervalForRequest > 0) {
conf.timeoutIntervalForRequest = configuration.timeoutIntervalForRequest;
}
if (configuration.timeoutIntervalForResource > 0) {
conf.timeoutIntervalForResource = configuration.timeoutIntervalForResource;
}
if (configuration.HTTPMaximumConnectionsPerHost > 0) {
conf.HTTPMaximumConnectionsPerHost = configuration.HTTPMaximumConnectionsPerHost;
}
if (configuration.proxyHost && configuration.proxyPort) {
// Create an NSURLSessionConfiguration that uses the proxy
NSDictionary *proxyDict = @{
@"HTTPEnable" : [NSNumber numberWithInt:1],
(NSString *)kCFStreamPropertyHTTPProxyHost : configuration.proxyHost,
(NSString *)kCFStreamPropertyHTTPProxyPort : configuration.proxyPort,
@"HTTPSEnable" : [NSNumber numberWithInt:1],
(NSString *)kCFStreamPropertyHTTPSProxyHost : configuration.proxyHost,
(NSString *)kCFStreamPropertyHTTPSProxyPort : configuration.proxyPort,
};
conf.connectionProxyDictionary = proxyDict;
}
_session = [NSURLSession sessionWithConfiguration:conf
delegate:self
delegateQueue:delegateQueue];
self.isUsingBackgroundSession = configuration.enableBackgroundTransmitService;
_sessionDelagateManager = [OSSSyncMutableDictionary new];
if (configuration.enableResetRetryCount) {
[_sessionDelagateManager addObserverForResetCurrentRetryCount];
}
NSOperationQueue * operationQueue = [NSOperationQueue new];
if (configuration.maxConcurrentRequestCount > 0) {
operationQueue.maxConcurrentOperationCount = configuration.maxConcurrentRequestCount;
}
self.taskExecutor = [OSSExecutor executorWithOperationQueue: operationQueue];
}
return self;
}
- (OSSTask *)sendRequest:(OSSNetworkingRequestDelegate *)request {
OSSLogVerbose(@"send request --------");
if (self.configuration.proxyHost && self.configuration.proxyPort) {
request.isAccessViaProxy = YES;
}
/* set maximum retry */
request.retryHandler.maxRetryCount = self.configuration.maxRetryCount;
OSSTaskCompletionSource * taskCompletionSource = [OSSTaskCompletionSource taskCompletionSource];
__weak OSSNetworkingRequestDelegate *weakRequest= request;
request.completionHandler = ^(id responseObject, NSError * error) {
[weakRequest reset];
// 1.
if (error)
{
if (weakRequest.metrics) {
NSMutableDictionary *userInfo = error.userInfo ? [NSMutableDictionary dictionaryWithDictionary:error.userInfo] : [NSMutableDictionary dictionary];
[userInfo oss_setObject:weakRequest.metrics forKey:OSSNetworkTaskMetrics];
[taskCompletionSource setError:[NSError errorWithDomain:error.domain
code:error.code
userInfo:userInfo]];
} else {
[taskCompletionSource setError:error];
}
}else
{
[self checkForCrc64WithResult:responseObject
requestDelegate:weakRequest
taskCompletionSource:taskCompletionSource];
}
};
[self dataTaskWithDelegate:request];
return taskCompletionSource.task;
}
- (void)checkForCrc64WithResult:(nonnull id)response requestDelegate:(OSSNetworkingRequestDelegate *)delegate taskCompletionSource:(OSSTaskCompletionSource *)source
{
OSSResult *result = (OSSResult *)response;
BOOL hasRange = [delegate.internalRequest valueForHTTPHeaderField:@"Range"] != nil;
NSURLComponents *urlComponents = [NSURLComponents componentsWithURL:delegate.internalRequest.URL resolvingAgainstBaseURL:YES];
BOOL hasXOSSProcess = [urlComponents.query containsString:@"x-oss-process"];
BOOL enableCRC = delegate.crc64Verifiable;
// 3.crc,headerFieldsRange
// x-oss-process,crc
if (!enableCRC || hasRange || hasXOSSProcess)
{
[source setResult:response];
}
else
{
OSSLogVerbose(@"--- checkForCrc64WithResult --- ");
// crc
OSSLogVerbose(@"result.remoteCRC64ecma : %@",result.remoteCRC64ecma);
OSSLogVerbose(@"if result.localCRC64ecma : %@",result.localCRC64ecma);
if (!result.remoteCRC64ecma.oss_isNotEmpty)
{
[source setResult:response];
return;
}
// getObject crcdelegate.responseParser consumeHttpResponseBody
// upload & put
// onReceiveData blocklocalCRC64ecma
if (!result.localCRC64ecma.oss_isNotEmpty)
{
OSSLogVerbose(@"delegate.uploadingFileURL : %@",delegate.uploadingFileURL);
if (delegate.uploadingFileURL)
{
OSSInputStreamHelper *helper = [[OSSInputStreamHelper alloc] initWithURL:delegate.uploadingFileURL];
[helper syncReadBuffers];
if (helper.crc64 != 0) {
result.localCRC64ecma = [NSString stringWithFormat:@"%llu",helper.crc64];
}
}
else
{
result.localCRC64ecma = delegate.contentCRC;
}
OSSLogVerbose(@"finally result.localCRC64ecma : %@",result.localCRC64ecma);
}
// appendcrc
if ([delegate.lastCRC oss_isNotEmpty] && [result.localCRC64ecma oss_isNotEmpty])
{
uint64_t last_crc64,local_crc64;
NSScanner *scanner = [NSScanner scannerWithString:delegate.lastCRC];
[scanner scanUnsignedLongLong:&last_crc64];
scanner = [NSScanner scannerWithString:result.localCRC64ecma];
[scanner scanUnsignedLongLong:&local_crc64];
NSURLComponents *urlComponents = [NSURLComponents componentsWithURL:delegate.internalRequest.URL resolvingAgainstBaseURL:YES];
NSArray<NSString *> *params = [urlComponents.query componentsSeparatedByString:@"&"];
__block NSString *positionValue;
[params enumerateObjectsUsingBlock:^(NSString *obj, NSUInteger idx, BOOL * _Nonnull stop) {
if ([obj rangeOfString:@"position="].location == 0)
{
*stop = YES;
positionValue = [obj substringFromIndex:9];
}
}];
uint64_t position = [positionValue longLongValue];
NSString *next_append_position = [result.httpResponseHeaderFields objectForKey:@"x-oss-next-append-position"];
uint64_t length = [next_append_position longLongValue] - position;
uint64_t crc_local = [OSSUtil crc64ForCombineCRC1:last_crc64 CRC2:local_crc64 length:(size_t)length];
result.localCRC64ecma = [NSString stringWithFormat:@"%llu",crc_local];
OSSLogVerbose(@"crc_local: %llu, crc_remote: %@,last_position: %llu,nextAppendPosition: %llu,length: %llu",crc_local,result.remoteCRC64ecma,position,[next_append_position longLongValue],length);
}
//crc,crc;,
if (result.remoteCRC64ecma.oss_isNotEmpty && result.localCRC64ecma.oss_isNotEmpty)
{
if ([result.remoteCRC64ecma isEqualToString:result.localCRC64ecma])
{
[source setResult:response];
}else
{
NSString *errorMessage = [NSString stringWithFormat:@"crc validation fails(local_crc64ecma: %@,remote_crc64ecma: %@)",result.localCRC64ecma,result.remoteCRC64ecma];
NSError *crcError = [NSError errorWithDomain:OSSClientErrorDomain
code:OSSClientErrorCodeInvalidCRC
userInfo:@{OSSErrorMessageTOKEN:errorMessage}];
[source setError:crcError];
}
}
else
{
[source setResult:response];
}
}
}
- (void)dataTaskWithDelegate:(OSSNetworkingRequestDelegate *)requestDelegate {
[[[[[OSSTask taskWithResult:nil] continueWithExecutor:self.taskExecutor withSuccessBlock:^id(OSSTask *task) {
OSSLogVerbose(@"start to intercept request");
for (id<OSSRequestInterceptor> interceptor in requestDelegate.interceptors) {
task = [interceptor interceptRequestMessage:requestDelegate.allNeededMessage];
if (task.error) {
return task;
}
}
return task;
}] continueWithSuccessBlock:^id(OSSTask *task) {
return [requestDelegate buildInternalHttpRequest];
}] continueWithSuccessBlock:^id(OSSTask *task) {
NSURLSessionDataTask * sessionTask = nil;
if (self.configuration.timeoutIntervalForRequest > 0) {
requestDelegate.internalRequest.timeoutInterval = self.configuration.timeoutIntervalForRequest;
}
if (requestDelegate.uploadingData) {
[requestDelegate.internalRequest setHTTPBody:requestDelegate.uploadingData];
sessionTask = [_session dataTaskWithRequest:requestDelegate.internalRequest];
} else if (requestDelegate.uploadingFileURL) {
sessionTask = [_session uploadTaskWithRequest:requestDelegate.internalRequest fromFile:requestDelegate.uploadingFileURL];
requestDelegate.isBackgroundUploadFileTask = self.isUsingBackgroundSession;
} else { // not upload request
sessionTask = [_session dataTaskWithRequest:requestDelegate.internalRequest];
}
requestDelegate.currentSessionTask = sessionTask;
requestDelegate.httpRequestNotSuccessResponseBody = [NSMutableData new];
[self.sessionDelagateManager setObject:requestDelegate forKey:@(sessionTask.taskIdentifier)];
if (requestDelegate.isRequestCancelled) {
return [OSSTask taskWithError:[NSError errorWithDomain:OSSClientErrorDomain
code:OSSClientErrorCodeTaskCancelled
userInfo:nil]];
}
[sessionTask resume];
return task;
}] continueWithBlock:^id(OSSTask *task) {
// if error occurs before created sessionTask
if (task.error) {
requestDelegate.completionHandler(nil, task.error);
} else if (task.isFaulted) {
requestDelegate.completionHandler(nil, [NSError errorWithDomain:OSSClientErrorDomain
code:OSSClientErrorCodeExcpetionCatched
userInfo:@{OSSErrorMessageTOKEN: [NSString stringWithFormat:@"Catch exception - %@", task.exception]}]);
}
return nil;
}];
}
#pragma mark - NSURLSessionTaskDelegate Methods
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)sessionTask didCompleteWithError:(NSError *)error
{
if (error) {
OSSLogError(@"%@,error: %@", NSStringFromSelector(_cmd), error);
}
OSSNetworkingRequestDelegate * delegate = [self.sessionDelagateManager objectForKey:@(sessionTask.taskIdentifier)];
[self.sessionDelagateManager removeObjectForKey:@(sessionTask.taskIdentifier)];
NSHTTPURLResponse * httpResponse = (NSHTTPURLResponse *)sessionTask.response;
if (delegate == nil) {
OSSLogVerbose(@"delegate: %@", delegate);
/* if the background transfer service is enable, may recieve the previous task complete callback */
/* for now, we ignore it */
return ;
}
/* background upload task will not call back didRecieveResponse */
if (delegate.isBackgroundUploadFileTask) {
OSSLogVerbose(@"backgroud upload task did recieve response: %@", httpResponse);
if (httpResponse.statusCode >= 200 && httpResponse.statusCode < 300 && httpResponse.statusCode != 203) {
[delegate.responseParser consumeHttpResponse:httpResponse];
} else {
delegate.isHttpRequestNotSuccessResponse = YES;
}
}
[[[[OSSTask taskWithResult:nil] continueWithSuccessBlock:^id(OSSTask * task) {
if (!delegate.error) {
delegate.error = error;
}
if (delegate.error) {
OSSLogDebug(@"networking request completed with error: %@", error);
if ([delegate.error.domain isEqualToString:NSURLErrorDomain] && delegate.error.code == NSURLErrorCancelled) {
return [OSSTask taskWithError:[NSError errorWithDomain:OSSClientErrorDomain
code:OSSClientErrorCodeTaskCancelled
userInfo:[error userInfo]]];
} else {
NSMutableDictionary * userInfo = [NSMutableDictionary dictionaryWithDictionary:[error userInfo]];
[userInfo setObject:[NSString stringWithFormat:@"%ld", (long)error.code] forKey:@"OriginErrorCode"];
return [OSSTask taskWithError:[NSError errorWithDomain:OSSClientErrorDomain
code:OSSClientErrorCodeNetworkError
userInfo:userInfo]];
}
}
return task;
}] continueWithSuccessBlock:^id(OSSTask *task) {
if (delegate.isHttpRequestNotSuccessResponse) {
if (httpResponse.statusCode == 0) {
return [OSSTask taskWithError:[NSError errorWithDomain:OSSClientErrorDomain
code:OSSClientErrorCodeNetworkingFailWithResponseCode0
userInfo:@{OSSErrorMessageTOKEN: @"Request failed, response code 0"}]];
}
NSString * notSuccessResponseBody = [[NSString alloc] initWithData:delegate.httpRequestNotSuccessResponseBody encoding:NSUTF8StringEncoding];
OSSLogError(@"http error response: %@", notSuccessResponseBody);
NSDictionary * dict = [NSDictionary oss_dictionaryWithXMLString:notSuccessResponseBody];
return [OSSTask taskWithError:[NSError errorWithDomain:OSSServerErrorDomain
code:(-1 * httpResponse.statusCode)
userInfo:dict]];
}
return task;
}] continueWithBlock:^id(OSSTask *task) {
if (task.error) {
OSSNetworkingRetryType retryType = [delegate.retryHandler shouldRetry:delegate.currentRetryCount
requestDelegate:delegate
response:httpResponse
error:task.error];
OSSLogVerbose(@"current retry count: %u, retry type: %d", delegate.currentRetryCount, (int)retryType);
switch (retryType) {
case OSSNetworkingRetryTypeShouldNotRetry: {
delegate.completionHandler(nil, task.error);
return nil;
}
case OSSNetworkingRetryTypeShouldCorrectClockSkewAndRetry: {
/* correct clock skew */
NSString * dateStr = [[httpResponse allHeaderFields] objectForKey:@"Date"];
if ([dateStr length] > 0) {
NSDate * serverTime = [NSDate oss_dateFromString:dateStr];
NSDate * deviceTime = [NSDate date];
NSTimeInterval skewTime = [deviceTime timeIntervalSinceDate:serverTime];
[NSDate oss_setClockSkew:skewTime];
} else if (!error) {
// The response header does not have the 'Date' field.
// This should not happen.
OSSLogError(@"Date header does not exist, unable to fix the clock skew");
}
break;
}
default:
break;
}
/* now, should retry */
NSTimeInterval suspendTime = [delegate.retryHandler timeIntervalForRetry:delegate.currentRetryCount retryType:retryType];
delegate.currentRetryCount++;
[NSThread sleepForTimeInterval:suspendTime];
if(delegate.retryCallback){
delegate.retryCallback();
}
/* retry recursively */
[delegate reset];
[self dataTaskWithDelegate:delegate];
} else {
OSSResult *result = [delegate.responseParser constructResultObject];
result.metrics = delegate.metrics;
delegate.completionHandler(result, nil);
}
return nil;
}];
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend
{
OSSNetworkingRequestDelegate * delegate = [self.sessionDelagateManager objectForKey:@(task.taskIdentifier)];
if (delegate.uploadProgress)
{
delegate.uploadProgress(bytesSent, totalBytesSent, totalBytesExpectedToSend);
}
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * __nullable credential))completionHandler
{
if (!challenge) {
return;
}
NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
NSURLCredential *credential = nil;
/*
* Gets the host name
*/
NSString * host = [[task.currentRequest allHTTPHeaderFields] objectForKey:@"Host"];
if (!host) {
host = task.currentRequest.URL.host;
}
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
if ([self evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:host]) {
disposition = NSURLSessionAuthChallengeUseCredential;
credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
}
} else {
disposition = NSURLSessionAuthChallengePerformDefaultHandling;
}
// Uses the default evaluation for other challenges.
completionHandler(disposition,credential);
}
- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session
{
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
willPerformHTTPRedirection:(NSHTTPURLResponse *)response
newRequest:(NSURLRequest *)request
completionHandler:(void (^)(NSURLRequest * _Nullable))completionHandler {
if (self.configuration.enableFollowRedirects) {
completionHandler(request);
} else {
completionHandler(nil);
}
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics {
if (self.configuration.enableNetworkMetricInfo) {
OSSNetworkingRequestDelegate *delegate = [self.sessionDelagateManager objectForKey:@(task.taskIdentifier)];
delegate.metrics = metrics;
OSSLogDebug(@"%@", metrics);
}
}
#pragma mark - NSURLSessionDataDelegate Methods
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler
{
/* background upload task will not call back didRecieveResponse */
OSSLogVerbose(@"%@,response: %@", NSStringFromSelector(_cmd), response);
OSSNetworkingRequestDelegate * delegate = [self.sessionDelagateManager objectForKey:@(dataTask.taskIdentifier)];
NSHTTPURLResponse * httpResponse = (NSHTTPURLResponse *)response;
if (httpResponse.statusCode >= 200 && httpResponse.statusCode < 300 && httpResponse.statusCode != 203) {
[delegate.responseParser consumeHttpResponse:httpResponse];
} else {
delegate.isHttpRequestNotSuccessResponse = YES;
}
completionHandler(NSURLSessionResponseAllow);
}
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
{
OSSNetworkingRequestDelegate * delegate = [self.sessionDelagateManager objectForKey:@(dataTask.taskIdentifier)];
/* background upload task will not call back didRecieveResponse.
so if we recieve response data after background uploading file,
we consider it as error response message since a successful uploading request will not response any data */
if (delegate.isBackgroundUploadFileTask)
{
//statuscode
NSHTTPURLResponse * httpResponse = (NSHTTPURLResponse *)dataTask.response;
if (httpResponse.statusCode >= 200 && httpResponse.statusCode < 300 && httpResponse.statusCode != 203) {
[delegate.responseParser consumeHttpResponse:httpResponse];
delegate.isHttpRequestNotSuccessResponse = NO;
}else
{
delegate.isHttpRequestNotSuccessResponse = YES;
}
}
if (delegate.isHttpRequestNotSuccessResponse) {
[delegate.httpRequestNotSuccessResponseBody appendData:data];
}
else {
if (delegate.onRecieveData) {
delegate.onRecieveData(data);
} else {
OSSTask * consumeTask = [delegate.responseParser consumeHttpResponseBody:data];
if (consumeTask.error) {
OSSLogError(@"consume data error: %@", consumeTask.error);
delegate.error = consumeTask.error;
[dataTask cancel];
}
}
}
if (!delegate.isHttpRequestNotSuccessResponse && delegate.downloadProgress) {
int64_t bytesWritten = [data length];
delegate.payloadTotalBytesWritten += bytesWritten;
int64_t totalBytesExpectedToWrite = dataTask.response.expectedContentLength;
delegate.downloadProgress(bytesWritten, delegate.payloadTotalBytesWritten, totalBytesExpectedToWrite);
}
}
#pragma mark - Private Methods
- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust forDomain:(NSString *)domain {
/*
* Creates the policies for certificate verification.
*/
NSMutableArray *policies = [NSMutableArray array];
if (domain) {
[policies addObject:(__bridge_transfer id)SecPolicyCreateSSL(true, (__bridge CFStringRef)domain)];
} else {
[policies addObject:(__bridge_transfer id)SecPolicyCreateBasicX509()];
}
/*
* Sets the policies to server's certificate
*/
SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef)policies);
/*
* Evaulates if the current serverTrust is trustable.
* It's officially suggested that the serverTrust could be passed when result = kSecTrustResultUnspecified or kSecTrustResultProceed.
* For more information checks out https://developer.apple.com/library/ios/technotes/tn2232/_index.html
* For detail information about SecTrustResultType, checks out SecTrust.h
*/
SecTrustResultType result;
SecTrustEvaluate(serverTrust, &result);
return (result == kSecTrustResultUnspecified || result == kSecTrustResultProceed);
}
@end

View File

@@ -0,0 +1,81 @@
//
// OSSNetworkingRequestDelegate.h
// AliyunOSSSDK
//
// Created by huaixu on 2018/1/22.
// Copyright © 2018年 aliyun. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "OSSConstants.h"
#import "OSSTask.h"
@class OSSAllRequestNeededMessage;
@class OSSURLRequestRetryHandler;
@class OSSHttpResponseParser;
/**
The proxy object class for each OSS request.
*/
@interface OSSNetworkingRequestDelegate : NSObject
@property (nonatomic, strong) NSMutableArray * interceptors;
@property (nonatomic, strong) NSMutableURLRequest *internalRequest;
@property (nonatomic, assign) OSSOperationType operType;
@property (nonatomic, assign) BOOL isAccessViaProxy;
@property (nonatomic, assign) BOOL isRequestCancelled;
@property (nonatomic, strong) OSSAllRequestNeededMessage *allNeededMessage;
@property (nonatomic, strong) OSSURLRequestRetryHandler *retryHandler;
@property (nonatomic, strong) OSSHttpResponseParser *responseParser;
@property (nonatomic, strong) NSData * uploadingData;
@property (nonatomic, strong) NSURL * uploadingFileURL;
@property (nonatomic, assign) int64_t payloadTotalBytesWritten;
@property (nonatomic, assign) BOOL isBackgroundUploadFileTask;
@property (nonatomic, assign) BOOL isHttpdnsEnable;
@property (nonatomic, assign) BOOL isPathStyleAccessEnable;
@property (nonatomic, assign) BOOL isCustomPathPrefixEnable;
@property (nonatomic, copy) NSArray * cnameExcludeList;
@property (nonatomic, assign) uint32_t currentRetryCount;
@property (nonatomic, strong) NSError * error;
@property (nonatomic, assign) BOOL isHttpRequestNotSuccessResponse;
@property (nonatomic, strong) NSMutableData *httpRequestNotSuccessResponseBody;
@property (atomic, strong) NSURLSessionDataTask *currentSessionTask;
@property (nonatomic, strong) NSURLSessionTaskMetrics *metrics API_AVAILABLE(macos(10.12), ios(10.0));
@property (nonatomic, copy) OSSNetworkingUploadProgressBlock uploadProgress;
@property (nonatomic, copy) OSSNetworkingDownloadProgressBlock downloadProgress;
@property (nonatomic, copy) OSSNetworkingRetryBlock retryCallback;
@property (nonatomic, copy) OSSNetworkingCompletionHandlerBlock completionHandler;
@property (nonatomic, copy) OSSNetworkingOnRecieveDataBlock onRecieveData;
/**
* when put object to server,client caculate crc64 code and assigns it to
* this property.
*/
@property (nonatomic, copy) NSString *contentCRC;
/** last crc64 code */
@property (nonatomic, copy) NSString *lastCRC;
/**
* determine whether to verify crc64 code
*/
@property (nonatomic, assign) BOOL crc64Verifiable;
- (OSSTask *)buildInternalHttpRequest;
- (void)reset;
- (void)cancel;
@end

View File

@@ -0,0 +1,186 @@
//
// OSSNetworkingRequestDelegate.m
// AliyunOSSSDK
//
// Created by huaixu on 2018/1/22.
// Copyright © 2018 aliyun. All rights reserved.
//
#import "OSSNetworkingRequestDelegate.h"
#import "OSSAllRequestNeededMessage.h"
#import "OSSURLRequestRetryHandler.h"
#import "OSSHttpResponseParser.h"
#import "OSSDefine.h"
#import "OSSUtil.h"
#import "OSSLog.h"
#import "OSSIPv6Adapter.h"
@implementation OSSNetworkingRequestDelegate
- (instancetype)init {
if (self = [super init]) {
self.retryHandler = [OSSURLRequestRetryHandler defaultRetryHandler];
self.interceptors = [[NSMutableArray alloc] init];
self.isHttpdnsEnable = YES;
}
return self;
}
- (void)reset {
self.isHttpRequestNotSuccessResponse = NO;
self.error = nil;
self.payloadTotalBytesWritten = 0;
self.isRequestCancelled = NO;
[self.responseParser reset];
}
- (void)cancel {
self.isRequestCancelled = YES;
if (self.currentSessionTask) {
OSSLogDebug(@"this task is cancelled now!");
[self.currentSessionTask cancel];
}
}
- (OSSTask *)validateRequestParams {
NSString * errorMessage = nil;
if ((self.operType == OSSOperationTypeAppendObject || self.operType == OSSOperationTypePutObject || self.operType == OSSOperationTypeUploadPart)
&& !self.uploadingData && !self.uploadingFileURL) {
errorMessage = @"This operation need data or file to upload but none is set";
}
if (self.uploadingFileURL && ![[NSFileManager defaultManager] fileExistsAtPath:[self.uploadingFileURL path]]) {
errorMessage = @"File doesn't exist";
}
if (errorMessage) {
return [OSSTask taskWithError:[NSError errorWithDomain:OSSClientErrorDomain
code:OSSClientErrorCodeInvalidArgument
userInfo:@{OSSErrorMessageTOKEN: errorMessage}]];
} else {
return [self.allNeededMessage validateRequestParamsInOperationType:self.operType];
}
}
- (OSSTask *)buildInternalHttpRequest {
OSSTask * validateParam = [self validateRequestParams];
if (validateParam.error) {
return validateParam;
}
#define URLENCODE(a) [OSSUtil encodeURL:(a)]
OSSLogDebug(@"start to build request")
// build base url string
NSString *bucketName = self.allNeededMessage.bucketName;
NSString *objectKey = self.allNeededMessage.objectKey;
NSString *urlString = self.allNeededMessage.endpoint;
NSURLComponents *urlComponents = [[NSURLComponents alloc] initWithString:urlString];
NSString *headerHost = nil;
BOOL isPathStyle = NO;
NSURLComponents *temComs = [NSURLComponents new];
temComs.scheme = urlComponents.scheme;
temComs.host = urlComponents.host;
temComs.port = urlComponents.port;
if (self.isCustomPathPrefixEnable) {
temComs.path = urlComponents.path;
}
if ([self.allNeededMessage.bucketName oss_isNotEmpty]) {
OSSIPv6Adapter *ipAdapter = [OSSIPv6Adapter getInstance];
if ([OSSUtil isOssOriginBucketHost:temComs.host]) {
// eg. insert bucket to the begining of host.
temComs.host = [NSString stringWithFormat:@"%@.%@", self.allNeededMessage.bucketName, temComs.host];
headerHost = temComs.host;
if ([temComs.scheme.lowercaseString isEqualToString:@"http"] && self.isHttpdnsEnable) {
NSString *dnsResult = [OSSUtil getIpByHost: temComs.host];
temComs.host = dnsResult;
}
} else if (self.allNeededMessage.isHostInCnameExcludeList) {
if (self.isPathStyleAccessEnable) {
isPathStyle = YES;
} else {
temComs.host = [NSString stringWithFormat:@"%@.%@", self.allNeededMessage.bucketName, temComs.host];
}
} else if ([ipAdapter isIPv4Address:temComs.host] || [ipAdapter isIPv6Address:temComs.host]) {
isPathStyle = YES;
}
}
urlString = temComs.string;
if (isPathStyle) {
urlString = [NSString stringWithFormat:@"%@/%@", urlString, bucketName];
}
// join object name
if ([self.allNeededMessage.objectKey oss_isNotEmpty]) {
urlString = [urlString oss_stringByAppendingPathComponentForURL:URLENCODE(self.allNeededMessage.objectKey)];
}
// join query string
if (self.allNeededMessage.params) {
NSMutableArray * querys = [[NSMutableArray alloc] init];
for (NSString * key in [self.allNeededMessage.params allKeys]) {
NSString * value = [self.allNeededMessage.params objectForKey:key];
if (value) {
if ([value isEqualToString:@""]) {
[querys addObject:URLENCODE(key)];
} else {
[querys addObject:[NSString stringWithFormat:@"%@=%@", URLENCODE(key), URLENCODE(value)]];
}
}
}
if (querys && [querys count]) {
NSString * queryString = [querys componentsJoinedByString:@"&"];
urlString = [NSString stringWithFormat:@"%@?%@", urlString, queryString];
}
}
OSSLogDebug(@"built full url: %@", urlString)
// generate internal request For NSURLSession
self.internalRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlString]];
// set http method of request
if (self.allNeededMessage.httpMethod) {
[self.internalRequest setHTTPMethod:self.allNeededMessage.httpMethod];
}
// set host of header fields
if ([headerHost oss_isNotEmpty]) {
[self.internalRequest setValue:headerHost forHTTPHeaderField:@"Host"];
}
if (self.allNeededMessage.contentType) {
[self.internalRequest setValue:self.allNeededMessage.contentType forHTTPHeaderField:@"Content-Type"];
}
if (self.allNeededMessage.contentMd5) {
[self.internalRequest setValue:self.allNeededMessage.contentMd5 forHTTPHeaderField:@"Content-MD5"];
}
if (self.allNeededMessage.date) {
[self.internalRequest setValue:self.allNeededMessage.date forHTTPHeaderField:@"Date"];
}
if (self.allNeededMessage.range) {
[self.internalRequest setValue:self.allNeededMessage.range forHTTPHeaderField:@"Range"];
}
if (self.allNeededMessage.contentSHA1) {
[self.internalRequest setValue:_allNeededMessage.contentSHA1 forHTTPHeaderField:@"x-oss-hash-sha1"];
}
if (self.allNeededMessage.headerParams) {
for (NSString * key in [self.allNeededMessage.headerParams allKeys]) {
[self.internalRequest setValue:[self.allNeededMessage.headerParams objectForKey:key] forHTTPHeaderField:key];
}
}
OSSLogVerbose(@"buidlInternalHttpRequest -\nmethod: %@\nurl: %@\nheader: %@", self.internalRequest.HTTPMethod,
self.internalRequest.URL, self.internalRequest.allHTTPHeaderFields)
#undef URLENCODE//(a)
return [OSSTask taskWithResult:nil];
}
@end

View File

@@ -0,0 +1,27 @@
//
// OSSPutObjectTaggingRequest.h
// AliyunOSSSDK
//
// Created by ws on 2021/5/25.
// Copyright © 2021 aliyun. All rights reserved.
//
#import "OSSRequest.h"
NS_ASSUME_NONNULL_BEGIN
@interface OSSPutObjectTaggingRequest : OSSRequest
/* bucket name */
@property (nonatomic, copy) NSString *bucketName;
/* object name */
@property (nonatomic, copy) NSString *objectKey;
@property (nonatomic, copy) NSDictionary *tags;
- (NSDictionary *)entityToDictionary;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,29 @@
//
// OSSPutObjectTaggingRequest.m
// AliyunOSSSDK
//
// Created by ws on 2021/5/25.
// Copyright © 2021 aliyun. All rights reserved.
//
#import "OSSPutObjectTaggingRequest.h"
@implementation OSSPutObjectTaggingRequest
- (NSDictionary *)requestParams {
return @{@"tagging": @""};
}
- (NSDictionary *)entityToDictionary {
NSMutableArray *tags = [NSMutableArray array];
for (NSString *key in [self.tags allKeys]) {
NSString *value = self.tags[key];
NSDictionary *tag = @{@"Tag": @{@"Key":key,
@"Value": value}};
[tags addObject:tag];
}
NSDictionary *entity = @{@"Tagging": @{@"TagSet": tags}};
return entity;
}
@end

View File

@@ -0,0 +1,17 @@
//
// OSSPutObjectTaggingResult.h
// AliyunOSSSDK
//
// Created by ws on 2021/5/25.
// Copyright © 2021 aliyun. All rights reserved.
//
#import "OSSResult.h"
NS_ASSUME_NONNULL_BEGIN
@interface OSSPutObjectTaggingResult : OSSResult
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,13 @@
//
// OSSPutObjectTaggingResult.m
// AliyunOSSSDK
//
// Created by ws on 2021/5/25.
// Copyright © 2021 aliyun. All rights reserved.
//
#import "OSSPutObjectTaggingResult.h"
@implementation OSSPutObjectTaggingResult
@end

View File

@@ -0,0 +1,25 @@
//
// OSSPutSymlinkRequest.h
// AliyunOSSSDK
//
// Created by huaixu on 2018/8/1.
// Copyright © 2018年 aliyun. All rights reserved.
//
#import "OSSRequest.h"
@interface OSSPutSymlinkRequest : OSSRequest
/* bucket name */
@property (nonatomic, copy) NSString *bucketName;
/* object name */
@property (nonatomic, copy) NSString *objectKey;
/* target object name */
@property (nonatomic, copy) NSString *targetObjectName;
/* meta info in request header fields */
@property (nonatomic, copy) NSDictionary *objectMeta;
@end

View File

@@ -0,0 +1,17 @@
//
// OSSPutSymlinkRequest.m
// AliyunOSSSDK
//
// Created by huaixu on 2018/8/1.
// Copyright © 2018 aliyun. All rights reserved.
//
#import "OSSPutSymlinkRequest.h"
@implementation OSSPutSymlinkRequest
- (NSDictionary *)requestParams {
return @{@"symlink": @""};
}
@end

View File

@@ -0,0 +1,13 @@
//
// OSSPutSymlinkResult.h
// AliyunOSSSDK
//
// Created by huaixu on 2018/8/1.
// Copyright © 2018年 aliyun. All rights reserved.
//
#import "OSSResult.h"
@interface OSSPutSymlinkResult : OSSResult
@end

View File

@@ -0,0 +1,13 @@
//
// OSSPutSymlinkResult.m
// AliyunOSSSDK
//
// Created by huaixu on 2018/8/1.
// Copyright © 2018 aliyun. All rights reserved.
//
#import "OSSPutSymlinkResult.h"
@implementation OSSPutSymlinkResult
@end

View File

@@ -0,0 +1,41 @@
//
// OSSRequest.h
// AliyunOSSSDK
//
// Created by huaixu on 2018/1/22.
// Copyright © 2018年 aliyun. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "OSSConstants.h"
/**
The base class of request to OSS.
*/
@interface OSSRequest : NSObject
/**
Flag of requiring authentication. It's per each request.
*/
@property (nonatomic, assign) BOOL isAuthenticationRequired;
/**
the flag of request canceled.
*/
@property (atomic, assign) BOOL isCancelled;
/**
the flag of verification about crc64
*/
@property (nonatomic, assign) OSSRequestCRCFlag crcFlag;
/**
Cancels the request
*/
- (void)cancel;
/**
Gets the query parameters' dictionary according to the properties.
*/
- (NSDictionary *)requestParams;
@end

View File

@@ -0,0 +1,41 @@
//
// OSSRequest.m
// AliyunOSSSDK
//
// Created by huaixu on 2018/1/22.
// Copyright © 2018 aliyun. All rights reserved.
//
#import "OSSRequest.h"
#import "OSSNetworkingRequestDelegate.h"
@interface OSSRequest ()
@property (nonatomic, strong) OSSNetworkingRequestDelegate *requestDelegate;
@end
@implementation OSSRequest
- (instancetype)init {
if (self = [super init]) {
self.requestDelegate = [OSSNetworkingRequestDelegate new];
self.isAuthenticationRequired = YES;
}
return self;
}
- (void)cancel {
self.isCancelled = YES;
if (self.requestDelegate) {
[self.requestDelegate cancel];
}
}
- (NSDictionary *)requestParams {
return nil;
}
@end

View File

@@ -0,0 +1,17 @@
//
// OSSRestoreObjectRequest.h
// AliyunOSSSDK
//
// Created by huaixu on 2018/8/1.
// Copyright © 2018年 aliyun. All rights reserved.
//
#import "OSSRequest.h"
@interface OSSRestoreObjectRequest : OSSRequest
@property (nonatomic, copy) NSString *bucketName;
@property (nonatomic, copy) NSString *objectKey;
@end

View File

@@ -0,0 +1,17 @@
//
// OSSRestoreObjectRequest.m
// AliyunOSSSDK
//
// Created by huaixu on 2018/8/1.
// Copyright © 2018 aliyun. All rights reserved.
//
#import "OSSRestoreObjectRequest.h"
@implementation OSSRestoreObjectRequest
- (NSDictionary *)requestParams {
return @{@"restore": @""};
}
@end

View File

@@ -0,0 +1,13 @@
//
// OSSRestoreObjectResult.h
// AliyunOSSSDK
//
// Created by huaixu on 2018/8/1.
// Copyright © 2018年 aliyun. All rights reserved.
//
#import "OSSResult.h"
@interface OSSRestoreObjectResult : OSSResult
@end

View File

@@ -0,0 +1,13 @@
//
// OSSRestoreObjectResult.m
// AliyunOSSSDK
//
// Created by huaixu on 2018/8/1.
// Copyright © 2018 aliyun. All rights reserved.
//
#import "OSSRestoreObjectResult.h"
@implementation OSSRestoreObjectResult
@end

View File

@@ -0,0 +1,45 @@
//
// OSSResult.h
// AliyunOSSSDK
//
// Created by huaixu on 2018/1/26.
// Copyright © 2018年 aliyun. All rights reserved.
//
#import <Foundation/Foundation.h>
/**
The base class of result from OSS.
*/
@interface OSSResult : NSObject
/**
The http response code.
*/
@property (nonatomic, assign) NSInteger httpResponseCode;
/**
The http headers, in the form of key value dictionary.
*/
@property (nonatomic, strong) NSDictionary * httpResponseHeaderFields;
/**
The request Id. It's the value of header x-oss-request-id, which is created from OSS server.
It's a unique Id represents this request. This is used for troubleshooting when you contact OSS support.
*/
@property (nonatomic, strong) NSString * requestId;
/**
It's the value of header x-oss-hash-crc64ecma, which is created from OSS server.
*/
@property (nonatomic, copy) NSString *remoteCRC64ecma;
/**
It's the value of local Data.
*/
@property (nonatomic, copy) NSString *localCRC64ecma;
/// statistics information for the task.
@property (nonatomic, strong) NSURLSessionTaskMetrics *metrics API_AVAILABLE(macos(10.12), ios(10.0));
@end

View File

@@ -0,0 +1,18 @@
//
// OSSResult.m
// AliyunOSSSDK
//
// Created by huaixu on 2018/1/26.
// Copyright © 2018 aliyun. All rights reserved.
//
#import "OSSResult.h"
@implementation OSSResult
- (NSString *)description
{
return [NSString stringWithFormat:@"OSSResult<%p> : {httpResponseCode: %ld, requestId: %@, httpResponseHeaderFields: %@, local_crc64ecma: %@}",self,(long)self.httpResponseCode,self.requestId,self.httpResponseHeaderFields,self.localCRC64ecma];
}
@end

View File

@@ -0,0 +1,46 @@
//
// OSSService.h
// oss_ios_sdk
//
// Created by zhouzhuo on 8/20/15.
// Copyright (c) 2015 aliyun.com. All rights reserved.
//
#import <Foundation/Foundation.h>
#define OSS_IOS_SDK_VERSION OSSSDKVersion
#import "OSSDefine.h"
#import "OSSConstants.h"
#import "OSSNetworking.h"
#import "OSSNetworkingRequestDelegate.h"
#import "OSSAllRequestNeededMessage.h"
#import "OSSURLRequestRetryHandler.h"
#import "OSSHttpResponseParser.h"
#import "OSSRequest.h"
#import "OSSGetObjectACLRequest.h"
#import "OSSGetObjectACLResult.h"
#import "OSSDeleteMultipleObjectsRequest.h"
#import "OSSDeleteMultipleObjectsResult.h"
#import "OSSGetBucketInfoRequest.h"
#import "OSSGetBucketInfoResult.h"
#import "OSSPutSymlinkRequest.h"
#import "OSSPutSymlinkResult.h"
#import "OSSGetSymlinkRequest.h"
#import "OSSGetSymlinkResult.h"
#import "OSSRestoreObjectRequest.h"
#import "OSSRestoreObjectResult.h"
#import "OSSGetObjectTaggingRequest.h"
#import "OSSGetObjectTaggingResult.h"
#import "OSSPutObjectTaggingRequest.h"
#import "OSSPutObjectTaggingResult.h"
#import "OSSDeleteObjectTaggingRequest.h"
#import "OSSDeleteObjectTaggingResult.h"
#import "OSSClient.h"
#import "OSSModel.h"
#import "OSSUtil.h"
#import "OSSLog.h"
#import "OSSBolts.h"

View File

@@ -0,0 +1,26 @@
/*
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
#import "OSSCancellationToken.h"
#import "OSSCancellationTokenRegistration.h"
#import "OSSCancellationTokenSource.h"
#import "OSSExecutor.h"
#import "OSSTask.h"
#import "OSSTaskCompletionSource.h"
NS_ASSUME_NONNULL_BEGIN
/**
A string containing the version of the Bolts Framework used by the current application.
*/
extern NSString *const OSSBoltsFrameworkVersionString;
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,17 @@
/*
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
#import "OSSBolts.h"
NS_ASSUME_NONNULL_BEGIN
NSString *const OSSBoltsFrameworkVersionString = @"1.7.0";
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,42 @@
/*
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
#import <Foundation/Foundation.h>
#import "OSSCancellationTokenRegistration.h"
NS_ASSUME_NONNULL_BEGIN
/*!
A block that will be called when a token is cancelled.
*/
typedef void(^OSSCancellationBlock)(void);
/*!
The consumer view of a CancellationToken.
Propagates notification that operations should be canceled.
A OSSCancellationToken has methods to inspect whether the token has been cancelled.
*/
@interface OSSCancellationToken : NSObject
/*!
Whether cancellation has been requested for this token source.
*/
@property (nonatomic, assign, readonly, getter=isCancellationRequested) BOOL cancellationRequested;
/*!
Register a block to be notified when the token is cancelled.
If the token is already cancelled the delegate will be notified immediately.
*/
- (OSSCancellationTokenRegistration *)registerCancellationObserverWithBlock:(OSSCancellationBlock)block;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,144 @@
/*
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
#import "OSSCancellationToken.h"
#import "OSSCancellationTokenRegistration.h"
NS_ASSUME_NONNULL_BEGIN
@interface OSSCancellationToken ()
@property (nullable, nonatomic, strong) NSMutableArray *registrations;
@property (nonatomic, strong) NSObject *lock;
@property (nonatomic) BOOL disposed;
@end
@interface OSSCancellationTokenRegistration (OSSCancellationToken)
+ (instancetype)registrationWithToken:(OSSCancellationToken *)token delegate:(OSSCancellationBlock)delegate;
- (void)notifyDelegate;
@end
@implementation OSSCancellationToken
@synthesize cancellationRequested = _cancellationRequested;
#pragma mark - Initializer
- (instancetype)init {
self = [super init];
if (!self) return self;
_registrations = [NSMutableArray array];
_lock = [NSObject new];
return self;
}
#pragma mark - Custom Setters/Getters
- (BOOL)isCancellationRequested {
@synchronized(self.lock) {
[self throwIfDisposed];
return _cancellationRequested;
}
}
- (void)cancel {
NSArray *registrations;
@synchronized(self.lock) {
[self throwIfDisposed];
if (_cancellationRequested) {
return;
}
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(cancelPrivate) object:nil];
_cancellationRequested = YES;
registrations = [self.registrations copy];
}
[self notifyCancellation:registrations];
}
- (void)notifyCancellation:(NSArray *)registrations {
for (OSSCancellationTokenRegistration *registration in registrations) {
[registration notifyDelegate];
}
}
- (OSSCancellationTokenRegistration *)registerCancellationObserverWithBlock:(OSSCancellationBlock)block {
@synchronized(self.lock) {
OSSCancellationTokenRegistration *registration = [OSSCancellationTokenRegistration registrationWithToken:self delegate:[block copy]];
[self.registrations addObject:registration];
return registration;
}
}
- (void)unregisterRegistration:(OSSCancellationTokenRegistration *)registration {
@synchronized(self.lock) {
[self throwIfDisposed];
[self.registrations removeObject:registration];
}
}
// Delay on a non-public method to prevent interference with a user calling performSelector or
// cancelPreviousPerformRequestsWithTarget on the public method
- (void)cancelPrivate {
[self cancel];
}
- (void)cancelAfterDelay:(int)millis {
[self throwIfDisposed];
if (millis < -1) {
[NSException raise:NSInvalidArgumentException format:@"Delay must be >= -1"];
}
if (millis == 0) {
[self cancel];
return;
}
@synchronized(self.lock) {
[self throwIfDisposed];
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(cancelPrivate) object:nil];
if (self.cancellationRequested) {
return;
}
if (millis != -1) {
double delay = (double)millis / 1000;
[self performSelector:@selector(cancelPrivate) withObject:nil afterDelay:delay];
}
}
}
- (void)dispose {
@synchronized(self.lock) {
if (self.disposed) {
return;
}
[self.registrations makeObjectsPerformSelector:@selector(dispose)];
self.registrations = nil;
self.disposed = YES;
}
}
- (void)throwIfDisposed {
if (self.disposed) {
[NSException raise:NSInternalInconsistencyException format:@"Object already disposed"];
}
}
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,29 @@
/*
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/*!
Represents the registration of a cancellation observer with a cancellation token.
Can be used to unregister the observer at a later time.
*/
@interface OSSCancellationTokenRegistration : NSObject
/*!
Removes the cancellation observer registered with the token
and releases all resources associated with this registration.
*/
- (void)dispose;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,79 @@
/*
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
#import "OSSCancellationTokenRegistration.h"
#import "OSSCancellationToken.h"
NS_ASSUME_NONNULL_BEGIN
@interface OSSCancellationTokenRegistration ()
@property (nonatomic, weak) OSSCancellationToken *token;
@property (nullable, nonatomic, strong) OSSCancellationBlock cancellationObserverBlock;
@property (nonatomic, strong) NSObject *lock;
@property (nonatomic) BOOL disposed;
@end
@interface OSSCancellationToken (OSSCancellationTokenRegistration)
- (void)unregisterRegistration:(OSSCancellationTokenRegistration *)registration;
@end
@implementation OSSCancellationTokenRegistration
+ (instancetype)registrationWithToken:(OSSCancellationToken *)token delegate:(OSSCancellationBlock)delegate {
OSSCancellationTokenRegistration *registration = [OSSCancellationTokenRegistration new];
registration.token = token;
registration.cancellationObserverBlock = delegate;
return registration;
}
- (instancetype)init {
self = [super init];
if (!self) return self;
_lock = [NSObject new];
return self;
}
- (void)dispose {
@synchronized(self.lock) {
if (self.disposed) {
return;
}
self.disposed = YES;
}
OSSCancellationToken *token = self.token;
if (token != nil) {
[token unregisterRegistration:self];
self.token = nil;
}
self.cancellationObserverBlock = nil;
}
- (void)notifyDelegate {
@synchronized(self.lock) {
[self throwIfDisposed];
self.cancellationObserverBlock();
}
}
- (void)throwIfDisposed {
NSAssert(!self.disposed, @"Object already disposed");
}
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,60 @@
/*
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@class OSSCancellationToken;
/*!
OSSCancellationTokenSource represents the producer side of a CancellationToken.
Signals to a CancellationToken that it should be canceled.
It is a cancellation token that also has methods
for changing the state of a token by cancelling it.
*/
@interface OSSCancellationTokenSource : NSObject
/*!
Creates a new cancellation token source.
*/
+ (instancetype)cancellationTokenSource;
/*!
The cancellation token associated with this CancellationTokenSource.
*/
@property (nonatomic, strong, readonly) OSSCancellationToken *token;
/*!
Whether cancellation has been requested for this token source.
*/
@property (nonatomic, assign, readonly, getter=isCancellationRequested) BOOL cancellationRequested;
/*!
Cancels the token if it has not already been cancelled.
*/
- (void)cancel;
/*!
Schedules a cancel operation on this CancellationTokenSource after the specified number of milliseconds.
@param millis The number of milliseconds to wait before completing the returned task.
If delay is `0` the cancel is executed immediately. If delay is `-1` any scheduled cancellation is stopped.
*/
- (void)cancelAfterDelay:(int)millis;
/*!
Releases all resources associated with this token source,
including disposing of all registrations.
*/
- (void)dispose;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,64 @@
/*
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
#import "OSSCancellationTokenSource.h"
#import "OSSCancellationToken.h"
NS_ASSUME_NONNULL_BEGIN
@interface OSSCancellationToken (OSSCancellationTokenSource)
- (void)cancel;
- (void)cancelAfterDelay:(int)millis;
- (void)dispose;
- (void)throwIfDisposed;
@end
@implementation OSSCancellationTokenSource
#pragma mark - Initializer
- (instancetype)init {
self = [super init];
if (!self) return self;
_token = [OSSCancellationToken new];
return self;
}
+ (instancetype)cancellationTokenSource {
return [OSSCancellationTokenSource new];
}
#pragma mark - Custom Setters/Getters
- (BOOL)isCancellationRequested {
return _token.isCancellationRequested;
}
- (void)cancel {
[_token cancel];
}
- (void)cancelAfterDelay:(int)millis {
[_token cancelAfterDelay:millis];
}
- (void)dispose {
[_token dispose];
}
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,62 @@
/*
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/*!
An object that can run a given block.
*/
@interface OSSExecutor : NSObject
/*!
Returns a default executor, which runs continuations immediately until the call stack gets too
deep, then dispatches to a new GCD queue.
*/
+ (instancetype)defaultExecutor;
/*!
Returns an executor that runs continuations on the thread where the previous task was completed.
*/
+ (instancetype)immediateExecutor;
/*!
Returns an executor that runs continuations on the main thread.
*/
+ (instancetype)mainThreadExecutor;
/*!
Returns a new executor that uses the given block to execute continuations.
@param block The block to use.
*/
+ (instancetype)executorWithBlock:(void(^)(void(^block)(void)))block;
/*!
Returns a new executor that runs continuations on the given queue.
@param queue The instance of `dispatch_queue_t` to dispatch all continuations onto.
*/
+ (instancetype)executorWithDispatchQueue:(dispatch_queue_t)queue;
/*!
Returns a new executor that runs continuations on the given queue.
@param queue The instance of `NSOperationQueue` to run all continuations on.
*/
+ (instancetype)executorWithOperationQueue:(NSOperationQueue *)queue;
/*!
Runs the given block using this executor's particular strategy.
@param block The block to execute.
*/
- (void)execute:(void(^)(void))block;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,136 @@
/*
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
#import "OSSExecutor.h"
#import <pthread.h>
NS_ASSUME_NONNULL_BEGIN
/*!
Get the remaining stack-size of the current thread.
@param totalSize The total stack size of the current thread.
@return The remaining size, in bytes, available to the current thread.
@note This function cannot be inlined, as otherwise the internal implementation could fail to report the proper
remaining stack space.
*/
__attribute__((noinline)) static size_t remaining_stack_size(size_t *restrict totalSize) {
pthread_t currentThread = pthread_self();
// NOTE: We must store stack pointers as uint8_t so that the pointer math is well-defined
uint8_t *endStack = pthread_get_stackaddr_np(currentThread);
*totalSize = pthread_get_stacksize_np(currentThread);
// NOTE: If the function is inlined, this value could be incorrect
uint8_t *frameAddr = __builtin_frame_address(0);
return (*totalSize) - (endStack - frameAddr);
}
@interface OSSExecutor ()
@property (nonatomic, copy) void(^block)(void(^block)(void));
@end
@implementation OSSExecutor
#pragma mark - Executor methods
+ (instancetype)defaultExecutor {
static OSSExecutor *defaultExecutor = NULL;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
defaultExecutor = [self executorWithBlock:^void(void(^block)(void)) {
// We prefer to run everything possible immediately, so that there is callstack information
// when debugging. However, we don't want the stack to get too deep, so if the remaining stack space
// is less than 10% of the total space, we dispatch to another GCD queue.
size_t totalStackSize = 0;
size_t remainingStackSize = remaining_stack_size(&totalStackSize);
if (remainingStackSize < (totalStackSize / 10)) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), block);
} else {
@autoreleasepool {
block();
}
}
}];
});
return defaultExecutor;
}
+ (instancetype)immediateExecutor {
static OSSExecutor *immediateExecutor = NULL;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
immediateExecutor = [self executorWithBlock:^void(void(^block)(void)) {
block();
}];
});
return immediateExecutor;
}
+ (instancetype)mainThreadExecutor {
static OSSExecutor *mainThreadExecutor = NULL;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
mainThreadExecutor = [self executorWithBlock:^void(void(^block)(void)) {
if (![NSThread isMainThread]) {
dispatch_async(dispatch_get_main_queue(), block);
} else {
@autoreleasepool {
block();
}
}
}];
});
return mainThreadExecutor;
}
+ (instancetype)executorWithBlock:(void(^)(void(^block)(void)))block {
return [[self alloc] initWithBlock:block];
}
+ (instancetype)executorWithDispatchQueue:(dispatch_queue_t)queue {
return [self executorWithBlock:^void(void(^block)(void)) {
dispatch_async(queue, block);
}];
}
+ (instancetype)executorWithOperationQueue:(NSOperationQueue *)queue {
return [self executorWithBlock:^void(void(^block)(void)) {
[queue addOperation:[NSBlockOperation blockOperationWithBlock:block]];
}];
}
#pragma mark - Initializer
- (instancetype)initWithBlock:(void(^)(void(^block)(void)))block {
self = [super init];
if (!self) return self;
_block = block;
return self;
}
#pragma mark - Execution
- (void)execute:(void(^)(void))block {
self.block(block);
}
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,295 @@
/*
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
#import <Foundation/Foundation.h>
#import "OSSCancellationToken.h"
NS_ASSUME_NONNULL_BEGIN
/*!
Error domain used if there was multiple errors on <OSSTask taskForCompletionOfAllTasks:>.
*/
extern NSString *const OSSTaskErrorDomain;
/*!
An error code used for <OSSTask taskForCompletionOfAllTasks:>, if there were multiple errors.
*/
extern NSInteger const kOSSMultipleErrorsError;
/*!
An exception that is thrown if there was multiple exceptions on <OSSTask taskForCompletionOfAllTasks:>.
*/
extern NSString *const OSSTaskMultipleExceptionsException;
/*!
An error userInfo key used if there were multiple errors on <OSSTask taskForCompletionOfAllTasks:>.
Value type is `NSArray<NSError *> *`.
*/
extern NSString *const OSSTaskMultipleErrorsUserInfoKey;
/*!
An error userInfo key used if there were multiple exceptions on <OSSTask taskForCompletionOfAllTasks:>.
Value type is `NSArray<NSException *> *`.
*/
extern NSString *const OSSTaskMultipleExceptionsUserInfoKey;
@class OSSExecutor;
@class OSSTask;
/*!
The consumer view of a Task. A OSSTask has methods to
inspect the state of the task, and to add continuations to
be run once the task is complete.
*/
@interface OSSTask<__covariant ResultType> : NSObject
/*!
A block that can act as a continuation for a task.
*/
typedef __nullable id(^OSSContinuationBlock)(OSSTask<ResultType> *task);
/*!
Creates a task that is already completed with the given result.
@param result The result for the task.
*/
+ (instancetype)taskWithResult:(_Nullable ResultType)result;
/*!
Creates a task that is already completed with the given error.
@param error The error for the task.
*/
+ (instancetype)taskWithError:(NSError *)error;
/*!
Creates a task that is already completed with the given exception.
@param exception The exception for the task.
*/
+ (instancetype)taskWithException:(NSException *)exception;
/*!
Creates a task that is already cancelled.
*/
+ (instancetype)cancelledTask;
/*!
Returns a task that will be completed (with result == nil) once
all of the input tasks have completed.
@param tasks An `NSArray` of the tasks to use as an input.
*/
+ (instancetype)taskForCompletionOfAllTasks:(nullable NSArray<OSSTask *> *)tasks;
/*!
Returns a task that will be completed once all of the input tasks have completed.
If all tasks complete successfully without being faulted or cancelled the result will be
an `NSArray` of all task results in the order they were provided.
@param tasks An `NSArray` of the tasks to use as an input.
*/
+ (instancetype)taskForCompletionOfAllTasksWithResults:(nullable NSArray<OSSTask *> *)tasks;
/*!
Returns a task that will be completed once there is at least one successful task.
The first task to successuly complete will set the result, all other tasks results are
ignored.
@param tasks An `NSArray` of the tasks to use as an input.
*/
+ (instancetype)taskForCompletionOfAnyTask:(nullable NSArray<OSSTask *> *)tasks;
/*!
Returns a task that will be completed a certain amount of time in the future.
@param millis The approximate number of milliseconds to wait before the
task will be finished (with result == nil).
*/
+ (instancetype)taskWithDelay:(int)millis;
/*!
Returns a task that will be completed a certain amount of time in the future.
@param millis The approximate number of milliseconds to wait before the
task will be finished (with result == nil).
@param token The cancellation token (optional).
*/
+ (instancetype)taskWithDelay:(int)millis cancellationToken:(nullable OSSCancellationToken *)token;
/*!
Returns a task that will be completed after the given block completes with
the specified executor.
@param executor A OSSExecutor responsible for determining how the
continuation block will be run.
@param block The block to immediately schedule to run with the given executor.
@returns A task that will be completed after block has run.
If block returns a OSSTask, then the task returned from
this method will not be completed until that task is completed.
*/
+ (instancetype)taskFromExecutor:(OSSExecutor *)executor withBlock:(nullable id (^)(void))block;
// Properties that will be set on the task once it is completed.
/*!
The result of a successful task.
*/
@property (nullable, nonatomic, strong, readonly) ResultType result;
/*!
The error of a failed task.
*/
@property (nullable, nonatomic, strong, readonly) NSError *error;
/*!
The exception of a failed task.
*/
@property (nullable, nonatomic, strong, readonly) NSException *exception;
/*!
Whether this task has been cancelled.
*/
@property (nonatomic, assign, readonly, getter=isCancelled) BOOL cancelled;
/*!
Whether this task has completed due to an error or exception.
*/
@property (nonatomic, assign, readonly, getter=isFaulted) BOOL faulted;
/*!
Whether this task has completed.
*/
@property (nonatomic, assign, readonly, getter=isCompleted) BOOL completed;
/*!
Enqueues the given block to be run once this task is complete.
This method uses a default execution strategy. The block will be
run on the thread where the previous task completes, unless the
the stack depth is too deep, in which case it will be run on a
dispatch queue with default priority.
@param block The block to be run once this task is complete.
@returns A task that will be completed after block has run.
If block returns a OSSTask, then the task returned from
this method will not be completed until that task is completed.
*/
- (OSSTask *)continueWithBlock:(OSSContinuationBlock)block;
/*!
Enqueues the given block to be run once this task is complete.
This method uses a default execution strategy. The block will be
run on the thread where the previous task completes, unless the
the stack depth is too deep, in which case it will be run on a
dispatch queue with default priority.
@param block The block to be run once this task is complete.
@param cancellationToken The cancellation token (optional).
@returns A task that will be completed after block has run.
If block returns a OSSTask, then the task returned from
this method will not be completed until that task is completed.
*/
- (OSSTask *)continueWithBlock:(OSSContinuationBlock)block cancellationToken:(nullable OSSCancellationToken *)cancellationToken;
/*!
Enqueues the given block to be run once this task is complete.
@param executor A OSSExecutor responsible for determining how the
continuation block will be run.
@param block The block to be run once this task is complete.
@returns A task that will be completed after block has run.
If block returns a OSSTask, then the task returned from
this method will not be completed until that task is completed.
*/
- (OSSTask *)continueWithExecutor:(OSSExecutor *)executor withBlock:(OSSContinuationBlock)block;
/*!
Enqueues the given block to be run once this task is complete.
@param executor A OSSExecutor responsible for determining how the
continuation block will be run.
@param block The block to be run once this task is complete.
@param cancellationToken The cancellation token (optional).
@returns A task that will be completed after block has run.
If block returns a OSSTask, then the task returned from
his method will not be completed until that task is completed.
*/
- (OSSTask *)continueWithExecutor:(OSSExecutor *)executor
block:(OSSContinuationBlock)block
cancellationToken:(nullable OSSCancellationToken *)cancellationToken;
/*!
Identical to continueWithBlock:, except that the block is only run
if this task did not produce a cancellation, error, or exception.
If it did, then the failure will be propagated to the returned
task.
@param block The block to be run once this task is complete.
@returns A task that will be completed after block has run.
If block returns a OSSTask, then the task returned from
this method will not be completed until that task is completed.
*/
- (OSSTask *)continueWithSuccessBlock:(OSSContinuationBlock)block;
/*!
Identical to continueWithBlock:, except that the block is only run
if this task did not produce a cancellation, error, or exception.
If it did, then the failure will be propagated to the returned
task.
@param block The block to be run once this task is complete.
@param cancellationToken The cancellation token (optional).
@returns A task that will be completed after block has run.
If block returns a OSSTask, then the task returned from
this method will not be completed until that task is completed.
*/
- (OSSTask *)continueWithSuccessBlock:(OSSContinuationBlock)block cancellationToken:(nullable OSSCancellationToken *)cancellationToken;
/*!
Identical to continueWithExecutor:withBlock:, except that the block
is only run if this task did not produce a cancellation, error, or
exception. If it did, then the failure will be propagated to the
returned task.
@param executor A OSSExecutor responsible for determining how the
continuation block will be run.
@param block The block to be run once this task is complete.
@returns A task that will be completed after block has run.
If block returns a OSSTask, then the task returned from
this method will not be completed until that task is completed.
*/
- (OSSTask *)continueWithExecutor:(OSSExecutor *)executor withSuccessBlock:(OSSContinuationBlock)block;
/*!
Identical to continueWithExecutor:withBlock:, except that the block
is only run if this task did not produce a cancellation, error, or
exception. If it did, then the failure will be propagated to the
returned task.
@param executor A OSSExecutor responsible for determining how the
continuation block will be run.
@param block The block to be run once this task is complete.
@param cancellationToken The cancellation token (optional).
@returns A task that will be completed after block has run.
If block returns a OSSTask, then the task returned from
this method will not be completed until that task is completed.
*/
- (OSSTask *)continueWithExecutor:(OSSExecutor *)executor
successBlock:(OSSContinuationBlock)block
cancellationToken:(nullable OSSCancellationToken *)cancellationToken;
/*!
Waits until this operation is completed.
This method is inefficient and consumes a thread resource while
it's running. It should be avoided. This method logs a warning
message if it is used on the main thread.
*/
- (void)waitUntilFinished;
@end
@class OSSResult;
@interface OSSTask(OSS)
typedef void(^OSSCompleteBlock)(BOOL isSuccess, NSError * _Nullable error, OSSResult * _Nullable result);
- (BOOL)isSuccessful;
- (NSError *)toError;
- (OSSTask *)completed:(OSSCompleteBlock)block;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,584 @@
/*
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
#import "OSSTask.h"
#import "OSSLog.h"
#import "OSSConstants.h"
#import "OSSDefine.h"
#import <libkern/OSAtomic.h>
#import "OSSBolts.h"
NS_ASSUME_NONNULL_BEGIN
__attribute__ ((noinline)) void ossWarnBlockingOperationOnMainThread() {
NSLog(@"Warning: A long-running operation is being executed on the main thread. \n"
" Break on warnBlockingOperationOnMainThread() to debug.");
}
NSString *const OSSTaskErrorDomain = @"bolts";
NSInteger const kOSSMultipleErrorsError = 80175001;
NSString *const OSSTaskMultipleExceptionsException = @"OSSMultipleExceptionsException";
NSString *const OSSTaskMultipleErrorsUserInfoKey = @"errors";
NSString *const OSSTaskMultipleExceptionsUserInfoKey = @"exceptions";
@interface OSSTask () {
id _result;
NSError *_error;
NSException *_exception;
}
@property (nonatomic, assign, readwrite, getter=isCancelled) BOOL cancelled;
@property (nonatomic, assign, readwrite, getter=isFaulted) BOOL faulted;
@property (nonatomic, assign, readwrite, getter=isCompleted) BOOL completed;
@property (nonatomic, strong) NSObject *lock;
@property (nonatomic, strong) NSCondition *condition;
@property (nonatomic, strong) NSMutableArray *callbacks;
@end
@implementation OSSTask
#pragma mark - Initializer
- (instancetype)init {
self = [super init];
if (!self) return self;
_lock = [[NSObject alloc] init];
_condition = [[NSCondition alloc] init];
_callbacks = [NSMutableArray array];
return self;
}
- (instancetype)initWithResult:(_Nullable id)result {
self = [super init];
if (self) {
[self trySetResult:result];
}
return self;
}
- (instancetype)initWithError:(NSError *)error {
self = [super init];
if (!self) return self;
[self trySetError:error];
return self;
}
- (instancetype)initWithException:(NSException *)exception {
self = [super init];
if (!self) return self;
[self trySetException:exception];
return self;
}
- (instancetype)initCancelled {
self = [super init];
if (!self) return self;
[self trySetCancelled];
return self;
}
#pragma mark - Task Class methods
+ (instancetype)taskWithResult:(_Nullable id)result {
return [[self alloc] initWithResult:result];
}
+ (instancetype)taskWithError:(NSError *)error {
return [[self alloc] initWithError:error];
}
+ (instancetype)taskWithException:(NSException *)exception {
return [[self alloc] initWithException:exception];
}
+ (instancetype)cancelledTask {
return [[self alloc] initCancelled];
}
+ (instancetype)taskForCompletionOfAllTasks:(nullable NSArray<OSSTask *> *)tasks {
__block int32_t total = (int32_t)tasks.count;
if (total == 0) {
return [self taskWithResult:nil];
}
__block int32_t cancelled = 0;
NSObject *lock = [[NSObject alloc] init];
NSMutableArray *errors = [NSMutableArray array];
NSMutableArray *exceptions = [NSMutableArray array];
OSSTaskCompletionSource *tcs = [OSSTaskCompletionSource taskCompletionSource];
for (OSSTask *task in tasks) {
[task continueWithBlock:^id(OSSTask *task) {
if (task.exception) {
@synchronized (lock) {
[exceptions addObject:task.exception];
}
} else if (task.error) {
@synchronized (lock) {
[errors addObject:task.error];
}
} else if (task.cancelled) {
OSAtomicIncrement32Barrier(&cancelled);
}
if (OSAtomicDecrement32Barrier(&total) == 0) {
if (exceptions.count > 0) {
if (exceptions.count == 1) {
tcs.exception = [exceptions firstObject];
} else {
NSException *exception =
[NSException exceptionWithName:OSSTaskMultipleExceptionsException
reason:@"There were multiple exceptions."
userInfo:@{ OSSTaskMultipleExceptionsUserInfoKey: exceptions }];
tcs.exception = exception;
}
} else if (errors.count > 0) {
if (errors.count == 1) {
tcs.error = [errors firstObject];
} else {
NSError *error = [NSError errorWithDomain:OSSTaskErrorDomain
code:kOSSMultipleErrorsError
userInfo:@{ OSSTaskMultipleErrorsUserInfoKey: errors }];
tcs.error = error;
}
} else if (cancelled > 0) {
[tcs cancel];
} else {
tcs.result = nil;
}
}
return nil;
}];
}
return tcs.task;
}
+ (instancetype)taskForCompletionOfAllTasksWithResults:(nullable NSArray<OSSTask *> *)tasks {
return [[self taskForCompletionOfAllTasks:tasks] continueWithSuccessBlock:^id(OSSTask *task) {
return [tasks valueForKey:@"result"];
}];
}
+ (instancetype)taskForCompletionOfAnyTask:(nullable NSArray<OSSTask *> *)tasks
{
__block int32_t total = (int32_t)tasks.count;
if (total == 0) {
return [self taskWithResult:nil];
}
__block int completed = 0;
__block int32_t cancelled = 0;
NSObject *lock = [NSObject new];
NSMutableArray<NSError *> *errors = [NSMutableArray new];
NSMutableArray<NSException *> *exceptions = [NSMutableArray new];
OSSTaskCompletionSource *source = [OSSTaskCompletionSource taskCompletionSource];
for (OSSTask *task in tasks) {
[task continueWithBlock:^id(OSSTask *task) {
if (task.exception != nil) {
@synchronized(lock) {
[exceptions addObject:task.exception];
}
} else if (task.error != nil) {
@synchronized(lock) {
[errors addObject:task.error];
}
} else if (task.cancelled) {
OSAtomicIncrement32Barrier(&cancelled);
} else {
if(OSAtomicCompareAndSwap32Barrier(0, 1, &completed)) {
[source setResult:task.result];
}
}
if (OSAtomicDecrement32Barrier(&total) == 0 &&
OSAtomicCompareAndSwap32Barrier(0, 1, &completed)) {
if (cancelled > 0) {
[source cancel];
} else if (exceptions.count > 0) {
if (exceptions.count == 1) {
source.exception = exceptions.firstObject;
} else {
NSException *exception =
[NSException exceptionWithName:OSSTaskMultipleExceptionsException
reason:@"There were multiple exceptions."
userInfo:@{ @"exceptions": exceptions }];
source.exception = exception;
}
} else if (errors.count > 0) {
if (errors.count == 1) {
source.error = errors.firstObject;
} else {
NSError *error = [NSError errorWithDomain:OSSTaskErrorDomain
code:kOSSMultipleErrorsError
userInfo:@{ @"errors": errors }];
source.error = error;
}
}
}
// Abort execution of per tasks continuations
return nil;
}];
}
return source.task;
}
+ (instancetype)taskWithDelay:(int)millis {
OSSTaskCompletionSource *tcs = [OSSTaskCompletionSource taskCompletionSource];
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, millis * NSEC_PER_MSEC);
dispatch_after(popTime, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
tcs.result = nil;
});
return tcs.task;
}
+ (instancetype)taskWithDelay:(int)millis cancellationToken:(nullable OSSCancellationToken *)token {
if (token.cancellationRequested) {
return [OSSTask cancelledTask];
}
OSSTaskCompletionSource *tcs = [OSSTaskCompletionSource taskCompletionSource];
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, millis * NSEC_PER_MSEC);
dispatch_after(popTime, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
if (token.cancellationRequested) {
[tcs cancel];
return;
}
tcs.result = nil;
});
return tcs.task;
}
+ (instancetype)taskFromExecutor:(OSSExecutor *)executor withBlock:(nullable id (^)(void))block {
return [[self taskWithResult:nil] continueWithExecutor:executor withBlock:^id(OSSTask *task) {
return block();
}];
}
#pragma mark - Custom Setters/Getters
- (nullable id)result {
@synchronized(self.lock) {
return _result;
}
}
- (BOOL)trySetResult:(nullable id)result {
@synchronized(self.lock) {
if (self.completed) {
return NO;
}
self.completed = YES;
_result = result;
[self runContinuations];
return YES;
}
}
- (nullable NSError *)error {
@synchronized(self.lock) {
return _error;
}
}
- (BOOL)trySetError:(NSError *)error {
@synchronized(self.lock) {
if (self.completed) {
return NO;
}
self.completed = YES;
self.faulted = YES;
_error = error;
[self runContinuations];
return YES;
}
}
- (nullable NSException *)exception {
@synchronized(self.lock) {
return _exception;
}
}
- (BOOL)trySetException:(NSException *)exception {
@synchronized(self.lock) {
if (self.completed) {
return NO;
}
self.completed = YES;
self.faulted = YES;
_exception = exception;
[self runContinuations];
return YES;
}
}
- (BOOL)isCancelled {
@synchronized(self.lock) {
return _cancelled;
}
}
- (BOOL)isFaulted {
@synchronized(self.lock) {
return _faulted;
}
}
- (BOOL)trySetCancelled {
@synchronized(self.lock) {
if (self.completed) {
return NO;
}
self.completed = YES;
self.cancelled = YES;
[self runContinuations];
return YES;
}
}
- (BOOL)isCompleted {
@synchronized(self.lock) {
return _completed;
}
}
- (void)runContinuations {
@synchronized(self.lock) {
[self.condition lock];
[self.condition broadcast];
[self.condition unlock];
for (void (^callback)(void) in self.callbacks) {
callback();
}
[self.callbacks removeAllObjects];
}
}
#pragma mark - Chaining methods
- (OSSTask *)continueWithExecutor:(OSSExecutor *)executor withBlock:(OSSContinuationBlock)block {
return [self continueWithExecutor:executor block:block cancellationToken:nil];
}
- (OSSTask *)continueWithExecutor:(OSSExecutor *)executor
block:(OSSContinuationBlock)block
cancellationToken:(nullable OSSCancellationToken *)cancellationToken {
OSSTaskCompletionSource *tcs = [OSSTaskCompletionSource taskCompletionSource];
// Capture all of the state that needs to used when the continuation is complete.
dispatch_block_t executionBlock = ^{
if (cancellationToken.cancellationRequested) {
[tcs cancel];
return;
}
id result = nil;
@try {
result = block(self);
} @catch (NSException *exception) {
NSError *error = [NSError errorWithDomain:OSSClientErrorDomain
code:OSSClientErrorCodeExcpetionCatched
userInfo:@{OSSErrorMessageTOKEN: [NSString stringWithFormat:@"Catch exception - %@", exception]}];
tcs.error = error;
OSSLogError(@"exception name: %@",[exception name]);
OSSLogError(@"exception reason: %@",[exception reason]);
return;
}
if ([result isKindOfClass:[OSSTask class]]) {
id (^setupWithTask) (OSSTask *) = ^id(OSSTask *task) {
if (cancellationToken.cancellationRequested || task.cancelled) {
[tcs cancel];
} else if (task.exception) {
NSError *error = [NSError errorWithDomain:OSSClientErrorDomain
code:OSSClientErrorCodeExcpetionCatched
userInfo:@{OSSErrorMessageTOKEN: [NSString stringWithFormat:@"Catch exception - %@", task.exception]}];
tcs.error = error;
} else if (task.error) {
tcs.error = task.error;
} else {
tcs.result = task.result;
}
return nil;
};
OSSTask *resultTask = (OSSTask *)result;
if (resultTask.completed) {
setupWithTask(resultTask);
} else {
[resultTask continueWithBlock:setupWithTask];
}
} else {
tcs.result = result;
}
};
BOOL completed;
@synchronized(self.lock) {
completed = self.completed;
if (!completed) {
[self.callbacks addObject:[^{
[executor execute:executionBlock];
} copy]];
}
}
if (completed) {
[executor execute:executionBlock];
}
return tcs.task;
}
- (OSSTask *)continueWithBlock:(OSSContinuationBlock)block {
return [self continueWithExecutor:[OSSExecutor defaultExecutor] block:block cancellationToken:nil];
}
- (OSSTask *)continueWithBlock:(OSSContinuationBlock)block cancellationToken:(nullable OSSCancellationToken *)cancellationToken {
return [self continueWithExecutor:[OSSExecutor defaultExecutor] block:block cancellationToken:cancellationToken];
}
- (OSSTask *)continueWithExecutor:(OSSExecutor *)executor
withSuccessBlock:(OSSContinuationBlock)block {
return [self continueWithExecutor:executor successBlock:block cancellationToken:nil];
}
- (OSSTask *)continueWithExecutor:(OSSExecutor *)executor
successBlock:(OSSContinuationBlock)block
cancellationToken:(nullable OSSCancellationToken *)cancellationToken {
if (cancellationToken.cancellationRequested) {
return [OSSTask cancelledTask];
}
return [self continueWithExecutor:executor block:^id(OSSTask *task) {
if (task.faulted || task.cancelled) {
return task;
} else {
return block(task);
}
} cancellationToken:cancellationToken];
}
- (OSSTask *)continueWithSuccessBlock:(OSSContinuationBlock)block {
return [self continueWithExecutor:[OSSExecutor defaultExecutor] successBlock:block cancellationToken:nil];
}
- (OSSTask *)continueWithSuccessBlock:(OSSContinuationBlock)block cancellationToken:(nullable OSSCancellationToken *)cancellationToken {
return [self continueWithExecutor:[OSSExecutor defaultExecutor] successBlock:block cancellationToken:cancellationToken];
}
#pragma mark - Syncing Task (Avoid it)
- (void)warnOperationOnMainThread {
ossWarnBlockingOperationOnMainThread();
}
- (void)waitUntilFinished {
if ([NSThread isMainThread]) {
[self warnOperationOnMainThread];
}
@synchronized(self.lock) {
if (self.completed) {
return;
}
[self.condition lock];
}
while (!self.completed) {
[self.condition wait];
}
[self.condition unlock];
}
#pragma mark - NSObject
- (NSString *)description {
// Acquire the data from the locked properties
BOOL completed;
BOOL cancelled;
BOOL faulted;
NSString *resultDescription = nil;
@synchronized(self.lock) {
completed = self.completed;
cancelled = self.cancelled;
faulted = self.faulted;
resultDescription = completed ? [NSString stringWithFormat:@" result = %@", self.result] : @"";
}
// Description string includes status information and, if available, the
// result since in some ways this is what a promise actually "is".
return [NSString stringWithFormat:@"<%@: %p; completed = %@; cancelled = %@; faulted = %@;%@>",
NSStringFromClass([self class]),
self,
completed ? @"YES" : @"NO",
cancelled ? @"YES" : @"NO",
faulted ? @"YES" : @"NO",
resultDescription];
}
@end
@implementation OSSTask(OSS)
- (BOOL)isSuccessful {
if (self.cancelled || self.faulted) {
return false;
}
return true;
}
- (NSError *)toError {
if (self.cancelled) {
return [NSError errorWithDomain:OSSClientErrorDomain
code:OSSClientErrorCodeTaskCancelled
userInfo:@{OSSErrorMessageTOKEN: @"This task is cancelled"}];
} else if (self.error) {
return self.error;
} else if (self.exception) {
return [NSError errorWithDomain:OSSClientErrorDomain
code:OSSClientErrorCodeExcpetionCatched
userInfo:@{OSSErrorMessageTOKEN: [NSString stringWithFormat:@"Catch exception - %@", self.exception]}];
}
return nil;
}
- (OSSTask *)completed:(OSSCompleteBlock)block {
return [self continueWithBlock:^id _Nullable(OSSTask * _Nonnull task) {
if ([task isSuccessful]) {
block(YES, nil, task.result);
} else {
block(NO, [task toError], nil);
}
return nil;
}];
}
@end
NS_ASSUME_NONNULL_END

Some files were not shown because too many files have changed in this diff Show More