Minor refactor / cleanup on S3 API:
Have all ASIS3Request subclasses parse the xml response in request finished - cuts out quite a bit of duplication Service and bucket requests now correctly parse error message xml Fixes to query string generation for bucket requests Keep track of the current element stack so we can correctly parse common prefixes Fix a couple of leaked objects Add new tests for issues raised by Tom Andersen in his patch + email
Showing
10 changed files
with
174 additions
and
148 deletions
| @@ -23,7 +23,7 @@ | @@ -23,7 +23,7 @@ | ||
| 23 | 23 | ||
| 24 | 24 | ||
| 25 | // Automatically set on build | 25 | // Automatically set on build |
| 26 | -NSString *ASIHTTPRequestVersion = @"v1.6.1-6 2010-04-12"; | 26 | +NSString *ASIHTTPRequestVersion = @"v1.6.1-8 2010-04-12"; |
| 27 | 27 | ||
| 28 | NSString* const NetworkRequestErrorDomain = @"ASIHTTPRequestErrorDomain"; | 28 | NSString* const NetworkRequestErrorDomain = @"ASIHTTPRequestErrorDomain"; |
| 29 | 29 |
| @@ -29,12 +29,15 @@ | @@ -29,12 +29,15 @@ | ||
| 29 | NSString *delimiter; | 29 | NSString *delimiter; |
| 30 | 30 | ||
| 31 | // Internally used while parsing the response | 31 | // Internally used while parsing the response |
| 32 | - NSString *currentContent; | ||
| 33 | - NSString *currentElement; | ||
| 34 | ASIS3BucketObject *currentObject; | 32 | ASIS3BucketObject *currentObject; |
| 33 | + | ||
| 34 | + // Returns an array of ASIS3BucketObjects created from the XML response | ||
| 35 | NSMutableArray *objects; | 35 | NSMutableArray *objects; |
| 36 | 36 | ||
| 37 | - NSMutableArray* foundFolders; | 37 | + // Will be populated with a list of 'folders' when a delimiter is set |
| 38 | + NSMutableArray *commonPrefixes; | ||
| 39 | + | ||
| 40 | + // Will be true if this request did not return all the results matching the query (use maxResultCount to configure the number of results to return) | ||
| 38 | BOOL isTruncated; | 41 | BOOL isTruncated; |
| 39 | } | 42 | } |
| 40 | 43 | ||
| @@ -57,12 +60,6 @@ | @@ -57,12 +60,6 @@ | ||
| 57 | // 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 |
| 58 | + (id)DELETERequestWithBucket:(NSString *)bucket; | 61 | + (id)DELETERequestWithBucket:(NSString *)bucket; |
| 59 | 62 | ||
| 60 | -// Returns an array of ASIS3BucketObjects created from the XML response | ||
| 61 | -- (NSArray *)bucketObjects; | ||
| 62 | - | ||
| 63 | -// prefixes are like folders - get them by setting a delimiter string (usually always @"/") | ||
| 64 | --(NSArray*)commonPrefixes; | ||
| 65 | - | ||
| 66 | //Builds a query string out of the list parameters we supplied | 63 | //Builds a query string out of the list parameters we supplied |
| 67 | - (void)createQueryString; | 64 | - (void)createQueryString; |
| 68 | 65 | ||
| @@ -72,5 +69,7 @@ | @@ -72,5 +69,7 @@ | ||
| 72 | @property (retain) NSString *marker; | 69 | @property (retain) NSString *marker; |
| 73 | @property (assign) int maxResultCount; | 70 | @property (assign) int maxResultCount; |
| 74 | @property (retain) NSString *delimiter; | 71 | @property (retain) NSString *delimiter; |
| 75 | -@property (readonly) BOOL isTruncated; | 72 | +@property (retain, readonly) NSMutableArray *objects; |
| 73 | +@property (retain, readonly) NSMutableArray *commonPrefixes; | ||
| 74 | +@property (assign, readonly) BOOL isTruncated; | ||
| 76 | @end | 75 | @end |
| @@ -12,16 +12,24 @@ | @@ -12,16 +12,24 @@ | ||
| 12 | 12 | ||
| 13 | // Private stuff | 13 | // Private stuff |
| 14 | @interface ASIS3BucketRequest () | 14 | @interface ASIS3BucketRequest () |
| 15 | -@property (retain, nonatomic) NSString *currentContent; | ||
| 16 | -@property (retain, nonatomic) NSString *currentElement; | ||
| 17 | @property (retain, nonatomic) ASIS3BucketObject *currentObject; | 15 | @property (retain, nonatomic) ASIS3BucketObject *currentObject; |
| 18 | -@property (retain, nonatomic) NSMutableArray *objects; | 16 | +@property (retain, nonatomic) NSString *currentXMLElementContent; |
| 19 | -@property (retain, nonatomic) NSMutableArray *foundFolders; | 17 | +@property (retain, nonatomic) NSMutableArray *currentXMLElementStack; |
| 20 | -@property (readwrite) BOOL isTruncated; | 18 | +@property (retain) NSMutableArray *objects; |
| 19 | +@property (retain) NSMutableArray *commonPrefixes; | ||
| 20 | +@property (assign) BOOL isTruncated; | ||
| 21 | @end | 21 | @end |
| 22 | 22 | ||
| 23 | @implementation ASIS3BucketRequest | 23 | @implementation ASIS3BucketRequest |
| 24 | 24 | ||
| 25 | +- (id)initWithURL:(NSURL *)newURL | ||
| 26 | +{ | ||
| 27 | + self = [super initWithURL:newURL]; | ||
| 28 | + [self setObjects:[[[NSMutableArray alloc] init] autorelease]]; | ||
| 29 | + [self setCommonPrefixes:[[[NSMutableArray alloc] init] autorelease]]; | ||
| 30 | + return self; | ||
| 31 | +} | ||
| 32 | + | ||
| 25 | + (id)requestWithBucket:(NSString *)bucket | 33 | + (id)requestWithBucket:(NSString *)bucket |
| 26 | { | 34 | { |
| 27 | ASIS3ObjectRequest *request = [[[self alloc] initWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://%@.s3.amazonaws.com",bucket]]] autorelease]; | 35 | ASIS3ObjectRequest *request = [[[self alloc] initWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://%@.s3.amazonaws.com",bucket]]] autorelease]; |
| @@ -56,10 +64,8 @@ | @@ -56,10 +64,8 @@ | ||
| 56 | - (void)dealloc | 64 | - (void)dealloc |
| 57 | { | 65 | { |
| 58 | [currentObject release]; | 66 | [currentObject release]; |
| 59 | - [currentElement release]; | ||
| 60 | - [currentContent release]; | ||
| 61 | [objects release]; | 67 | [objects release]; |
| 62 | - [foundFolders release]; | 68 | + [commonPrefixes release]; |
| 63 | [prefix release]; | 69 | [prefix release]; |
| 64 | [marker release]; | 70 | [marker release]; |
| 65 | [delimiter release]; | 71 | [delimiter release]; |
| @@ -83,19 +89,20 @@ | @@ -83,19 +89,20 @@ | ||
| 83 | [queryParts addObject:[NSString stringWithFormat:@"prefix=%@",[[self prefix] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]]; | 89 | [queryParts addObject:[NSString stringWithFormat:@"prefix=%@",[[self prefix] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]]; |
| 84 | } | 90 | } |
| 85 | if ([self marker]) { | 91 | if ([self marker]) { |
| 86 | - [queryParts addObject:[NSString stringWithFormat:@"marker=%@",[[self marker] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]]; | 92 | + [queryParts addObject:[NSString stringWithFormat:@"key-marker=%@",[[self marker] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]]; |
| 87 | } | 93 | } |
| 88 | if ([self delimiter]) { | 94 | if ([self delimiter]) { |
| 89 | [queryParts addObject:[NSString stringWithFormat:@"delimiter=%@",[[self delimiter] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]]; | 95 | [queryParts addObject:[NSString stringWithFormat:@"delimiter=%@",[[self delimiter] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]]; |
| 90 | } | 96 | } |
| 91 | if ([self maxResultCount] > 0) { | 97 | if ([self maxResultCount] > 0) { |
| 92 | - [queryParts addObject:[NSString stringWithFormat:@"delimiter=%hi",[self maxResultCount]]]; | 98 | + [queryParts addObject:[NSString stringWithFormat:@"max-keys=%hi",[self maxResultCount]]]; |
| 93 | } | 99 | } |
| 94 | if ([queryParts count]) | 100 | if ([queryParts count]) |
| 95 | { | 101 | { |
| 96 | NSString* template = @"%@?%@"; | 102 | NSString* template = @"%@?%@"; |
| 97 | - if ([self.subResource length] > 0) | 103 | + if ([[self subResource] length] > 0) { |
| 98 | - template = @"%@&%@"; | 104 | + template = @"%@&%@"; |
| 105 | + } | ||
| 99 | [self setURL:[NSURL URLWithString:[NSString stringWithFormat:template,[[self url] absoluteString],[queryParts componentsJoinedByString:@"&"]]]]; | 106 | [self setURL:[NSURL URLWithString:[NSString stringWithFormat:template,[[self url] absoluteString],[queryParts componentsJoinedByString:@"&"]]]]; |
| 100 | } | 107 | } |
| 101 | } | 108 | } |
| @@ -106,44 +113,12 @@ | @@ -106,44 +113,12 @@ | ||
| 106 | [super main]; | 113 | [super main]; |
| 107 | } | 114 | } |
| 108 | 115 | ||
| 109 | --(void)makeBucketsAndPrefixes; | ||
| 110 | -{ | ||
| 111 | - [self setObjects:[[[NSMutableArray alloc] init] autorelease]]; | ||
| 112 | - [self setFoundFolders:[[[NSMutableArray alloc] init] autorelease]]; | ||
| 113 | - NSXMLParser *parser = [[[NSXMLParser alloc] initWithData:[self responseData]] autorelease]; | ||
| 114 | - [parser setDelegate:self]; | ||
| 115 | - [parser setShouldProcessNamespaces:NO]; | ||
| 116 | - [parser setShouldReportNamespacePrefixes:NO]; | ||
| 117 | - [parser setShouldResolveExternalEntities:NO]; | ||
| 118 | - [parser parse]; | ||
| 119 | -} | ||
| 120 | - | ||
| 121 | -- (NSArray *)bucketObjects | ||
| 122 | -{ | ||
| 123 | - if ([self objects]) { | ||
| 124 | - return [self objects]; | ||
| 125 | - } | ||
| 126 | - [self makeBucketsAndPrefixes]; | ||
| 127 | - return [self objects]; | ||
| 128 | -} | ||
| 129 | - | ||
| 130 | --(NSArray*)commonPrefixes; | ||
| 131 | -{ | ||
| 132 | - if ([self foundFolders]) { | ||
| 133 | - return [self foundFolders]; | ||
| 134 | - } | ||
| 135 | - [self makeBucketsAndPrefixes]; | ||
| 136 | - return [self foundFolders]; | ||
| 137 | -} | ||
| 138 | - | ||
| 139 | - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict | 116 | - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict |
| 140 | { | 117 | { |
| 141 | - [self setCurrentElement:elementName]; | ||
| 142 | - | ||
| 143 | if ([elementName isEqualToString:@"Contents"]) { | 118 | if ([elementName isEqualToString:@"Contents"]) { |
| 144 | [self setCurrentObject:[ASIS3BucketObject objectWithBucket:[self bucket]]]; | 119 | [self setCurrentObject:[ASIS3BucketObject objectWithBucket:[self bucket]]]; |
| 145 | } | 120 | } |
| 146 | - [self setCurrentContent:@""]; | 121 | + [super parser:parser didStartElement:elementName namespaceURI:namespaceURI qualifiedName:qName attributes:attributeDict]; |
| 147 | } | 122 | } |
| 148 | 123 | ||
| 149 | - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName | 124 | - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName |
| @@ -152,27 +127,27 @@ | @@ -152,27 +127,27 @@ | ||
| 152 | [objects addObject:currentObject]; | 127 | [objects addObject:currentObject]; |
| 153 | [self setCurrentObject:nil]; | 128 | [self setCurrentObject:nil]; |
| 154 | } else if ([elementName isEqualToString:@"Key"]) { | 129 | } else if ([elementName isEqualToString:@"Key"]) { |
| 155 | - [[self currentObject] setKey:[self currentContent]]; | 130 | + [[self currentObject] setKey:[self currentXMLElementContent]]; |
| 156 | } else if ([elementName isEqualToString:@"LastModified"]) { | 131 | } else if ([elementName isEqualToString:@"LastModified"]) { |
| 157 | - [[self currentObject] setLastModified:[[ASIS3Request dateFormatter] dateFromString:[self currentContent]]]; | 132 | + [[self currentObject] setLastModified:[[ASIS3Request dateFormatter] dateFromString:[self currentXMLElementContent]]]; |
| 158 | } else if ([elementName isEqualToString:@"ETag"]) { | 133 | } else if ([elementName isEqualToString:@"ETag"]) { |
| 159 | - [[self currentObject] setETag:[self currentContent]]; | 134 | + [[self currentObject] setETag:[self currentXMLElementContent]]; |
| 160 | } else if ([elementName isEqualToString:@"Size"]) { | 135 | } else if ([elementName isEqualToString:@"Size"]) { |
| 161 | - [[self currentObject] setSize:(unsigned long long)[[self currentContent] longLongValue]]; | 136 | + [[self currentObject] setSize:(unsigned long long)[[self currentXMLElementContent] longLongValue]]; |
| 162 | } else if ([elementName isEqualToString:@"ID"]) { | 137 | } else if ([elementName isEqualToString:@"ID"]) { |
| 163 | - [[self currentObject] setOwnerID:[self currentContent]]; | 138 | + [[self currentObject] setOwnerID:[self currentXMLElementContent]]; |
| 164 | } else if ([elementName isEqualToString:@"DisplayName"]) { | 139 | } else if ([elementName isEqualToString:@"DisplayName"]) { |
| 165 | - [[self currentObject] setOwnerName:[self currentContent]]; | 140 | + [[self currentObject] setOwnerName:[self currentXMLElementContent]]; |
| 166 | - } else if ([elementName isEqualToString:@"Prefix"]) { | 141 | + } else if ([elementName isEqualToString:@"Prefix"] && [[self currentXMLElementStack] count] > 2 && [[[self currentXMLElementStack] objectAtIndex:[[self currentXMLElementStack] count]-2] isEqualToString:@"CommonPrefixes"]) { |
| 167 | - [foundFolders addObject:[NSString stringWithString:[self currentContent]]]; | 142 | + [[self commonPrefixes] addObject:[self currentXMLElementContent]]; |
| 168 | } else if ([elementName isEqualToString:@"IsTruncated"]) { | 143 | } else if ([elementName isEqualToString:@"IsTruncated"]) { |
| 169 | - self.isTruncated = [[NSString stringWithString:[self currentContent]] boolValue]; | 144 | + [self setIsTruncated:[[self currentXMLElementContent] isEqualToString:@"true"]]; |
| 145 | + } else { | ||
| 146 | + // Let ASIS3Request look for error messages | ||
| 147 | + [super parser:parser didEndElement:elementName namespaceURI:namespaceURI qualifiedName:qName]; | ||
| 170 | } | 148 | } |
| 171 | } | 149 | } |
| 172 | -- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string | 150 | + |
| 173 | -{ | ||
| 174 | - [self setCurrentContent:[[self currentContent] stringByAppendingString:string]]; | ||
| 175 | -} | ||
| 176 | 151 | ||
| 177 | #pragma mark NSCopying | 152 | #pragma mark NSCopying |
| 178 | 153 | ||
| @@ -188,17 +163,19 @@ | @@ -188,17 +163,19 @@ | ||
| 188 | return newRequest; | 163 | return newRequest; |
| 189 | } | 164 | } |
| 190 | 165 | ||
| 166 | + | ||
| 167 | + | ||
| 168 | + | ||
| 191 | @synthesize bucket; | 169 | @synthesize bucket; |
| 192 | @synthesize subResource; | 170 | @synthesize subResource; |
| 193 | -@synthesize currentContent; | ||
| 194 | -@synthesize currentElement; | ||
| 195 | @synthesize currentObject; | 171 | @synthesize currentObject; |
| 196 | @synthesize objects; | 172 | @synthesize objects; |
| 197 | -@synthesize foundFolders; | 173 | +@synthesize commonPrefixes; |
| 198 | @synthesize prefix; | 174 | @synthesize prefix; |
| 199 | @synthesize marker; | 175 | @synthesize marker; |
| 200 | @synthesize maxResultCount; | 176 | @synthesize maxResultCount; |
| 201 | @synthesize delimiter; | 177 | @synthesize delimiter; |
| 202 | @synthesize isTruncated; | 178 | @synthesize isTruncated; |
| 203 | - | 179 | +@synthesize currentXMLElementContent; |
| 180 | +@synthesize currentXMLElementStack; | ||
| 204 | @end | 181 | @end |
| @@ -112,16 +112,6 @@ | @@ -112,16 +112,6 @@ | ||
| 112 | } | 112 | } |
| 113 | } | 113 | } |
| 114 | 114 | ||
| 115 | -- (void)requestFinished | ||
| 116 | -{ | ||
| 117 | - // COPY requests return a 200 whether they succeed or fail, so we need to look at the XML to see if we were successful. | ||
| 118 | - if ([self responseStatusCode] == 200 && [self sourceKey] && [self sourceBucket]) { | ||
| 119 | - [self parseResponseXML]; | ||
| 120 | - return; | ||
| 121 | - } | ||
| 122 | - [super requestFinished]; | ||
| 123 | -} | ||
| 124 | - | ||
| 125 | - (NSString *)canonicalizedResource | 115 | - (NSString *)canonicalizedResource |
| 126 | { | 116 | { |
| 127 | return [NSString stringWithFormat:@"/%@%@",[self bucket],[ASIS3Request stringByURLEncodingForS3Path:[self key]]]; | 117 | return [NSString stringWithFormat:@"/%@%@",[self bucket],[ASIS3Request stringByURLEncodingForS3Path:[self key]]]; |
| @@ -147,6 +137,7 @@ | @@ -147,6 +137,7 @@ | ||
| 147 | } | 137 | } |
| 148 | 138 | ||
| 149 | 139 | ||
| 140 | + | ||
| 150 | @synthesize bucket; | 141 | @synthesize bucket; |
| 151 | @synthesize key; | 142 | @synthesize key; |
| 152 | @synthesize sourceBucket; | 143 | @synthesize sourceBucket; |
| @@ -42,7 +42,8 @@ typedef enum _ASIS3ErrorType { | @@ -42,7 +42,8 @@ typedef enum _ASIS3ErrorType { | ||
| 42 | NSString *accessPolicy; | 42 | NSString *accessPolicy; |
| 43 | 43 | ||
| 44 | // Internally used while parsing errors | 44 | // Internally used while parsing errors |
| 45 | - NSString *currentErrorString; | 45 | + NSString *currentXMLElementContent; |
| 46 | + NSMutableArray *currentXMLElementStack; | ||
| 46 | } | 47 | } |
| 47 | 48 | ||
| 48 | // Uses the supplied date to create a Date header string | 49 | // Uses the supplied date to create a Date header string |
| @@ -77,7 +78,6 @@ typedef enum _ASIS3ErrorType { | @@ -77,7 +78,6 @@ typedef enum _ASIS3ErrorType { | ||
| 77 | + (NSString *)stringByURLEncodingForS3Path:(NSString *)key; | 78 | + (NSString *)stringByURLEncodingForS3Path:(NSString *)key; |
| 78 | 79 | ||
| 79 | 80 | ||
| 80 | - | ||
| 81 | @property (retain) NSString *dateString; | 81 | @property (retain) NSString *dateString; |
| 82 | @property (retain) NSString *accessKey; | 82 | @property (retain) NSString *accessKey; |
| 83 | @property (retain) NSString *secretAccessKey; | 83 | @property (retain) NSString *secretAccessKey; |
| @@ -19,12 +19,11 @@ static NSString *sharedSecretAccessKey = nil; | @@ -19,12 +19,11 @@ static NSString *sharedSecretAccessKey = nil; | ||
| 19 | 19 | ||
| 20 | static NSDateFormatter *dateFormatter = nil; | 20 | static NSDateFormatter *dateFormatter = nil; |
| 21 | 21 | ||
| 22 | - | ||
| 23 | - | ||
| 24 | // Private stuff | 22 | // Private stuff |
| 25 | @interface ASIS3Request () | 23 | @interface ASIS3Request () |
| 26 | + (NSData *)HMACSHA1withKey:(NSString *)key forString:(NSString *)string; | 24 | + (NSData *)HMACSHA1withKey:(NSString *)key forString:(NSString *)string; |
| 27 | - @property (retain, nonatomic) NSString *currentErrorString; | 25 | + @property (retain, nonatomic) NSString *currentXMLElementContent; |
| 26 | + @property (retain, nonatomic) NSMutableArray *currentXMLElementStack; | ||
| 28 | @end | 27 | @end |
| 29 | 28 | ||
| 30 | @implementation ASIS3Request | 29 | @implementation ASIS3Request |
| @@ -40,6 +39,8 @@ static NSDateFormatter *dateFormatter = nil; | @@ -40,6 +39,8 @@ static NSDateFormatter *dateFormatter = nil; | ||
| 40 | 39 | ||
| 41 | - (void)dealloc | 40 | - (void)dealloc |
| 42 | { | 41 | { |
| 42 | + [currentXMLElementContent release]; | ||
| 43 | + [currentXMLElementStack release]; | ||
| 43 | [dateString release]; | 44 | [dateString release]; |
| 44 | [accessKey release]; | 45 | [accessKey release]; |
| 45 | [secretAccessKey release]; | 46 | [secretAccessKey release]; |
| @@ -123,11 +124,12 @@ static NSDateFormatter *dateFormatter = nil; | @@ -123,11 +124,12 @@ static NSDateFormatter *dateFormatter = nil; | ||
| 123 | 124 | ||
| 124 | - (void)requestFinished | 125 | - (void)requestFinished |
| 125 | { | 126 | { |
| 126 | - if ([self responseStatusCode] < 207) { | 127 | + if ([[[self responseHeaders] objectForKey:@"Content-Type"] isEqualToString:@"application/xml"]) { |
| 128 | + [self parseResponseXML]; | ||
| 129 | + } | ||
| 130 | + if (![self error]) { | ||
| 127 | [super requestFinished]; | 131 | [super requestFinished]; |
| 128 | - return; | ||
| 129 | } | 132 | } |
| 130 | - [self parseResponseXML]; | ||
| 131 | } | 133 | } |
| 132 | 134 | ||
| 133 | #pragma mark Error XML parsing | 135 | #pragma mark Error XML parsing |
| @@ -135,6 +137,7 @@ static NSDateFormatter *dateFormatter = nil; | @@ -135,6 +137,7 @@ static NSDateFormatter *dateFormatter = nil; | ||
| 135 | - (void)parseResponseXML | 137 | - (void)parseResponseXML |
| 136 | { | 138 | { |
| 137 | NSXMLParser *parser = [[[NSXMLParser alloc] initWithData:[self responseData]] autorelease]; | 139 | NSXMLParser *parser = [[[NSXMLParser alloc] initWithData:[self responseData]] autorelease]; |
| 140 | + [self setCurrentXMLElementStack:[NSMutableArray array]]; | ||
| 138 | [parser setDelegate:self]; | 141 | [parser setDelegate:self]; |
| 139 | [parser setShouldProcessNamespaces:NO]; | 142 | [parser setShouldProcessNamespaces:NO]; |
| 140 | [parser setShouldReportNamespacePrefixes:NO]; | 143 | [parser setShouldReportNamespacePrefixes:NO]; |
| @@ -150,16 +153,18 @@ static NSDateFormatter *dateFormatter = nil; | @@ -150,16 +153,18 @@ static NSDateFormatter *dateFormatter = nil; | ||
| 150 | 153 | ||
| 151 | - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict | 154 | - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict |
| 152 | { | 155 | { |
| 153 | - [self setCurrentErrorString:@""]; | 156 | + [self setCurrentXMLElementContent:@""]; |
| 157 | + [[self currentXMLElementStack] addObject:elementName]; | ||
| 154 | } | 158 | } |
| 155 | 159 | ||
| 156 | - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName | 160 | - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName |
| 157 | { | 161 | { |
| 162 | + [[self currentXMLElementStack] removeLastObject]; | ||
| 158 | if ([elementName isEqualToString:@"Message"]) { | 163 | if ([elementName isEqualToString:@"Message"]) { |
| 159 | - [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIS3ResponseErrorType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[self currentErrorString],NSLocalizedDescriptionKey,nil]]]; | 164 | + [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIS3ResponseErrorType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[self currentXMLElementContent],NSLocalizedDescriptionKey,nil]]]; |
| 160 | // Handle S3 connection expiry errors | 165 | // Handle S3 connection expiry errors |
| 161 | } else if ([elementName isEqualToString:@"Code"]) { | 166 | } else if ([elementName isEqualToString:@"Code"]) { |
| 162 | - if ([[self currentErrorString] isEqualToString:@"RequestTimeout"]) { | 167 | + if ([[self currentXMLElementContent] isEqualToString:@"RequestTimeout"]) { |
| 163 | if ([self retryUsingNewConnection]) { | 168 | if ([self retryUsingNewConnection]) { |
| 164 | [parser abortParsing]; | 169 | [parser abortParsing]; |
| 165 | return; | 170 | return; |
| @@ -170,7 +175,7 @@ static NSDateFormatter *dateFormatter = nil; | @@ -170,7 +175,7 @@ static NSDateFormatter *dateFormatter = nil; | ||
| 170 | 175 | ||
| 171 | - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string | 176 | - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string |
| 172 | { | 177 | { |
| 173 | - [self setCurrentErrorString:[[self currentErrorString] stringByAppendingString:string]]; | 178 | + [self setCurrentXMLElementContent:[[self currentXMLElementContent] stringByAppendingString:string]]; |
| 174 | } | 179 | } |
| 175 | 180 | ||
| 176 | - (id)copyWithZone:(NSZone *)zone | 181 | - (id)copyWithZone:(NSZone *)zone |
| @@ -255,6 +260,7 @@ static NSDateFormatter *dateFormatter = nil; | @@ -255,6 +260,7 @@ static NSDateFormatter *dateFormatter = nil; | ||
| 255 | @synthesize dateString; | 260 | @synthesize dateString; |
| 256 | @synthesize accessKey; | 261 | @synthesize accessKey; |
| 257 | @synthesize secretAccessKey; | 262 | @synthesize secretAccessKey; |
| 258 | -@synthesize currentErrorString; | 263 | +@synthesize currentXMLElementContent; |
| 264 | +@synthesize currentXMLElementStack; | ||
| 259 | @synthesize accessPolicy; | 265 | @synthesize accessPolicy; |
| 260 | @end | 266 | @end |
| @@ -15,19 +15,17 @@ | @@ -15,19 +15,17 @@ | ||
| 15 | @interface ASIS3ServiceRequest : ASIS3Request { | 15 | @interface ASIS3ServiceRequest : ASIS3Request { |
| 16 | 16 | ||
| 17 | // Internally used while parsing the response | 17 | // Internally used while parsing the response |
| 18 | - NSString *currentContent; | ||
| 19 | - NSString *currentElement; | ||
| 20 | ASIS3Bucket *currentBucket; | 18 | ASIS3Bucket *currentBucket; |
| 21 | - NSMutableArray *buckets; | ||
| 22 | NSString *ownerName; | 19 | NSString *ownerName; |
| 23 | NSString *ownerID; | 20 | NSString *ownerID; |
| 21 | + | ||
| 22 | + // A list of the buckets stored on S3 for this account | ||
| 23 | + NSMutableArray *buckets; | ||
| 24 | } | 24 | } |
| 25 | 25 | ||
| 26 | // Perform a GET request on the S3 service | 26 | // Perform a GET request on the S3 service |
| 27 | // This will fetch a list of the buckets attached to the S3 account | 27 | // This will fetch a list of the buckets attached to the S3 account |
| 28 | + (id)serviceRequest; | 28 | + (id)serviceRequest; |
| 29 | 29 | ||
| 30 | -// Parse the XML response from S3, and return an array of ASIS3Bucket objects | 30 | +@property (retain, readonly) NSMutableArray *buckets; |
| 31 | -- (NSArray *)allBuckets; | ||
| 32 | - | ||
| 33 | @end | 31 | @end |
| @@ -11,12 +11,13 @@ | @@ -11,12 +11,13 @@ | ||
| 11 | 11 | ||
| 12 | // Private stuff | 12 | // Private stuff |
| 13 | @interface ASIS3ServiceRequest () | 13 | @interface ASIS3ServiceRequest () |
| 14 | -@property (retain, nonatomic) NSMutableArray *buckets; | 14 | +@property (retain) NSMutableArray *buckets; |
| 15 | -@property (retain, nonatomic) NSString *currentContent; | ||
| 16 | -@property (retain, nonatomic) NSString *currentElement; | ||
| 17 | @property (retain, nonatomic) ASIS3Bucket *currentBucket; | 15 | @property (retain, nonatomic) ASIS3Bucket *currentBucket; |
| 18 | @property (retain, nonatomic) NSString *ownerID; | 16 | @property (retain, nonatomic) NSString *ownerID; |
| 19 | @property (retain, nonatomic) NSString *ownerName; | 17 | @property (retain, nonatomic) NSString *ownerName; |
| 18 | + | ||
| 19 | +@property (retain, nonatomic) NSMutableArray *currentXMLElementStack; | ||
| 20 | +@property (retain, nonatomic) NSString *currentXMLElementContent; | ||
| 20 | @end | 21 | @end |
| 21 | 22 | ||
| 22 | @implementation ASIS3ServiceRequest | 23 | @implementation ASIS3ServiceRequest |
| @@ -26,40 +27,30 @@ | @@ -26,40 +27,30 @@ | ||
| 26 | return [[[self alloc] initWithURL:[NSURL URLWithString:@"http://s3.amazonaws.com"]] autorelease]; | 27 | return [[[self alloc] initWithURL:[NSURL URLWithString:@"http://s3.amazonaws.com"]] autorelease]; |
| 27 | } | 28 | } |
| 28 | 29 | ||
| 30 | + | ||
| 31 | +- (id)initWithURL:(NSURL *)newURL | ||
| 32 | +{ | ||
| 33 | + self = [super initWithURL:newURL]; | ||
| 34 | + [self setBuckets:[[[NSMutableArray alloc] init] autorelease]]; | ||
| 35 | + return self; | ||
| 36 | +} | ||
| 37 | + | ||
| 38 | + | ||
| 29 | - (void)dealloc | 39 | - (void)dealloc |
| 30 | { | 40 | { |
| 31 | [buckets release]; | 41 | [buckets release]; |
| 32 | - [currentContent release]; | ||
| 33 | - [currentElement release]; | ||
| 34 | [currentBucket release]; | 42 | [currentBucket release]; |
| 35 | [ownerID release]; | 43 | [ownerID release]; |
| 36 | [ownerName release]; | 44 | [ownerName release]; |
| 37 | [super dealloc]; | 45 | [super dealloc]; |
| 38 | } | 46 | } |
| 39 | 47 | ||
| 40 | -- (NSArray *)allBuckets | ||
| 41 | -{ | ||
| 42 | - if ([self buckets]) { | ||
| 43 | - return [self buckets]; | ||
| 44 | - } | ||
| 45 | - [self setBuckets:[[[NSMutableArray alloc] init] autorelease]]; | ||
| 46 | - NSXMLParser *parser = [[[NSXMLParser alloc] initWithData:[self responseData]] autorelease]; | ||
| 47 | - [parser setDelegate:self]; | ||
| 48 | - [parser setShouldProcessNamespaces:NO]; | ||
| 49 | - [parser setShouldReportNamespacePrefixes:NO]; | ||
| 50 | - [parser setShouldResolveExternalEntities:NO]; | ||
| 51 | - [parser parse]; | ||
| 52 | - return [self buckets]; | ||
| 53 | -} | ||
| 54 | - | ||
| 55 | - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict | 48 | - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict |
| 56 | { | 49 | { |
| 57 | - [self setCurrentElement:elementName]; | ||
| 58 | - | ||
| 59 | if ([elementName isEqualToString:@"Bucket"]) { | 50 | if ([elementName isEqualToString:@"Bucket"]) { |
| 60 | [self setCurrentBucket:[ASIS3Bucket bucketWithOwnerID:[self ownerID] ownerName:[self ownerName]]]; | 51 | [self setCurrentBucket:[ASIS3Bucket bucketWithOwnerID:[self ownerID] ownerName:[self ownerName]]]; |
| 61 | } | 52 | } |
| 62 | - [self setCurrentContent:@""]; | 53 | + [super parser:parser didStartElement:elementName namespaceURI:namespaceURI qualifiedName:qName attributes:attributeDict]; |
| 63 | } | 54 | } |
| 64 | 55 | ||
| 65 | - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName | 56 | - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName |
| @@ -68,24 +59,22 @@ | @@ -68,24 +59,22 @@ | ||
| 68 | [[self buckets] addObject:[self currentBucket]]; | 59 | [[self buckets] addObject:[self currentBucket]]; |
| 69 | [self setCurrentBucket:nil]; | 60 | [self setCurrentBucket:nil]; |
| 70 | } else if ([elementName isEqualToString:@"Name"]) { | 61 | } else if ([elementName isEqualToString:@"Name"]) { |
| 71 | - [[self currentBucket] setName:[self currentContent]]; | 62 | + [[self currentBucket] setName:[self currentXMLElementContent]]; |
| 72 | } else if ([elementName isEqualToString:@"CreationDate"]) { | 63 | } else if ([elementName isEqualToString:@"CreationDate"]) { |
| 73 | - [[self currentBucket] setCreationDate:[[ASIS3Request dateFormatter] dateFromString:[self currentContent]]]; | 64 | + [[self currentBucket] setCreationDate:[[ASIS3Request dateFormatter] dateFromString:[self currentXMLElementContent]]]; |
| 74 | } else if ([elementName isEqualToString:@"ID"]) { | 65 | } else if ([elementName isEqualToString:@"ID"]) { |
| 75 | - [self setOwnerID:[self currentContent]]; | 66 | + [self setOwnerID:[self currentXMLElementContent]]; |
| 76 | } else if ([elementName isEqualToString:@"DisplayName"]) { | 67 | } else if ([elementName isEqualToString:@"DisplayName"]) { |
| 77 | - [self setOwnerName:[self currentContent]]; | 68 | + [self setOwnerName:[self currentXMLElementContent]]; |
| 69 | + } else { | ||
| 70 | + // Let ASIS3Request look for error messages | ||
| 71 | + [super parser:parser didEndElement:elementName namespaceURI:namespaceURI qualifiedName:qName]; | ||
| 78 | } | 72 | } |
| 79 | } | 73 | } |
| 80 | 74 | ||
| 81 | -- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string | ||
| 82 | -{ | ||
| 83 | - [self setCurrentContent:[[self currentContent] stringByAppendingString:string]]; | ||
| 84 | -} | ||
| 85 | - | ||
| 86 | @synthesize buckets; | 75 | @synthesize buckets; |
| 87 | -@synthesize currentContent; | 76 | +@synthesize currentXMLElementContent; |
| 88 | -@synthesize currentElement; | 77 | +@synthesize currentXMLElementStack; |
| 89 | @synthesize currentBucket; | 78 | @synthesize currentBucket; |
| 90 | @synthesize ownerID; | 79 | @synthesize ownerID; |
| 91 | @synthesize ownerName; | 80 | @synthesize ownerName; |
| @@ -118,8 +118,6 @@ static NSString *bucket = @""; | @@ -118,8 +118,6 @@ static NSString *bucket = @""; | ||
| 118 | 118 | ||
| 119 | - (void)testFailure | 119 | - (void)testFailure |
| 120 | { | 120 | { |
| 121 | - [self createTestBucket]; | ||
| 122 | - | ||
| 123 | // Needs expanding to cover more failure states - this is just a test to ensure Amazon's error description is being added to the error | 121 | // Needs expanding to cover more failure states - this is just a test to ensure Amazon's error description is being added to the error |
| 124 | 122 | ||
| 125 | // We're actually going to try with the Amazon example details, but the request will fail because the date is old | 123 | // We're actually going to try with the Amazon example details, but the request will fail because the date is old |
| @@ -141,6 +139,33 @@ static NSString *bucket = @""; | @@ -141,6 +139,33 @@ static NSString *bucket = @""; | ||
| 141 | success = ([[[request error] localizedDescription] isEqualToString:@"The difference between the request time and the current time is too large."]); | 139 | success = ([[[request error] localizedDescription] isEqualToString:@"The difference between the request time and the current time is too large."]); |
| 142 | GHAssertTrue(success,@"Generated error had the wrong description"); | 140 | GHAssertTrue(success,@"Generated error had the wrong description"); |
| 143 | 141 | ||
| 142 | + // Ensure a bucket request will correctly parse an error from S3 | ||
| 143 | + request = [ASIS3BucketRequest requestWithBucket:exampleBucket]; | ||
| 144 | + [request setDateString:dateString]; | ||
| 145 | + [request setSecretAccessKey:exampleSecretAccessKey]; | ||
| 146 | + [request setAccessKey:exampleAccessKey]; | ||
| 147 | + [request startSynchronous]; | ||
| 148 | + GHAssertNotNil([request error],@"Failed to generate an error when the request was not correctly signed"); | ||
| 149 | + | ||
| 150 | + success = ([[request error] code] == ASIS3ResponseErrorType); | ||
| 151 | + GHAssertTrue(success,@"Generated error had the wrong error code"); | ||
| 152 | + | ||
| 153 | + success = ([[[request error] localizedDescription] isEqualToString:@"The difference between the request time and the current time is too large."]); | ||
| 154 | + GHAssertTrue(success,@"Generated error had the wrong description"); | ||
| 155 | + | ||
| 156 | + // Ensure a service request will correctly parse an error from S3 | ||
| 157 | + request = [ASIS3ServiceRequest serviceRequest]; | ||
| 158 | + [request setDateString:dateString]; | ||
| 159 | + [request setSecretAccessKey:exampleSecretAccessKey]; | ||
| 160 | + [request setAccessKey:exampleAccessKey]; | ||
| 161 | + [request startSynchronous]; | ||
| 162 | + GHAssertNotNil([request error],@"Failed to generate an error when the request was not correctly signed"); | ||
| 163 | + | ||
| 164 | + success = ([[request error] code] == ASIS3ResponseErrorType); | ||
| 165 | + GHAssertTrue(success,@"Generated error had the wrong error code"); | ||
| 166 | + | ||
| 167 | + success = ([[[request error] localizedDescription] isEqualToString:@"The difference between the request time and the current time is too large."]); | ||
| 168 | + GHAssertTrue(success,@"Generated error had the wrong description"); | ||
| 144 | } | 169 | } |
| 145 | 170 | ||
| 146 | - (void)createTestBucket | 171 | - (void)createTestBucket |
| @@ -176,7 +201,7 @@ static NSString *bucket = @""; | @@ -176,7 +201,7 @@ static NSString *bucket = @""; | ||
| 176 | GHAssertNil([serviceRequest error],@"Failed to fetch the list of buckets from S3"); | 201 | GHAssertNil([serviceRequest error],@"Failed to fetch the list of buckets from S3"); |
| 177 | 202 | ||
| 178 | BOOL foundBucket = NO; | 203 | BOOL foundBucket = NO; |
| 179 | - for (ASIS3Bucket *theBucket in [serviceRequest allBuckets]) { | 204 | + for (ASIS3Bucket *theBucket in [serviceRequest buckets]) { |
| 180 | if ([[theBucket name] isEqualToString:bucket]) { | 205 | if ([[theBucket name] isEqualToString:bucket]) { |
| 181 | foundBucket = YES; | 206 | foundBucket = YES; |
| 182 | break; | 207 | break; |
| @@ -236,7 +261,7 @@ static NSString *bucket = @""; | @@ -236,7 +261,7 @@ static NSString *bucket = @""; | ||
| 236 | [listRequest setAccessKey:accessKey]; | 261 | [listRequest setAccessKey:accessKey]; |
| 237 | [listRequest startSynchronous]; | 262 | [listRequest startSynchronous]; |
| 238 | GHAssertNil([listRequest error],@"Failed to download a list from S3"); | 263 | GHAssertNil([listRequest error],@"Failed to download a list from S3"); |
| 239 | - success = [[listRequest bucketObjects] count]; | 264 | + success = [[listRequest objects] count]; |
| 240 | GHAssertTrue(success,@"The file didn't show up in the list"); | 265 | GHAssertTrue(success,@"The file didn't show up in the list"); |
| 241 | 266 | ||
| 242 | // Test again with a prefix query | 267 | // Test again with a prefix query |
| @@ -246,7 +271,7 @@ static NSString *bucket = @""; | @@ -246,7 +271,7 @@ static NSString *bucket = @""; | ||
| 246 | [listRequest setAccessKey:accessKey]; | 271 | [listRequest setAccessKey:accessKey]; |
| 247 | [listRequest startSynchronous]; | 272 | [listRequest startSynchronous]; |
| 248 | GHAssertNil([listRequest error],@"Failed to download a list from S3"); | 273 | GHAssertNil([listRequest error],@"Failed to download a list from S3"); |
| 249 | - success = [[listRequest bucketObjects] count]; | 274 | + success = [[listRequest objects] count]; |
| 250 | GHAssertTrue(success,@"The file didn't show up in the list"); | 275 | GHAssertTrue(success,@"The file didn't show up in the list"); |
| 251 | 276 | ||
| 252 | // DELETE the file | 277 | // DELETE the file |
| @@ -309,7 +334,7 @@ static NSString *bucket = @""; | @@ -309,7 +334,7 @@ static NSString *bucket = @""; | ||
| 309 | [bucketRequest setSecretAccessKey:secretAccessKey]; | 334 | [bucketRequest setSecretAccessKey:secretAccessKey]; |
| 310 | [bucketRequest setAccessKey:accessKey]; | 335 | [bucketRequest setAccessKey:accessKey]; |
| 311 | [bucketRequest startSynchronous]; | 336 | [bucketRequest startSynchronous]; |
| 312 | - GHAssertNil([bucketRequest error],@"Failed to create a bucket"); | 337 | + GHAssertNil([bucketRequest error],@"Failed to delete a bucket"); |
| 313 | 338 | ||
| 314 | 339 | ||
| 315 | } | 340 | } |
| @@ -387,14 +412,52 @@ static NSString *bucket = @""; | @@ -387,14 +412,52 @@ static NSString *bucket = @""; | ||
| 387 | GHAssertNil([request error],@"Give up on list request test - failed to upload a file"); | 412 | GHAssertNil([request error],@"Give up on list request test - failed to upload a file"); |
| 388 | } | 413 | } |
| 389 | 414 | ||
| 390 | - // Now get a list of the files | 415 | + // Test common prefixes |
| 391 | ASIS3BucketRequest *listRequest = [ASIS3BucketRequest requestWithBucket:bucket]; | 416 | ASIS3BucketRequest *listRequest = [ASIS3BucketRequest requestWithBucket:bucket]; |
| 417 | + [listRequest setSecretAccessKey:secretAccessKey]; | ||
| 418 | + [listRequest setAccessKey:accessKey]; | ||
| 419 | + [listRequest setDelimiter:@"/"]; | ||
| 420 | + [listRequest startSynchronous]; | ||
| 421 | + GHAssertNil([listRequest error],@"Failed to download a list from S3"); | ||
| 422 | + success = NO; | ||
| 423 | + for (NSString *prefix in [listRequest commonPrefixes]) { | ||
| 424 | + if ([prefix isEqualToString:@"test-file/"]) { | ||
| 425 | + success = YES; | ||
| 426 | + } | ||
| 427 | + } | ||
| 428 | + GHAssertTrue(success,@"Failed to obtain a list of common prefixes"); | ||
| 429 | + | ||
| 430 | + | ||
| 431 | + // Test truncation | ||
| 432 | + listRequest = [ASIS3BucketRequest requestWithBucket:bucket]; | ||
| 433 | + [listRequest setSecretAccessKey:secretAccessKey]; | ||
| 434 | + [listRequest setAccessKey:accessKey]; | ||
| 435 | + [listRequest setMaxResultCount:1]; | ||
| 436 | + [listRequest startSynchronous]; | ||
| 437 | + GHAssertTrue([listRequest isTruncated],@"Failed to identify what should be a truncated list of results"); | ||
| 438 | + | ||
| 439 | + // Test urls are built correctly when requesting a subresource | ||
| 440 | + listRequest = [ASIS3BucketRequest requestWithBucket:bucket subResource:@"acl"]; | ||
| 441 | + [listRequest setSecretAccessKey:secretAccessKey]; | ||
| 442 | + [listRequest setAccessKey:accessKey]; | ||
| 443 | + [listRequest setDelimiter:@"/"]; | ||
| 444 | + [listRequest setPrefix:@"foo"]; | ||
| 445 | + [listRequest setMarker:@"bar"]; | ||
| 446 | + [listRequest setMaxResultCount:5]; | ||
| 447 | + [listRequest createQueryString]; | ||
| 448 | + NSString *expectedURL = [NSString stringWithFormat:@"http://%@.s3.amazonaws.com/?acl&prefix=foo&key-marker=bar&delimiter=/&max-keys=5",bucket]; | ||
| 449 | + success = ([[[listRequest url] absoluteString] isEqualToString:expectedURL]); | ||
| 450 | + GHAssertTrue(success,@"Generated the wrong url when requesting a subresource"); | ||
| 451 | + | ||
| 452 | + | ||
| 453 | + // Now get a list of the files | ||
| 454 | + listRequest = [ASIS3BucketRequest requestWithBucket:bucket]; | ||
| 392 | [listRequest setPrefix:@"test-file"]; | 455 | [listRequest setPrefix:@"test-file"]; |
| 393 | [listRequest setSecretAccessKey:secretAccessKey]; | 456 | [listRequest setSecretAccessKey:secretAccessKey]; |
| 394 | [listRequest setAccessKey:accessKey]; | 457 | [listRequest setAccessKey:accessKey]; |
| 395 | [listRequest startSynchronous]; | 458 | [listRequest startSynchronous]; |
| 396 | GHAssertNil([listRequest error],@"Failed to download a list from S3"); | 459 | GHAssertNil([listRequest error],@"Failed to download a list from S3"); |
| 397 | - success = ([[listRequest bucketObjects] count] == 5); | 460 | + success = ([[listRequest objects] count] == 5); |
| 398 | GHAssertTrue(success,@"List did not contain all files"); | 461 | GHAssertTrue(success,@"List did not contain all files"); |
| 399 | 462 | ||
| 400 | // Please don't use an autoreleased operation queue with waitUntilAllOperationsAreFinished in your own code unless you're writing a test like this one | 463 | // Please don't use an autoreleased operation queue with waitUntilAllOperationsAreFinished in your own code unless you're writing a test like this one |
| @@ -405,7 +468,7 @@ static NSString *bucket = @""; | @@ -405,7 +468,7 @@ static NSString *bucket = @""; | ||
| 405 | [queue setRequestDidFinishSelector:@selector(GETRequestDone:)]; | 468 | [queue setRequestDidFinishSelector:@selector(GETRequestDone:)]; |
| 406 | [queue setRequestDidFailSelector:@selector(GETRequestFailed:)]; | 469 | [queue setRequestDidFailSelector:@selector(GETRequestFailed:)]; |
| 407 | [queue setDelegate:self]; | 470 | [queue setDelegate:self]; |
| 408 | - for (ASIS3BucketObject *object in [listRequest bucketObjects]) { | 471 | + for (ASIS3BucketObject *object in [listRequest objects]) { |
| 409 | ASIS3ObjectRequest *request = [object GETRequest]; | 472 | ASIS3ObjectRequest *request = [object GETRequest]; |
| 410 | [request setAccessKey:accessKey]; | 473 | [request setAccessKey:accessKey]; |
| 411 | [request setSecretAccessKey:secretAccessKey]; | 474 | [request setSecretAccessKey:secretAccessKey]; |
| @@ -421,7 +484,7 @@ static NSString *bucket = @""; | @@ -421,7 +484,7 @@ static NSString *bucket = @""; | ||
| 421 | [queue setDelegate:self]; | 484 | [queue setDelegate:self]; |
| 422 | i=0; | 485 | i=0; |
| 423 | // For each one, we'll just upload the same content again | 486 | // For each one, we'll just upload the same content again |
| 424 | - for (ASIS3BucketObject *object in [listRequest bucketObjects]) { | 487 | + for (ASIS3BucketObject *object in [listRequest objects]) { |
| 425 | NSString *oldFilePath = [[self filePathForTemporaryTestFiles] stringByAppendingPathComponent:[NSString stringWithFormat:@"%hi.txt",i]];; | 488 | NSString *oldFilePath = [[self filePathForTemporaryTestFiles] stringByAppendingPathComponent:[NSString stringWithFormat:@"%hi.txt",i]];; |
| 426 | ASIS3Request *request = [object PUTRequestWithFile:oldFilePath]; | 489 | ASIS3Request *request = [object PUTRequestWithFile:oldFilePath]; |
| 427 | [request setAccessKey:accessKey]; | 490 | [request setAccessKey:accessKey]; |
| @@ -439,7 +502,7 @@ static NSString *bucket = @""; | @@ -439,7 +502,7 @@ static NSString *bucket = @""; | ||
| 439 | [queue setDelegate:self]; | 502 | [queue setDelegate:self]; |
| 440 | i=0; | 503 | i=0; |
| 441 | 504 | ||
| 442 | - for (ASIS3BucketObject *object in [listRequest bucketObjects]) { | 505 | + for (ASIS3BucketObject *object in [listRequest objects]) { |
| 443 | ASIS3ObjectRequest *request = [object DELETERequest]; | 506 | ASIS3ObjectRequest *request = [object DELETERequest]; |
| 444 | [request setAccessKey:accessKey]; | 507 | [request setAccessKey:accessKey]; |
| 445 | [request setSecretAccessKey:secretAccessKey]; | 508 | [request setSecretAccessKey:secretAccessKey]; |
| @@ -456,7 +519,7 @@ static NSString *bucket = @""; | @@ -456,7 +519,7 @@ static NSString *bucket = @""; | ||
| 456 | [listRequest setAccessKey:accessKey]; | 519 | [listRequest setAccessKey:accessKey]; |
| 457 | [listRequest startSynchronous]; | 520 | [listRequest startSynchronous]; |
| 458 | GHAssertNil([listRequest error],@"Failed to download a list from S3"); | 521 | GHAssertNil([listRequest error],@"Failed to download a list from S3"); |
| 459 | - success = ([[listRequest bucketObjects] count] == 0); | 522 | + success = ([[listRequest objects] count] == 0); |
| 460 | GHAssertTrue(success,@"List contained files that should have been deleted"); | 523 | GHAssertTrue(success,@"List contained files that should have been deleted"); |
| 461 | 524 | ||
| 462 | } | 525 | } |
| @@ -685,6 +748,8 @@ static NSString *bucket = @""; | @@ -685,6 +748,8 @@ static NSString *bucket = @""; | ||
| 685 | [bucketObject2 release]; | 748 | [bucketObject2 release]; |
| 686 | } | 749 | } |
| 687 | 750 | ||
| 751 | + | ||
| 752 | + | ||
| 688 | @synthesize networkQueue; | 753 | @synthesize networkQueue; |
| 689 | 754 | ||
| 690 | @end | 755 | @end |
-
Please register or login to post a comment