Permalink
Browse files

Added support for S3 list requests

Added more tests, bug fixes
  • Loading branch information...
1 parent 3ab29ef commit 6941435a497520cd0f7a776312863f57794c8b49 @pokeb committed Jul 14, 2009
@@ -0,0 +1,52 @@
+//
+// ASIS3BucketObject.h
+// Mac
+//
+// Created by Ben Copsey on 13/07/2009.
+// Copyright 2009 All-Seeing Interactive. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+@class ASIS3Request;
+
+@interface ASIS3BucketObject : NSObject {
+
+ // The bucket this object belongs to
+ NSString *bucket;
+
+ // The key (path) of this object in the bucket
+ NSString *key;
+
+ // When this object was last modified
+ NSDate *lastModified;
+
+ // The ETag for this object's content
+ NSString *ETag;
+
+ // The size in bytes of this object
+ unsigned long long size;
+
+ // Info about the owner
+ NSString *ownerID;
+ NSString *ownerName;
+}
+
++ (id)objectWithBucket:(NSString *)bucket;
+
+// Returns a request that will fetch this object when run
+- (ASIS3Request *)GETRequest;
+
+// Returns a request that will replace this object with the contents of the file at filePath when run
+- (ASIS3Request *)PUTRequestWithFile:(NSString *)filePath;
+
+// Returns a request that will delete this object when run
+- (ASIS3Request *)DELETERequest;
+
+@property (retain) NSString *bucket;
+@property (retain) NSString *key;
+@property (retain) NSDate *lastModified;
+@property (retain) NSString *ETag;
+@property (assign) unsigned long long size;
+@property (retain) NSString *ownerID;
+@property (retain) NSString *ownerName;
+@end
@@ -0,0 +1,61 @@
+//
+// ASIS3BucketObject.m
+// Mac
+//
+// Created by Ben Copsey on 13/07/2009.
+// Copyright 2009 All-Seeing Interactive. All rights reserved.
+//
+
+#import "ASIS3BucketObject.h"
+#import "ASIS3Request.h"
+
+@implementation ASIS3BucketObject
+
++ (id)objectWithBucket:(NSString *)bucket
+{
+ ASIS3BucketObject *object = [[[ASIS3BucketObject alloc] init] autorelease];
+ [object setBucket:bucket];
+ return object;
+}
+
+- (void)dealloc
+{
+ [key release];
+ [lastModified release];
+ [ETag release];
+ [ownerID release];
+ [ownerName release];
+ [super dealloc];
+}
+
+- (ASIS3Request *)GETRequest
+{
+ return [ASIS3Request requestWithBucket:[self bucket] path:[NSString stringWithFormat:@"/%@",[self key]]];
+}
+
+- (ASIS3Request *)PUTRequestWithFile:(NSString *)filePath
+{
+ return [ASIS3Request PUTRequestForFile:filePath withBucket:[self bucket] path:[NSString stringWithFormat:@"/%@",[self key]]];
+}
+
+- (ASIS3Request *)DELETERequest
+{
+ ASIS3Request *request = [ASIS3Request requestWithBucket:[self bucket] path:[NSString stringWithFormat:@"/%@",[self key]]];
+ [request setRequestMethod:@"DELETE"];
+ return request;
+}
+
+
+- (NSString *)description
+{
+ return [NSString stringWithFormat:@"Key: %@ lastModified: %@ ETag: %@ size: %llu ownerID: %@ ownerName: %@",[self key],[self lastModified],[self ETag],[self size],[self ownerID],[self ownerName]];
+}
+
+@synthesize bucket;
+@synthesize key;
+@synthesize lastModified;
+@synthesize ETag;
+@synthesize size;
+@synthesize ownerID;
+@synthesize ownerName;
+@end
View
@@ -0,0 +1,42 @@
+//
+// ASIS3ListRequest.h
+// Mac
+//
+// Created by Ben Copsey on 13/07/2009.
+// Copyright 2009 All-Seeing Interactive. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "ASIS3Request.h"
+@class ASIS3BucketObject;
+
+@interface ASIS3ListRequest : ASIS3Request {
+
+ NSString *prefix;
+ NSString *marker;
+ int maxResultCount;
+ NSString *delimiter;
+
+ // Internally used while parsing the response
+ NSString *currentContent;
+ NSString *currentElement;
+ ASIS3BucketObject *currentObject;
+ NSMutableArray *objects;
+
+
+}
+// Create a list request
++ (id)listRequestWithBucket:(NSString *)bucket;
+
+
+// Returns an array of ASIS3BucketObjects created from the XML response
+- (NSArray *)bucketObjects;
+
+//Builds a query string out of the list parameters we supplied
+- (void)createQueryString;
+
+@property (retain) NSString *prefix;
+@property (retain) NSString *marker;
+@property (assign) int maxResultCount;
+@property (retain) NSString *delimiter;
+@end
View
@@ -0,0 +1,137 @@
+//
+// ASIS3ListRequest.m
+// Mac
+//
+// Created by Ben Copsey on 13/07/2009.
+// Copyright 2009 All-Seeing Interactive. All rights reserved.
+//
+#import "ASIS3ListRequest.h"
+#import "ASIS3BucketObject.h"
+
+
+static NSDateFormatter *dateFormatter = nil;
+
+// Private stuff
+@interface ASIS3ListRequest ()
+ @property (retain,setter=setURL:) NSURL *url;
+ @property (retain, nonatomic) NSString *currentContent;
+ @property (retain, nonatomic) NSString *currentElement;
+ @property (retain, nonatomic) ASIS3BucketObject *currentObject;
+ @property (retain, nonatomic) NSMutableArray *objects;
+@end
+
+@implementation ASIS3ListRequest
+
++ (void)initialize
+{
+ dateFormatter = [[NSDateFormatter alloc] init];
+ [dateFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]];
+ [dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss'.000Z'"];
+}
+
++ (id)listRequestWithBucket:(NSString *)bucket
+{
+ ASIS3ListRequest *request = [[[ASIS3ListRequest alloc] initWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://%@.s3.amazonaws.com",bucket]]] autorelease];
+ [request setBucket:bucket];
+ return request;
+}
+
+- (void)dealloc
+{
+ [currentElement release];
+ [currentObject release];
+ [objects release];
+ [super dealloc];
+}
+
+- (void)createQueryString
+{
+ NSMutableArray *queryParts = [[[NSMutableArray alloc] init] autorelease];
+ if ([self prefix]) {
+ [queryParts addObject:[NSString stringWithFormat:@"prefix=%@",[[self prefix] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];
+ }
+ if ([self marker]) {
+ [queryParts addObject:[NSString stringWithFormat:@"marker=%@",[[self marker] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];
+ }
+ if ([self delimiter]) {
+ [queryParts addObject:[NSString stringWithFormat:@"delimiter=%@",[[self delimiter] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];
+ }
+ if ([self maxResultCount] > 0) {
+ [queryParts addObject:[NSString stringWithFormat:@"delimiter=%hi",[self maxResultCount]]];
+ }
+ if ([queryParts count]) {
+ [self setURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@?%@",[[self url] absoluteString],[queryParts componentsJoinedByString:@"&"]]]];
+ }
+}
+
+- (void)main
+{
+ [self createQueryString];
+ [super main];
+}
+
+- (NSArray *)bucketObjects
+{
+ if ([self objects]) {
+ return [self objects];
+ }
+ [self setObjects:[[[NSMutableArray alloc] init] autorelease]];
+ NSXMLParser *parser = [[[NSXMLParser alloc] initWithData:[self responseData]] autorelease];
+ [parser setDelegate:self];
+ [parser setShouldProcessNamespaces:NO];
+ [parser setShouldReportNamespacePrefixes:NO];
+ [parser setShouldResolveExternalEntities:NO];
+ [parser parse];
+ return [self objects];
+}
+
+- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
+{
+ [self setCurrentElement:elementName];
+
+ if ([elementName isEqualToString:@"Contents"]) {
+ [self setCurrentObject:[ASIS3BucketObject objectWithBucket:[self bucket]]];
+ }
+ [self setCurrentContent:@""];
+}
+
+- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
+{
+ if ([elementName isEqualToString:@"Contents"]) {
+ [objects addObject:currentObject];
+ [self setCurrentObject:nil];
+ } else if ([elementName isEqualToString:@"Key"]) {
+ [[self currentObject] setKey:[self currentContent]];
+ } else if ([elementName isEqualToString:@"LastModified"]) {
+ [[self currentObject] setLastModified:[dateFormatter dateFromString:[self currentContent]]];
+ } else if ([elementName isEqualToString:@"ETag"]) {
+ [[self currentObject] setETag:[self currentContent]];
+ } else if ([elementName isEqualToString:@"Size"]) {
+ [[self currentObject] setSize:(unsigned long long)[[self currentContent] longLongValue]];
+ } else if ([elementName isEqualToString:@"ID"]) {
+ [[self currentObject] setOwnerID:[self currentContent]];
+ } else if ([elementName isEqualToString:@"DisplayName"]) {
+ [[self currentObject] setOwnerName:[self currentContent]];
+ }
+}
+
+- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
+{
+ [self setCurrentContent:[[self currentContent] stringByAppendingString:string]];
+}
+
+- (void)parserDidEndDocument:(NSXMLParser *)parser
+{
+}
+
+
+@synthesize currentContent;
+@synthesize currentElement;
+@synthesize currentObject;
+@synthesize objects;
+@synthesize prefix;
+@synthesize marker;
+@synthesize maxResultCount;
+@synthesize delimiter;
+@synthesize url;
+@end
View
@@ -4,8 +4,7 @@
// Created by Ben Copsey on 30/06/2009.
// Copyright 2009 All-Seeing Interactive. All rights reserved.
//
-// A (basic) class for accessing data stored on Amazon's Simple Storage Service (http://aws.amazon.com/s3/)
-// It uses the REST API, with canned access policies rather than full support for ACLs (though if you build/parse them yourself you can still use ACLs)
+// A (basic) class for accessing data stored on Amazon's Simple Storage Service (http://aws.amazon.com/s3/) using the REST API
#import <Foundation/Foundation.h>
#import "ASIHTTPRequest.h"
@@ -16,6 +15,12 @@ extern NSString *const ASIS3AccessPolicyPublicRead;
extern NSString *const ASIS3AccessPolicyPublicReadWrote;
extern NSString *const ASIS3AccessPolicyAuthenticatedRead;
+typedef enum _ASIS3ErrorType {
+ ASIS3ResponseParsingFailedType = 1,
+ ASIS3ResponseErrorType = 2
+
+} ASIS3ErrorType;
+
@interface ASIS3Request : ASIHTTPRequest {
// Your S3 access key. Set it on the request, or set it globally using [ASIS3Request setSharedAccessKey:]
@@ -38,7 +43,19 @@ extern NSString *const ASIS3AccessPolicyAuthenticatedRead;
// Will be set to 'application/octet-stream' otherwise in iPhone apps, or autodetected on Mac OS X
NSString *mimeType;
+ // The access policy to use when PUTting a file (see the string constants at the top of this header)
NSString *accessPolicy;
+
+ // Options for filtering list requests
+ // See http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?RESTBucketGET.html
+ NSString *listPrefix;
+ NSString *listMarker;
+ int listMaxResults;
+ NSString *listDelimiter;
+
+ // Internally used while parsing errors
+ NSString *currentErrorString;
+
}
#pragma mark Constructors
@@ -49,16 +66,15 @@ extern NSString *const ASIS3AccessPolicyAuthenticatedRead;
// Create a PUT request using the file at filePath as the body
+ (id)PUTRequestForFile:(NSString *)filePath withBucket:(NSString *)bucket path:(NSString *)path;
-// Create a list request
-+ (id)listRequestWithBucket:(NSString *)bucket prefix:(NSString *)prefix maxResults:(int)maxResults marker:(NSString *)marker;
-
// Generates the request headers S3 needs
// Automatically called before the request begins in startRequest
- (void)generateS3Headers;
// Uses the supplied date to create a Date header string
- (void)setDate:(NSDate *)date;
+#pragma mark Helper functions
+
// Only works on Mac OS, will always return 'application/octet-stream' on iPhone
+ (NSString *)mimeTypeForFileAtPath:(NSString *)path;
@@ -77,5 +93,6 @@ extern NSString *const ASIS3AccessPolicyAuthenticatedRead;
@property (retain) NSString *mimeType;
@property (retain) NSString *accessKey;
@property (retain) NSString *secretAccessKey;
-@property (assign) NSString *accessPolicy;
+@property (retain) NSString *accessPolicy;
+
@end
Oops, something went wrong.

0 comments on commit 6941435

Please sign in to comment.