Merge branch 'new-s3-changes' into v1.8-merge
Conflicts: Mac.xcodeproj/project.pbxproj
Showing
9 changed files
with
204 additions
and
54 deletions
@@ -60,15 +60,12 @@ | @@ -60,15 +60,12 @@ | ||
60 | // Use for deleting buckets - they must be empty for this to succeed | 60 | // Use for deleting buckets - they must be empty for this to succeed |
61 | + (id)DELETERequestWithBucket:(NSString *)bucket; | 61 | + (id)DELETERequestWithBucket:(NSString *)bucket; |
62 | 62 | ||
63 | -//Builds a query string out of the list parameters we supplied | 63 | +@property (retain, nonatomic) NSString *bucket; |
64 | -- (void)createQueryString; | 64 | +@property (retain, nonatomic) NSString *subResource; |
65 | - | 65 | +@property (retain, nonatomic) NSString *prefix; |
66 | -@property (retain) NSString *bucket; | 66 | +@property (retain, nonatomic) NSString *marker; |
67 | -@property (retain) NSString *subResource; | 67 | +@property (assign, nonatomic) int maxResultCount; |
68 | -@property (retain) NSString *prefix; | 68 | +@property (retain, nonatomic) NSString *delimiter; |
69 | -@property (retain) NSString *marker; | ||
70 | -@property (assign) int maxResultCount; | ||
71 | -@property (retain) NSString *delimiter; | ||
72 | @property (retain, readonly) NSMutableArray *objects; | 69 | @property (retain, readonly) NSMutableArray *objects; |
73 | @property (retain, readonly) NSMutableArray *commonPrefixes; | 70 | @property (retain, readonly) NSMutableArray *commonPrefixes; |
74 | @property (assign, readonly) BOOL isTruncated; | 71 | @property (assign, readonly) BOOL isTruncated; |
@@ -30,20 +30,19 @@ | @@ -30,20 +30,19 @@ | ||
30 | 30 | ||
31 | + (id)requestWithBucket:(NSString *)bucket | 31 | + (id)requestWithBucket:(NSString *)bucket |
32 | { | 32 | { |
33 | - ASIS3BucketRequest *request = [[[self alloc] initWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://%@.s3.amazonaws.com",bucket]]] autorelease]; | 33 | + ASIS3BucketRequest *request = [[[self alloc] initWithURL:nil] autorelease]; |
34 | [request setBucket:bucket]; | 34 | [request setBucket:bucket]; |
35 | return request; | 35 | return request; |
36 | } | 36 | } |
37 | 37 | ||
38 | + (id)requestWithBucket:(NSString *)bucket subResource:(NSString *)subResource | 38 | + (id)requestWithBucket:(NSString *)bucket subResource:(NSString *)subResource |
39 | { | 39 | { |
40 | - ASIS3BucketRequest *request = [[[self alloc] initWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://%@.s3.amazonaws.com/?%@",bucket,subResource]]] autorelease]; | 40 | + ASIS3BucketRequest *request = [[[self alloc] initWithURL:nil] autorelease]; |
41 | [request setBucket:bucket]; | 41 | [request setBucket:bucket]; |
42 | [request setSubResource:subResource]; | 42 | [request setSubResource:subResource]; |
43 | return request; | 43 | return request; |
44 | } | 44 | } |
45 | 45 | ||
46 | - | ||
47 | + (id)PUTRequestWithBucket:(NSString *)bucket | 46 | + (id)PUTRequestWithBucket:(NSString *)bucket |
48 | { | 47 | { |
49 | ASIS3BucketRequest *request = [self requestWithBucket:bucket]; | 48 | ASIS3BucketRequest *request = [self requestWithBucket:bucket]; |
@@ -80,8 +79,14 @@ | @@ -80,8 +79,14 @@ | ||
80 | return [NSString stringWithFormat:@"/%@/",[self bucket]]; | 79 | return [NSString stringWithFormat:@"/%@/",[self bucket]]; |
81 | } | 80 | } |
82 | 81 | ||
83 | -- (void)createQueryString | 82 | +- (void)buildURL |
84 | { | 83 | { |
84 | + NSString *baseURL; | ||
85 | + if ([self subResource]) { | ||
86 | + baseURL = [NSString stringWithFormat:@"%@://%@.%@/?%@",[self requestScheme],[self bucket],[[self class] S3Host],[self subResource]]; | ||
87 | + } else { | ||
88 | + baseURL = [NSString stringWithFormat:@"%@://%@.%@",[self requestScheme],[self bucket],[[self class] S3Host]]; | ||
89 | + } | ||
85 | NSMutableArray *queryParts = [[[NSMutableArray alloc] init] autorelease]; | 90 | NSMutableArray *queryParts = [[[NSMutableArray alloc] init] autorelease]; |
86 | if ([self prefix]) { | 91 | if ([self prefix]) { |
87 | [queryParts addObject:[NSString stringWithFormat:@"prefix=%@",[[self prefix] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]]; | 92 | [queryParts addObject:[NSString stringWithFormat:@"prefix=%@",[[self prefix] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]]; |
@@ -95,20 +100,16 @@ | @@ -95,20 +100,16 @@ | ||
95 | if ([self maxResultCount] > 0) { | 100 | if ([self maxResultCount] > 0) { |
96 | [queryParts addObject:[NSString stringWithFormat:@"max-keys=%hi",[self maxResultCount]]]; | 101 | [queryParts addObject:[NSString stringWithFormat:@"max-keys=%hi",[self maxResultCount]]]; |
97 | } | 102 | } |
98 | - if ([queryParts count]) | 103 | + if ([queryParts count]) { |
99 | - { | ||
100 | NSString* template = @"%@?%@"; | 104 | NSString* template = @"%@?%@"; |
101 | if ([[self subResource] length] > 0) { | 105 | if ([[self subResource] length] > 0) { |
102 | template = @"%@&%@"; | 106 | template = @"%@&%@"; |
103 | } | 107 | } |
104 | - [self setURL:[NSURL URLWithString:[NSString stringWithFormat:template,[[self url] absoluteString],[queryParts componentsJoinedByString:@"&"]]]]; | 108 | + [self setURL:[NSURL URLWithString:[NSString stringWithFormat:template,baseURL,[queryParts componentsJoinedByString:@"&"]]]]; |
105 | - } | 109 | + } else { |
106 | -} | 110 | + [self setURL:[NSURL URLWithString:baseURL]]; |
107 | 111 | ||
108 | -- (void)main | 112 | + } |
109 | -{ | ||
110 | - [self createQueryString]; | ||
111 | - [super main]; | ||
112 | } | 113 | } |
113 | 114 | ||
114 | - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict | 115 | - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict |
@@ -146,7 +147,6 @@ | @@ -146,7 +147,6 @@ | ||
146 | } | 147 | } |
147 | } | 148 | } |
148 | 149 | ||
149 | - | ||
150 | #pragma mark NSCopying | 150 | #pragma mark NSCopying |
151 | 151 | ||
152 | - (id)copyWithZone:(NSZone *)zone | 152 | - (id)copyWithZone:(NSZone *)zone |
@@ -161,9 +161,6 @@ | @@ -161,9 +161,6 @@ | ||
161 | return newRequest; | 161 | return newRequest; |
162 | } | 162 | } |
163 | 163 | ||
164 | - | ||
165 | - | ||
166 | - | ||
167 | @synthesize bucket; | 164 | @synthesize bucket; |
168 | @synthesize subResource; | 165 | @synthesize subResource; |
169 | @synthesize currentObject; | 166 | @synthesize currentObject; |
@@ -10,6 +10,9 @@ | @@ -10,6 +10,9 @@ | ||
10 | #import <Foundation/Foundation.h> | 10 | #import <Foundation/Foundation.h> |
11 | #import "ASIS3Request.h" | 11 | #import "ASIS3Request.h" |
12 | 12 | ||
13 | +// Constants for storage class | ||
14 | +extern NSString *const ASIS3StorageClassStandard; | ||
15 | +extern NSString *const ASIS3StorageClassReducedRedundancy; | ||
13 | 16 | ||
14 | @interface ASIS3ObjectRequest : ASIS3Request { | 17 | @interface ASIS3ObjectRequest : ASIS3Request { |
15 | 18 | ||
@@ -28,7 +31,14 @@ | @@ -28,7 +31,14 @@ | ||
28 | // Can be autodetected when PUTing a file from disk, will default to 'application/octet-stream' when PUTing data | 31 | // Can be autodetected when PUTing a file from disk, will default to 'application/octet-stream' when PUTing data |
29 | NSString *mimeType; | 32 | NSString *mimeType; |
30 | 33 | ||
34 | + // Set this to specify you want to work with a particular subresource (eg an acl for that resource) | ||
35 | + // See requestWithBucket:key:subResource:, below. | ||
31 | NSString* subResource; | 36 | NSString* subResource; |
37 | + | ||
38 | + // The storage class to be used for PUT requests | ||
39 | + // Set this to ASIS3StorageClassReducedRedundancy to save money on storage, at (presumably) a slightly higher risk you will lose the data | ||
40 | + // If this is not set, no x-amz-storage-class header will be sent to S3, and their default will be used | ||
41 | + NSString *storageClass; | ||
32 | } | 42 | } |
33 | 43 | ||
34 | // Create a request, building an appropriate url | 44 | // Create a request, building an appropriate url |
@@ -60,11 +70,11 @@ | @@ -60,11 +70,11 @@ | ||
60 | // Creates a HEAD request for the object at path | 70 | // Creates a HEAD request for the object at path |
61 | + (id)HEADRequestWithBucket:(NSString *)bucket key:(NSString *)key; | 71 | + (id)HEADRequestWithBucket:(NSString *)bucket key:(NSString *)key; |
62 | 72 | ||
63 | -@property (retain) NSString *bucket; | 73 | +@property (retain, nonatomic) NSString *bucket; |
64 | -@property (retain) NSString *key; | 74 | +@property (retain, nonatomic) NSString *key; |
65 | -@property (retain) NSString *sourceBucket; | 75 | +@property (retain, nonatomic) NSString *sourceBucket; |
66 | -@property (retain) NSString *sourceKey; | 76 | +@property (retain, nonatomic) NSString *sourceKey; |
67 | @property (retain, nonatomic) NSString *mimeType; | 77 | @property (retain, nonatomic) NSString *mimeType; |
68 | -@property (retain) NSString *subResource; | 78 | +@property (retain, nonatomic) NSString *subResource; |
69 | - | 79 | +@property (retain, nonatomic) NSString *storageClass; |
70 | @end | 80 | @end |
@@ -8,6 +8,8 @@ | @@ -8,6 +8,8 @@ | ||
8 | 8 | ||
9 | #import "ASIS3ObjectRequest.h" | 9 | #import "ASIS3ObjectRequest.h" |
10 | 10 | ||
11 | +NSString *const ASIS3StorageClassStandard = @"STANDARD"; | ||
12 | +NSString *const ASIS3StorageClassReducedRedundancy = @"REDUCED_REDUNDANCY"; | ||
11 | 13 | ||
12 | @implementation ASIS3ObjectRequest | 14 | @implementation ASIS3ObjectRequest |
13 | 15 | ||
@@ -21,8 +23,7 @@ | @@ -21,8 +23,7 @@ | ||
21 | 23 | ||
22 | + (id)requestWithBucket:(NSString *)bucket key:(NSString *)key | 24 | + (id)requestWithBucket:(NSString *)bucket key:(NSString *)key |
23 | { | 25 | { |
24 | - NSString *path = [ASIS3Request stringByURLEncodingForS3Path:key]; | 26 | + ASIS3ObjectRequest *request = [[[self alloc] initWithURL:nil] autorelease]; |
25 | - ASIS3ObjectRequest *request = [[[self alloc] initWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://%@.s3.amazonaws.com%@",bucket,path]]] autorelease]; | ||
26 | [request setBucket:bucket]; | 27 | [request setBucket:bucket]; |
27 | [request setKey:key]; | 28 | [request setKey:key]; |
28 | return request; | 29 | return request; |
@@ -30,8 +31,7 @@ | @@ -30,8 +31,7 @@ | ||
30 | 31 | ||
31 | + (id)requestWithBucket:(NSString *)bucket key:(NSString *)key subResource:(NSString *)subResource | 32 | + (id)requestWithBucket:(NSString *)bucket key:(NSString *)key subResource:(NSString *)subResource |
32 | { | 33 | { |
33 | - NSString *path = [ASIS3Request stringByURLEncodingForS3Path:key]; | 34 | + ASIS3ObjectRequest *request = [[[self alloc] initWithURL:nil] autorelease]; |
34 | - ASIS3ObjectRequest *request = [[[self alloc] initWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://%@.s3.amazonaws.com%@?%@",bucket,path,subResource]]] autorelease]; | ||
35 | [request setSubResource:subResource]; | 35 | [request setSubResource:subResource]; |
36 | [request setBucket:bucket]; | 36 | [request setBucket:bucket]; |
37 | [request setKey:key]; | 37 | [request setKey:key]; |
@@ -79,8 +79,6 @@ | @@ -79,8 +79,6 @@ | ||
79 | return request; | 79 | return request; |
80 | } | 80 | } |
81 | 81 | ||
82 | - | ||
83 | - | ||
84 | - (id)copyWithZone:(NSZone *)zone | 82 | - (id)copyWithZone:(NSZone *)zone |
85 | { | 83 | { |
86 | ASIS3ObjectRequest *newRequest = [super copyWithZone:zone]; | 84 | ASIS3ObjectRequest *newRequest = [super copyWithZone:zone]; |
@@ -100,9 +98,19 @@ | @@ -100,9 +98,19 @@ | ||
100 | [sourceKey release]; | 98 | [sourceKey release]; |
101 | [sourceBucket release]; | 99 | [sourceBucket release]; |
102 | [subResource release]; | 100 | [subResource release]; |
101 | + [storageClass release]; | ||
103 | [super dealloc]; | 102 | [super dealloc]; |
104 | } | 103 | } |
105 | 104 | ||
105 | +- (void)buildURL | ||
106 | +{ | ||
107 | + if ([self subResource]) { | ||
108 | + [self setURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@://%@.%@%@?%@",[self requestScheme],[self bucket],[[self class] S3Host],[ASIS3Request stringByURLEncodingForS3Path:[self key]],[self subResource]]]]; | ||
109 | + } else { | ||
110 | + [self setURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@://%@.%@%@",[self requestScheme],[self bucket],[[self class] S3Host],[ASIS3Request stringByURLEncodingForS3Path:[self key]]]]]; | ||
111 | + } | ||
112 | +} | ||
113 | + | ||
106 | - (NSString *)mimeType | 114 | - (NSString *)mimeType |
107 | { | 115 | { |
108 | if (mimeType) { | 116 | if (mimeType) { |
@@ -129,6 +137,9 @@ | @@ -129,6 +137,9 @@ | ||
129 | NSString *path = [ASIS3Request stringByURLEncodingForS3Path:[self sourceKey]]; | 137 | NSString *path = [ASIS3Request stringByURLEncodingForS3Path:[self sourceKey]]; |
130 | [headers setObject:[[self sourceBucket] stringByAppendingString:path] forKey:@"x-amz-copy-source"]; | 138 | [headers setObject:[[self sourceBucket] stringByAppendingString:path] forKey:@"x-amz-copy-source"]; |
131 | } | 139 | } |
140 | + if ([self storageClass]) { | ||
141 | + [headers setObject:[self storageClass] forKey:@"x-amz-storage-class"]; | ||
142 | + } | ||
132 | return headers; | 143 | return headers; |
133 | } | 144 | } |
134 | 145 | ||
@@ -141,12 +152,11 @@ | @@ -141,12 +152,11 @@ | ||
141 | return [super stringToSignForHeaders:canonicalizedAmzHeaders resource:canonicalizedResource]; | 152 | return [super stringToSignForHeaders:canonicalizedAmzHeaders resource:canonicalizedResource]; |
142 | } | 153 | } |
143 | 154 | ||
144 | - | ||
145 | @synthesize bucket; | 155 | @synthesize bucket; |
146 | @synthesize key; | 156 | @synthesize key; |
147 | @synthesize sourceBucket; | 157 | @synthesize sourceBucket; |
148 | @synthesize sourceKey; | 158 | @synthesize sourceKey; |
149 | @synthesize mimeType; | 159 | @synthesize mimeType; |
150 | @synthesize subResource; | 160 | @synthesize subResource; |
151 | - | 161 | +@synthesize storageClass; |
152 | @end | 162 | @end |
@@ -18,16 +18,24 @@ | @@ -18,16 +18,24 @@ | ||
18 | // See http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?RESTAccessPolicy.html for what these mean | 18 | // See http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?RESTAccessPolicy.html for what these mean |
19 | extern NSString *const ASIS3AccessPolicyPrivate; // This is the default in S3 when no access policy header is provided | 19 | extern NSString *const ASIS3AccessPolicyPrivate; // This is the default in S3 when no access policy header is provided |
20 | extern NSString *const ASIS3AccessPolicyPublicRead; | 20 | extern NSString *const ASIS3AccessPolicyPublicRead; |
21 | -extern NSString *const ASIS3AccessPolicyPublicReadWrote; | 21 | +extern NSString *const ASIS3AccessPolicyPublicReadWrite; |
22 | extern NSString *const ASIS3AccessPolicyAuthenticatedRead; | 22 | extern NSString *const ASIS3AccessPolicyAuthenticatedRead; |
23 | +extern NSString *const ASIS3AccessPolicyBucketOwnerRead; | ||
24 | +extern NSString *const ASIS3AccessPolicyBucketOwnerFullControl; | ||
25 | + | ||
26 | +// Constants for requestScheme - defaults is ASIS3RequestSchemeHTTP | ||
27 | +extern NSString *const ASIS3RequestSchemeHTTP; | ||
28 | +extern NSString *const ASIS3RequestSchemeHTTPS; | ||
29 | + | ||
30 | + | ||
23 | 31 | ||
24 | typedef enum _ASIS3ErrorType { | 32 | typedef enum _ASIS3ErrorType { |
25 | ASIS3ResponseParsingFailedType = 1, | 33 | ASIS3ResponseParsingFailedType = 1, |
26 | ASIS3ResponseErrorType = 2 | 34 | ASIS3ResponseErrorType = 2 |
27 | - | ||
28 | } ASIS3ErrorType; | 35 | } ASIS3ErrorType; |
29 | 36 | ||
30 | 37 | ||
38 | + | ||
31 | @interface ASIS3Request : ASIHTTPRequest <NSCopying, NSXMLParserDelegate> { | 39 | @interface ASIS3Request : ASIHTTPRequest <NSCopying, NSXMLParserDelegate> { |
32 | 40 | ||
33 | // Your S3 access key. Set it on the request, or set it globally using [ASIS3Request setSharedAccessKey:] | 41 | // Your S3 access key. Set it on the request, or set it globally using [ASIS3Request setSharedAccessKey:] |
@@ -36,6 +44,9 @@ typedef enum _ASIS3ErrorType { | @@ -36,6 +44,9 @@ typedef enum _ASIS3ErrorType { | ||
36 | // Your S3 secret access key. Set it on the request, or set it globally using [ASIS3Request setSharedSecretAccessKey:] | 44 | // Your S3 secret access key. Set it on the request, or set it globally using [ASIS3Request setSharedSecretAccessKey:] |
37 | NSString *secretAccessKey; | 45 | NSString *secretAccessKey; |
38 | 46 | ||
47 | + // Set to ASIS3RequestSchemeHTTPS to send your requests via HTTPS (default is ASIS3RequestSchemeHTTP) | ||
48 | + NSString *requestScheme; | ||
49 | + | ||
39 | // The string that will be used in the HTTP date header. Generally you'll want to ignore this and let the class add the current date for you, but the accessor is used by the tests | 50 | // The string that will be used in the HTTP date header. Generally you'll want to ignore this and let the class add the current date for you, but the accessor is used by the tests |
40 | NSString *dateString; | 51 | NSString *dateString; |
41 | 52 | ||
@@ -68,7 +79,7 @@ typedef enum _ASIS3ErrorType { | @@ -68,7 +79,7 @@ typedef enum _ASIS3ErrorType { | ||
68 | + (void)setSharedAccessKey:(NSString *)newAccessKey; | 79 | + (void)setSharedAccessKey:(NSString *)newAccessKey; |
69 | + (NSString *)sharedSecretAccessKey; | 80 | + (NSString *)sharedSecretAccessKey; |
70 | + (void)setSharedSecretAccessKey:(NSString *)newAccessKey; | 81 | + (void)setSharedSecretAccessKey:(NSString *)newAccessKey; |
71 | - | 82 | + |
72 | # pragma mark helpers | 83 | # pragma mark helpers |
73 | 84 | ||
74 | // Returns a date formatter than can be used to parse a date from S3 | 85 | // Returns a date formatter than can be used to parse a date from S3 |
@@ -82,7 +93,11 @@ typedef enum _ASIS3ErrorType { | @@ -82,7 +93,11 @@ typedef enum _ASIS3ErrorType { | ||
82 | // You shouldn't normally need to use this yourself | 93 | // You shouldn't normally need to use this yourself |
83 | + (NSString *)stringByURLEncodingForS3Path:(NSString *)key; | 94 | + (NSString *)stringByURLEncodingForS3Path:(NSString *)key; |
84 | 95 | ||
96 | +// Returns a string for the hostname used for S3 requests. You shouldn't ever need to change this. | ||
97 | ++ (NSString *)S3Host; | ||
85 | 98 | ||
99 | +// This is called automatically before the request starts to build the request URL (if one has not been manually set already) | ||
100 | +- (void)buildURL; | ||
86 | 101 | ||
87 | @property (retain) NSString *dateString; | 102 | @property (retain) NSString *dateString; |
88 | @property (retain) NSString *accessKey; | 103 | @property (retain) NSString *accessKey; |
@@ -90,4 +105,5 @@ typedef enum _ASIS3ErrorType { | @@ -90,4 +105,5 @@ typedef enum _ASIS3ErrorType { | ||
90 | @property (retain) NSString *accessPolicy; | 105 | @property (retain) NSString *accessPolicy; |
91 | @property (retain) NSString *currentXMLElementContent; | 106 | @property (retain) NSString *currentXMLElementContent; |
92 | @property (retain) NSMutableArray *currentXMLElementStack; | 107 | @property (retain) NSMutableArray *currentXMLElementStack; |
108 | +@property (retain) NSString *requestScheme; | ||
93 | @end | 109 | @end |
@@ -9,10 +9,15 @@ | @@ -9,10 +9,15 @@ | ||
9 | #import "ASIS3Request.h" | 9 | #import "ASIS3Request.h" |
10 | #import <CommonCrypto/CommonHMAC.h> | 10 | #import <CommonCrypto/CommonHMAC.h> |
11 | 11 | ||
12 | -NSString* const ASIS3AccessPolicyPrivate = @"private"; | 12 | +NSString *const ASIS3AccessPolicyPrivate = @"private"; |
13 | -NSString* const ASIS3AccessPolicyPublicRead = @"public-read"; | 13 | +NSString *const ASIS3AccessPolicyPublicRead = @"public-read"; |
14 | -NSString* const ASIS3AccessPolicyPublicReadWrote = @"public-read-write"; | 14 | +NSString *const ASIS3AccessPolicyPublicReadWrite = @"public-read-write"; |
15 | -NSString* const ASIS3AccessPolicyAuthenticatedRead = @"authenticated-read"; | 15 | +NSString *const ASIS3AccessPolicyAuthenticatedRead = @"authenticated-read"; |
16 | +NSString *const ASIS3AccessPolicyBucketOwnerRead = @"bucket-owner-read"; | ||
17 | +NSString *const ASIS3AccessPolicyBucketOwnerFullControl = @"bucket-owner-full-control"; | ||
18 | + | ||
19 | +NSString *const ASIS3RequestSchemeHTTP = @"http"; | ||
20 | +NSString *const ASIS3RequestSchemeHTTPS = @"https"; | ||
16 | 21 | ||
17 | static NSString *sharedAccessKey = nil; | 22 | static NSString *sharedAccessKey = nil; |
18 | static NSString *sharedSecretAccessKey = nil; | 23 | static NSString *sharedSecretAccessKey = nil; |
@@ -29,6 +34,7 @@ static NSString *sharedSecretAccessKey = nil; | @@ -29,6 +34,7 @@ static NSString *sharedSecretAccessKey = nil; | ||
29 | self = [super initWithURL:newURL]; | 34 | self = [super initWithURL:newURL]; |
30 | // After a bit of experimentation/guesswork, this number seems to reduce the chance of a 'RequestTimeout' error | 35 | // After a bit of experimentation/guesswork, this number seems to reduce the chance of a 'RequestTimeout' error |
31 | [self setPersistentConnectionTimeoutSeconds:20]; | 36 | [self setPersistentConnectionTimeoutSeconds:20]; |
37 | + [self setRequestScheme:ASIS3RequestSchemeHTTP]; | ||
32 | return self; | 38 | return self; |
33 | } | 39 | } |
34 | 40 | ||
@@ -41,6 +47,7 @@ static NSString *sharedSecretAccessKey = nil; | @@ -41,6 +47,7 @@ static NSString *sharedSecretAccessKey = nil; | ||
41 | [accessKey release]; | 47 | [accessKey release]; |
42 | [secretAccessKey release]; | 48 | [secretAccessKey release]; |
43 | [accessPolicy release]; | 49 | [accessPolicy release]; |
50 | + [requestScheme release]; | ||
44 | [super dealloc]; | 51 | [super dealloc]; |
45 | } | 52 | } |
46 | 53 | ||
@@ -67,6 +74,14 @@ static NSString *sharedSecretAccessKey = nil; | @@ -67,6 +74,14 @@ static NSString *sharedSecretAccessKey = nil; | ||
67 | return headers; | 74 | return headers; |
68 | } | 75 | } |
69 | 76 | ||
77 | +- (void)main | ||
78 | +{ | ||
79 | + if (![self url]) { | ||
80 | + [self buildURL]; | ||
81 | + } | ||
82 | + [super main]; | ||
83 | +} | ||
84 | + | ||
70 | - (NSString *)canonicalizedResource | 85 | - (NSString *)canonicalizedResource |
71 | { | 86 | { |
72 | return @"/"; | 87 | return @"/"; |
@@ -79,6 +94,9 @@ static NSString *sharedSecretAccessKey = nil; | @@ -79,6 +94,9 @@ static NSString *sharedSecretAccessKey = nil; | ||
79 | 94 | ||
80 | - (void)buildRequestHeaders | 95 | - (void)buildRequestHeaders |
81 | { | 96 | { |
97 | + if (![self url]) { | ||
98 | + [self buildURL]; | ||
99 | + } | ||
82 | [super buildRequestHeaders]; | 100 | [super buildRequestHeaders]; |
83 | 101 | ||
84 | // If an access key / secret access key haven't been set for this request, let's use the shared keys | 102 | // If an access key / secret access key haven't been set for this request, let's use the shared keys |
@@ -100,7 +118,7 @@ static NSString *sharedSecretAccessKey = nil; | @@ -100,7 +118,7 @@ static NSString *sharedSecretAccessKey = nil; | ||
100 | // Add a header for the access policy if one was set, otherwise we won't add one (and S3 will default to private) | 118 | // Add a header for the access policy if one was set, otherwise we won't add one (and S3 will default to private) |
101 | NSMutableDictionary *amzHeaders = [self S3Headers]; | 119 | NSMutableDictionary *amzHeaders = [self S3Headers]; |
102 | NSString *canonicalizedAmzHeaders = @""; | 120 | NSString *canonicalizedAmzHeaders = @""; |
103 | - for (NSString *header in [amzHeaders keyEnumerator]) { | 121 | + for (NSString *header in [amzHeaders keysSortedByValueUsingSelector:@selector(compare:)]) { |
104 | canonicalizedAmzHeaders = [NSString stringWithFormat:@"%@%@:%@\n",canonicalizedAmzHeaders,[header lowercaseString],[amzHeaders objectForKey:header]]; | 122 | canonicalizedAmzHeaders = [NSString stringWithFormat:@"%@%@:%@\n",canonicalizedAmzHeaders,[header lowercaseString],[amzHeaders objectForKey:header]]; |
105 | [self addRequestHeader:header value:[amzHeaders objectForKey:header]]; | 123 | [self addRequestHeader:header value:[amzHeaders objectForKey:header]]; |
106 | } | 124 | } |
@@ -274,6 +292,14 @@ static NSString *sharedSecretAccessKey = nil; | @@ -274,6 +292,14 @@ static NSString *sharedSecretAccessKey = nil; | ||
274 | return [NSData dataWithBytes:digest length:CC_SHA1_DIGEST_LENGTH]; | 292 | return [NSData dataWithBytes:digest length:CC_SHA1_DIGEST_LENGTH]; |
275 | } | 293 | } |
276 | 294 | ||
295 | ++ (NSString *)S3Host | ||
296 | +{ | ||
297 | + return @"s3.amazonaws.com"; | ||
298 | +} | ||
299 | + | ||
300 | +- (void)buildURL | ||
301 | +{ | ||
302 | +} | ||
277 | 303 | ||
278 | @synthesize dateString; | 304 | @synthesize dateString; |
279 | @synthesize accessKey; | 305 | @synthesize accessKey; |
@@ -281,4 +307,5 @@ static NSString *sharedSecretAccessKey = nil; | @@ -281,4 +307,5 @@ static NSString *sharedSecretAccessKey = nil; | ||
281 | @synthesize currentXMLElementContent; | 307 | @synthesize currentXMLElementContent; |
282 | @synthesize currentXMLElementStack; | 308 | @synthesize currentXMLElementStack; |
283 | @synthesize accessPolicy; | 309 | @synthesize accessPolicy; |
310 | +@synthesize requestScheme; | ||
284 | @end | 311 | @end |
@@ -21,10 +21,10 @@ | @@ -21,10 +21,10 @@ | ||
21 | 21 | ||
22 | + (id)serviceRequest | 22 | + (id)serviceRequest |
23 | { | 23 | { |
24 | - return [[[self alloc] initWithURL:[NSURL URLWithString:@"http://s3.amazonaws.com"]] autorelease]; | 24 | + ASIS3ServiceRequest *request = [[[self alloc] initWithURL:nil] autorelease]; |
25 | + return request; | ||
25 | } | 26 | } |
26 | 27 | ||
27 | - | ||
28 | - (id)initWithURL:(NSURL *)newURL | 28 | - (id)initWithURL:(NSURL *)newURL |
29 | { | 29 | { |
30 | self = [super initWithURL:newURL]; | 30 | self = [super initWithURL:newURL]; |
@@ -32,7 +32,6 @@ | @@ -32,7 +32,6 @@ | ||
32 | return self; | 32 | return self; |
33 | } | 33 | } |
34 | 34 | ||
35 | - | ||
36 | - (void)dealloc | 35 | - (void)dealloc |
37 | { | 36 | { |
38 | [buckets release]; | 37 | [buckets release]; |
@@ -42,6 +41,11 @@ | @@ -42,6 +41,11 @@ | ||
42 | [super dealloc]; | 41 | [super dealloc]; |
43 | } | 42 | } |
44 | 43 | ||
44 | +- (void)buildURL | ||
45 | +{ | ||
46 | + [self setURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@://%@",[self requestScheme],[[self class] S3Host]]]]; | ||
47 | +} | ||
48 | + | ||
45 | - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict | 49 | - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict |
46 | { | 50 | { |
47 | if ([elementName isEqualToString:@"Bucket"]) { | 51 | if ([elementName isEqualToString:@"Bucket"]) { |
@@ -21,6 +21,8 @@ | @@ -21,6 +21,8 @@ | ||
21 | - (void)testListRequest; | 21 | - (void)testListRequest; |
22 | - (void)testSubclasses; | 22 | - (void)testSubclasses; |
23 | - (void)createTestBucket; | 23 | - (void)createTestBucket; |
24 | +- (void)testCopy; | ||
25 | +- (void)testHTTPS; | ||
24 | 26 | ||
25 | @property (retain,nonatomic) ASINetworkQueue *networkQueue; | 27 | @property (retain,nonatomic) ASINetworkQueue *networkQueue; |
26 | @end | 28 | @end |
@@ -20,8 +20,6 @@ static NSString *accessKey = @""; | @@ -20,8 +20,6 @@ static NSString *accessKey = @""; | ||
20 | // You should run these tests on a bucket that does not yet exist | 20 | // You should run these tests on a bucket that does not yet exist |
21 | static NSString *bucket = @""; | 21 | static NSString *bucket = @""; |
22 | 22 | ||
23 | - | ||
24 | - | ||
25 | // Used for subclass test | 23 | // Used for subclass test |
26 | @interface ASIS3ObjectRequestSubclass : ASIS3ObjectRequest {} | 24 | @interface ASIS3ObjectRequestSubclass : ASIS3ObjectRequest {} |
27 | @end | 25 | @end |
@@ -220,6 +218,7 @@ static NSString *bucket = @""; | @@ -220,6 +218,7 @@ static NSString *bucket = @""; | ||
220 | ASIS3ObjectRequest *request = [ASIS3ObjectRequest PUTRequestForFile:filePath withBucket:bucket key:key]; | 218 | ASIS3ObjectRequest *request = [ASIS3ObjectRequest PUTRequestForFile:filePath withBucket:bucket key:key]; |
221 | [request setSecretAccessKey:secretAccessKey]; | 219 | [request setSecretAccessKey:secretAccessKey]; |
222 | [request setAccessKey:accessKey]; | 220 | [request setAccessKey:accessKey]; |
221 | + [request setStorageClass:ASIS3StorageClassReducedRedundancy]; | ||
223 | [request startSynchronous]; | 222 | [request startSynchronous]; |
224 | success = [[request responseString] isEqualToString:@""]; | 223 | success = [[request responseString] isEqualToString:@""]; |
225 | GHAssertTrue(success,@"Failed to PUT a file to S3"); | 224 | GHAssertTrue(success,@"Failed to PUT a file to S3"); |
@@ -452,7 +451,7 @@ static NSString *bucket = @""; | @@ -452,7 +451,7 @@ static NSString *bucket = @""; | ||
452 | [listRequest setPrefix:@"foo"]; | 451 | [listRequest setPrefix:@"foo"]; |
453 | [listRequest setMarker:@"bar"]; | 452 | [listRequest setMarker:@"bar"]; |
454 | [listRequest setMaxResultCount:5]; | 453 | [listRequest setMaxResultCount:5]; |
455 | - [listRequest createQueryString]; | 454 | + [listRequest buildURL]; |
456 | NSString *expectedURL = [NSString stringWithFormat:@"http://%@.s3.amazonaws.com/?acl&prefix=foo&marker=bar&delimiter=/&max-keys=5",bucket]; | 455 | NSString *expectedURL = [NSString stringWithFormat:@"http://%@.s3.amazonaws.com/?acl&prefix=foo&marker=bar&delimiter=/&max-keys=5",bucket]; |
457 | success = ([[[listRequest url] absoluteString] isEqualToString:expectedURL]); | 456 | success = ([[[listRequest url] absoluteString] isEqualToString:expectedURL]); |
458 | GHAssertTrue(success,@"Generated the wrong url when requesting a subresource"); | 457 | GHAssertTrue(success,@"Generated the wrong url when requesting a subresource"); |
@@ -757,6 +756,94 @@ static NSString *bucket = @""; | @@ -757,6 +756,94 @@ static NSString *bucket = @""; | ||
757 | } | 756 | } |
758 | 757 | ||
759 | 758 | ||
759 | +- (void)testHTTPS | ||
760 | +{ | ||
761 | + [ASIS3Request setSharedAccessKey:accessKey]; | ||
762 | + [ASIS3Request setSharedSecretAccessKey:secretAccessKey]; | ||
763 | + | ||
764 | + // Create a bucket | ||
765 | + ASIS3Request *request = [ASIS3BucketRequest PUTRequestWithBucket:bucket]; | ||
766 | + [request setRequestScheme:ASIS3RequestSchemeHTTPS]; | ||
767 | + [request startSynchronous]; | ||
768 | + GHAssertNil([request error],@"Failed to create a bucket"); | ||
769 | + | ||
770 | + // PUT something in it | ||
771 | + NSString *key = @"king"; | ||
772 | + request = [ASIS3ObjectRequest PUTRequestForData:[@"fink" dataUsingEncoding:NSUTF8StringEncoding] withBucket:bucket key:key]; | ||
773 | + [request setRequestScheme:ASIS3RequestSchemeHTTPS]; | ||
774 | + [request startSynchronous]; | ||
775 | + BOOL success = [[request responseString] isEqualToString:@""]; | ||
776 | + GHAssertTrue(success,@"Failed to PUT some data into S3"); | ||
777 | + | ||
778 | + // GET it | ||
779 | + request = [ASIS3ObjectRequest requestWithBucket:bucket key:key]; | ||
780 | + [request setRequestScheme:ASIS3RequestSchemeHTTPS]; | ||
781 | + [request startSynchronous]; | ||
782 | + success = [[request responseString] isEqualToString:@"fink"]; | ||
783 | + GHAssertTrue(success,@"Failed to GET the correct data from S3"); | ||
784 | + | ||
785 | + // DELETE it | ||
786 | + request = [ASIS3ObjectRequest DELETERequestWithBucket:bucket key:@"king"]; | ||
787 | + [request setRequestScheme:ASIS3RequestSchemeHTTPS]; | ||
788 | + [request startSynchronous]; | ||
789 | + success = [[request responseString] isEqualToString:@""]; | ||
790 | + GHAssertTrue(success,@"Failed to DELETE the object from S3"); | ||
791 | + | ||
792 | + // Delete the bucket | ||
793 | + request = [ASIS3BucketRequest DELETERequestWithBucket:bucket]; | ||
794 | + [request setRequestScheme:ASIS3RequestSchemeHTTPS]; | ||
795 | + [request startSynchronous]; | ||
796 | + GHAssertNil([request error],@"Failed to delete a bucket"); | ||
797 | + | ||
798 | + [ASIS3Request setSharedAccessKey:nil]; | ||
799 | + [ASIS3Request setSharedSecretAccessKey:nil]; | ||
800 | +} | ||
801 | + | ||
802 | +// Ideally this test would actually parse the ACL XML and check it, but for now it just makes sure S3 doesn't return an error | ||
803 | +- (void)testCannedACLs | ||
804 | +{ | ||
805 | + [ASIS3Request setSharedAccessKey:accessKey]; | ||
806 | + [ASIS3Request setSharedSecretAccessKey:secretAccessKey]; | ||
807 | + | ||
808 | + // Create a bucket | ||
809 | + ASIS3Request *request = [ASIS3BucketRequest PUTRequestWithBucket:bucket]; | ||
810 | + [request setRequestScheme:ASIS3RequestSchemeHTTPS]; | ||
811 | + [request startSynchronous]; | ||
812 | + GHAssertNil([request error],@"Failed to create a bucket"); | ||
813 | + | ||
814 | + NSArray *ACLs = [NSArray arrayWithObjects:ASIS3AccessPolicyPrivate,ASIS3AccessPolicyPublicRead,ASIS3AccessPolicyPublicReadWrite,ASIS3AccessPolicyAuthenticatedRead,ASIS3AccessPolicyBucketOwnerRead,ASIS3AccessPolicyBucketOwnerFullControl,nil]; | ||
815 | + | ||
816 | + for (NSString *cannedACL in ACLs) { | ||
817 | + // PUT object | ||
818 | + NSString *key = @"king"; | ||
819 | + request = [ASIS3ObjectRequest PUTRequestForData:[@"fink" dataUsingEncoding:NSUTF8StringEncoding] withBucket:bucket key:key]; | ||
820 | + [request setAccessPolicy:cannedACL]; | ||
821 | + [request startSynchronous]; | ||
822 | + GHAssertNil([request error],@"Failed to PUT some data into S3"); | ||
823 | + | ||
824 | + // GET object ACL | ||
825 | + request = [ASIS3ObjectRequest requestWithBucket:bucket key:key subResource:@"acl"]; | ||
826 | + [request startSynchronous]; | ||
827 | + GHAssertNil([request error],@"Failed to fetch the object"); | ||
828 | + } | ||
829 | + | ||
830 | + // DELETE it | ||
831 | + request = [ASIS3ObjectRequest DELETERequestWithBucket:bucket key:@"king"]; | ||
832 | + [request setRequestScheme:ASIS3RequestSchemeHTTPS]; | ||
833 | + [request startSynchronous]; | ||
834 | + BOOL success = [[request responseString] isEqualToString:@""]; | ||
835 | + GHAssertTrue(success,@"Failed to DELETE the object from S3"); | ||
836 | + | ||
837 | + // Delete the bucket | ||
838 | + request = [ASIS3BucketRequest DELETERequestWithBucket:bucket]; | ||
839 | + [request setRequestScheme:ASIS3RequestSchemeHTTPS]; | ||
840 | + [request startSynchronous]; | ||
841 | + GHAssertNil([request error],@"Failed to delete a bucket"); | ||
842 | + | ||
843 | + [ASIS3Request setSharedAccessKey:nil]; | ||
844 | + [ASIS3Request setSharedSecretAccessKey:nil]; | ||
845 | +} | ||
846 | + | ||
760 | 847 | ||
761 | @synthesize networkQueue; | 848 | @synthesize networkQueue; |
762 | 849 |
-
Please register or login to post a comment