Michael Mayo

refactor xml parsing and add partial cdn management support

... ... @@ -10,7 +10,41 @@
@interface ASICloudFilesCDNRequest : ASICloudFilesRequest {
NSString *accountName;
NSString *containerName;
}
@property (nonatomic, retain) NSString *accountName;
@property (nonatomic, retain) NSString *containerName;
// HEAD /<api version>/<account>/<container>
// Response:
// X-CDN-Enabled: True
// X-CDN-URI: http://cdn.cloudfiles.mosso.com/c1234
// X-CDN-TTL: 86400
+ (id)containerInfoRequest:(NSString *)containerName;
- (BOOL)cdnEnabled;
- (NSString *)cdnURI;
- (NSUInteger)cdnTTL;
// GET /<api version>/<account>
// limit, marker, format, enabled_only=true
+ (id)listRequest;
+ (id)listRequestWithLimit:(NSUInteger)limit marker:(NSString *)marker enabledOnly:(BOOL)enabledOnly;
- (NSArray *)containers;
// PUT /<api version>/<account>/<container>
// PUT operations against a Container are used to CDN-enable that Container.
// Include an HTTP header of X-TTL to specify a custom TTL.
// POST /<api version>/<account>/<container>
// POST operations against a CDN-enabled Container are used to adjust CDN attributes.
// The POST operation can be used to set a new TTL cache expiration or to enable/disable public sharing over the CDN.
// X-TTL: 86400
// X-CDN-Enabled: True
@end
... ...
... ... @@ -11,4 +11,100 @@
@implementation ASICloudFilesCDNRequest
@synthesize accountName, containerName;
+ (id)cdnRequestWithMethod:(NSString *)method query:(NSString *)query {
NSString *urlString = [NSString stringWithFormat:@"%@%@", [ASICloudFilesRequest cdnManagementURL], query];
ASICloudFilesCDNRequest *request = [[ASICloudFilesCDNRequest alloc] initWithURL:[NSURL URLWithString:urlString]];
[request setRequestMethod:method];
[request addRequestHeader:@"X-Auth-Token" value:[ASICloudFilesRequest authToken]];
return request;
}
+ (id)cdnRequestWithMethod:(NSString *)method containerName:(NSString *)containerName {
NSString *urlString = [NSString stringWithFormat:@"%@/%@", [ASICloudFilesRequest cdnManagementURL], containerName];
//NSLog(@"object request url: %@", urlString);
ASICloudFilesCDNRequest *request = [[ASICloudFilesCDNRequest alloc] initWithURL:[NSURL URLWithString:urlString]];
[request setRequestMethod:method];
[request addRequestHeader:@"X-Auth-Token" value:[ASICloudFilesRequest authToken]];
request.containerName = containerName;
return request;
}
#pragma mark -
#pragma mark HEAD - Container Info
+ (id)containerInfoRequest:(NSString *)containerName {
ASICloudFilesCDNRequest *request = [ASICloudFilesCDNRequest cdnRequestWithMethod:@"HEAD" containerName:containerName];
return request;
}
- (BOOL)cdnEnabled {
return [[[self responseHeaders] objectForKey:@"X-Cdn-Enabled"] boolValue];
}
- (NSString *)cdnURI {
return [[self responseHeaders] objectForKey:@"X-Cdn-Uri"];
}
- (NSUInteger)cdnTTL {
return [[[self responseHeaders] objectForKey:@"X-Ttl"] intValue];
}
#pragma mark -
#pragma mark GET - CDN Container Lists
+ (id)listRequest {
ASICloudFilesCDNRequest *request = [ASICloudFilesCDNRequest cdnRequestWithMethod:@"GET" query:nil];
return request;
}
+ (id)listRequestWithLimit:(NSUInteger)limit marker:(NSString *)marker enabledOnly:(BOOL)enabledOnly {
NSString *query = @"?format=xml";
if (limit > 0) {
query = [query stringByAppendingString:[NSString stringWithFormat:@"&limit=%i", limit]];
}
if (marker) {
query = [query stringByAppendingString:[NSString stringWithFormat:@"&marker=%@", marker]];
}
if (limit > 0) {
query = [query stringByAppendingString:[NSString stringWithFormat:@"&limit=%i", limit]];
}
ASICloudFilesCDNRequest *request = [ASICloudFilesCDNRequest cdnRequestWithMethod:@"GET" query:query];
return request;
}
- (NSArray *)containers {
return nil;
}
// GET /<api version>/<account>
// limit, marker, format, enabled_only=true
// + (id)getObjectRequestWithContainer:(NSString *)containerName objectPath:(NSString *)objectPath;
// PUT /<api version>/<account>/<container>
// PUT operations against a Container are used to CDN-enable that Container.
// Include an HTTP header of X-TTL to specify a custom TTL.
// POST /<api version>/<account>/<container>
// POST operations against a CDN-enabled Container are used to adjust CDN attributes.
// The POST operation can be used to set a new TTL cache expiration or to enable/disable public sharing over the CDN.
// X-TTL: 86400
// X-CDN-Enabled: True
#pragma mark -
#pragma mark Memory Management
-(void)dealloc {
[accountName release];
[containerName release];
[super dealloc];
}
@end
... ...
... ... @@ -10,15 +10,34 @@
@interface ASICloudFilesContainer : NSObject {
// regular container attributes
NSString *name;
NSUInteger count;
NSUInteger bytes;
// CDN container attributes
BOOL cdnEnabled;
NSUInteger ttl;
NSString *cdnURL;
BOOL logRetention;
NSString *referrerACL;
NSString *useragentACL;
}
+ (id)container;
// regular container attributes
@property (nonatomic, retain) NSString *name;
@property (nonatomic) NSUInteger count;
@property (nonatomic) NSUInteger bytes;
// CDN container attributes
@property (nonatomic) BOOL cdnEnabled;
@property (nonatomic) NSUInteger ttl;
@property (nonatomic, retain) NSString *cdnURL;
@property (nonatomic) BOOL logRetention;
@property (nonatomic, retain) NSString *referrerACL;
@property (nonatomic, retain) NSString *useragentACL;
@end
... ...
... ... @@ -11,8 +11,12 @@
@implementation ASICloudFilesContainer
// regular container attributes
@synthesize name, count, bytes;
// CDN container attributes
@synthesize cdnEnabled, ttl, cdnURL, logRetention, referrerACL, useragentACL;
+ (id)container {
ASICloudFilesContainer *container = [[[self alloc] init] autorelease];
return container;
... ...
... ... @@ -8,27 +8,24 @@
#import "ASICloudFilesRequest.h"
@class ASICloudFilesContainer;
@class ASICloudFilesContainer, ASICloudFilesContainerXMLParserDelegate;
@interface ASICloudFilesContainerRequest : ASICloudFilesRequest {
NSMutableArray *containerObjects;
//NSUInteger containerCount;
//NSUInteger bytesUsed;
// NSUInteger limit;
// NSString *marker; // last item found as the offset
// NSString *format; // json or xml
// Internally used while parsing the response
NSString *currentContent;
NSString *currentElement;
ASICloudFilesContainer *currentObject;
ASICloudFilesContainerXMLParserDelegate *xmlParserDelegate;
}
@property (nonatomic, retain) NSString *currentElement;
@property (nonatomic, retain) NSString *currentContent;
@property (nonatomic, retain) ASICloudFilesContainer *currentObject;
@property (nonatomic, retain) ASICloudFilesContainerXMLParserDelegate *xmlParserDelegate;
#pragma mark Constructors
... ... @@ -55,14 +52,4 @@
- (NSUInteger)bytesUsed;
- (NSArray *)containers;
// ASICloudFilesContainerListRequest
// GET on account (for containers)
// limit
// marker (last item found as the offset)
// format - 'json' or 'xml'
// create container
// DELETE to delete
@end
... ...
... ... @@ -8,11 +8,13 @@
#import "ASICloudFilesContainerRequest.h"
#import "ASICloudFilesContainer.h"
#import "ASICloudFilesContainerXMLParserDelegate.h"
@implementation ASICloudFilesContainerRequest
@synthesize currentElement, currentContent, currentObject;
@synthesize xmlParserDelegate;
//ASIHTTPRequest *request = [[ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:rackspaceCloudAuthURL]];
//NSMutableDictionary *headers = [[NSMutableDictionary alloc] initWithCapacity:2];
... ... @@ -117,18 +119,35 @@
//NSLog(@"list response data: %@", [self responseString]);
NSXMLParser *parser = [[[NSXMLParser alloc] initWithData:[self responseData]] autorelease];
[parser setDelegate:self];
if (xmlParserDelegate == nil) {
xmlParserDelegate = [[ASICloudFilesContainerXMLParserDelegate alloc] init];
}
[parser setDelegate:xmlParserDelegate];
[parser setShouldProcessNamespaces:NO];
[parser setShouldReportNamespacePrefixes:NO];
[parser setShouldResolveExternalEntities:NO];
[parser parse];
return containerObjects;
return xmlParserDelegate.containerObjects;
}
#pragma mark -
#pragma mark XML Parser Delegate
/*
<container>
<name>playground</name>
<cdn_enabled>True</cdn_enabled>
<ttl>259200</ttl>
<cdn_url>http://c0023891.cdn.cloudfiles.rackspacecloud.com</cdn_url>
<log_retention>True</log_retention>
<referrer_acl></referrer_acl>
<useragent_acl></useragent_acl>
</container>
<account name="MossoCloudFS_56ad0327-43d6-4ac4-9883-797f5690238e">
<container><name>bigdir</name><count>1536</count><bytes>10752</bytes></container>
<container><name>cf_service</name><count>35</count><bytes>66151933</bytes></container>
... ... @@ -145,6 +164,8 @@
<container><name>wadecrash</name><count>5</count><bytes>19839804</bytes></container>
</account>
*/
/*
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
[self setCurrentElement:elementName];
... ... @@ -172,11 +193,14 @@
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
[self setCurrentContent:[[self currentContent] stringByAppendingString:string]];
}
*/
- (void)dealloc {
[currentElement release];
[currentContent release];
[currentObject release];
[xmlParserDelegate release];
[super dealloc];
}
... ...
//
// ASICloudFilesContainerXMLParserDelegate.h
// iPhone
//
// Created by Michael Mayo on 1/10/10.
// Copyright 2010 __MyCompanyName__. All rights reserved.
//
#import "ASICloudFilesRequest.h"
@class ASICloudFilesContainer;
@interface ASICloudFilesContainerXMLParserDelegate : NSObject {
NSMutableArray *containerObjects;
// Internally used while parsing the response
NSString *currentContent;
NSString *currentElement;
ASICloudFilesContainer *currentObject;
}
@property (nonatomic, retain) NSMutableArray *containerObjects;
@property (nonatomic, retain) NSString *currentElement;
@property (nonatomic, retain) NSString *currentContent;
@property (nonatomic, retain) ASICloudFilesContainer *currentObject;
@end
... ...
//
// ASICloudFilesContainerXMLParserDelegate.m
// iPhone
//
// Created by Michael Mayo on 1/10/10.
// Copyright 2010 __MyCompanyName__. All rights reserved.
//
#import "ASICloudFilesContainerXMLParserDelegate.h"
#import "ASICloudFilesContainer.h"
@implementation ASICloudFilesContainerXMLParserDelegate
@synthesize containerObjects, currentElement, currentContent, currentObject;
#pragma mark -
#pragma mark XML Parser Delegate
/*
<container>
<name>playground</name>
<cdn_enabled>True</cdn_enabled>
<ttl>259200</ttl>
<cdn_url>http://c0023891.cdn.cloudfiles.rackspacecloud.com</cdn_url>
<log_retention>True</log_retention>
<referrer_acl></referrer_acl>
<useragent_acl></useragent_acl>
</container>
<account name="MossoCloudFS_56ad0327-43d6-4ac4-9883-797f5690238e">
<container><name>bigdir</name><count>1536</count><bytes>10752</bytes></container>
<container><name>cf_service</name><count>35</count><bytes>66151933</bytes></container>
<container><name>elcamino</name><count>15</count><bytes>162457114</bytes></container>
<container><name>laptop&#32;migration</name><count>15</count><bytes>225656510</bytes></container>
<container><name>mike&#32;mayo</name><count>2</count><bytes>499581</bytes></container>
<container><name>overhrd.com</name><count>12</count><bytes>205775052</bytes></container>
<container><name>personal</name><count>2</count><bytes>14158285</bytes></container>
<container><name>playground</name><count>4</count><bytes>2040999</bytes></container>
<container><name>pubcamino</name><count>1</count><bytes>219946</bytes></container>
<container><name>pubtest2</name><count>0</count><bytes>0</bytes></container>
<container><name>refreshtest</name><count>0</count><bytes>0</bytes></container>
<container><name>testfromapp</name><count>1</count><bytes>234288</bytes></container>
<container><name>wadecrash</name><count>5</count><bytes>19839804</bytes></container>
</account>
*/
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
[self setCurrentElement:elementName];
NSLog(@"start %@", elementName);
if ([elementName isEqualToString:@"container"]) {
[self setCurrentObject:[ASICloudFilesContainer container]];
}
[self setCurrentContent:@""];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
NSLog(@"end %@", elementName);
if ([elementName isEqualToString:@"name"]) {
[self currentObject].name = [self currentContent];
} else if ([elementName isEqualToString:@"count"]) {
//[[self currentObject] setKey:[self currentContent]];
[self currentObject].count = [[self currentContent] intValue];
} else if ([elementName isEqualToString:@"bytes"]) {
[self currentObject].bytes = [[self currentContent] intValue];
} else if ([elementName isEqualToString:@"container"]) {
// we're done with this container. time to move on to the next
if (containerObjects == nil) {
containerObjects = [[NSMutableArray alloc] init];
}
[containerObjects addObject:currentObject];
[self setCurrentObject:nil];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
[self setCurrentContent:[[self currentContent] stringByAppendingString:string]];
}
#pragma mark -
#pragma mark Memory Management
- (void)dealloc {
[containerObjects release];
[currentElement release];
[currentContent release];
[currentObject release];
[super dealloc];
}
@end
... ...
... ... @@ -16,14 +16,6 @@
@interface ASICloudFilesRequest : ASIHTTPRequest {
// GET operations against the X-CDN-Management-Url for an account are performed to retrieve a list of existing CDN-enabled Containers
// GET /<api version>/<account>
// list containers
// list objects in a container
// cdn operations
}
+ (NSString *)storageURL;
... ... @@ -47,40 +39,4 @@
+ (id)storageRequest;
+ (id)cdnRequest;
//+ (id)PUTRequestForFile:(NSString *)filePath withContainer:(NSString *)container path:(NSString *)path;
// Create a request to list all objects in a container
//+ (id)objectListRequestWithContainer:(NSString *)container;
// HEAD /<api version>/<account>/<container>
// HEAD operations against a storage Container are used to determine the number of Objects, and the total bytes of all Objects stored in the Container.
// The Object count and utilization are returned in the X-Container-Object-Count and X-Container-Bytes-Used headers respectively.
// HEAD /<api version>/<account>/<container>/<object>
// No response body is returned. Metadata is returned as HTTP headers. A status code of 204 (No Content) indicates success, status 404 (Not Found) is returned when the Object does not exist.
// CDN URL
// HEAD /<api version>/<account>/<container>
// HEAD operations against a CDN-enabled Container are used to determine the CDN attributes of the Container.
// PUT operations against a Container are used to CDN-enable that Container.
// POST operations against a CDN-enabled Container are used to adjust CDN attributes.
// Create a request, building an appropriate url
//+ (id)requestWithContainer:(NSString *)container path:(NSString *)path;
//
//// Create a PUT request using the file at filePath as the body
//+ (id)PUTRequestForFile:(NSString *)filePath withContainer:(NSString *)container path:(NSString *)path;
//
//// Create a PUT request using the supplied NSData as the body (set the mime-type manually with setMimeType: if necessary)
//+ (id)PUTRequestForData:(NSData *)data withContainer:(NSString *)container path:(NSString *)path;
//
//// Create a DELETE request for the object at path
//+ (id)DELETERequestWithContainer:(NSString *)container path:(NSString *)path;
// TODO: CDN toggle containers
@end
... ...
... ... @@ -21,7 +21,7 @@
#import "ASIInputStream.h"
// Automatically set on build
NSString *ASIHTTPRequestVersion = @"v1.2-28 2010-01-08";
NSString *ASIHTTPRequestVersion = @"v1.2-29 2010-01-10";
// We use our own custom run loop mode as CoreAnimation seems to want to hijack our threads otherwise
static CFStringRef ASIHTTPRequestRunMode = CFSTR("ASIHTTPRequest");
... ...
... ... @@ -17,9 +17,6 @@
@property (retain,nonatomic) ASINetworkQueue *networkQueue;
// Convenience Constructors
- (void)testSubclasses;
// ASICloudFilesRequest
- (void)testAuthentication;
- (void)testDateParser;
... ...
... ... @@ -37,11 +37,6 @@ static NSString *apiKey = @"1c331a7a4a6eb58ca6072afe81e812d0";
}
}
// Convenience Constructors
- (void)testSubclasses {
GHAssertTrue(NO, @"Test not implemented.");
}
// ASICloudFilesRequest
- (void)testAuthentication {
[self authenticate];
... ... @@ -264,6 +259,39 @@ static NSString *apiKey = @"1c331a7a4a6eb58ca6072afe81e812d0";
GHAssertNil([deleteRequest error], @"Failed to delete object");
}
// CDN
- (void)testCDNContainerInfo {
[self authenticate];
ASICloudFilesCDNRequest *request = [ASICloudFilesCDNRequest containerInfoRequest:@"overhrd.com"];
[request start];
GHAssertTrue([request responseStatusCode] == 204, @"Failed to retrieve CDN container info");
GHAssertTrue([request cdnEnabled], @"Failed to retrieve CDN container info");
GHAssertNotNil([request cdnURI], @"Failed to retrieve CDN container info");
GHAssertTrue([request cdnTTL] > 0, @"Failed to retrieve CDN container info");
}
- (void)testCDNContainerList {
[self authenticate];
ASICloudFilesCDNRequest *request = [ASICloudFilesCDNRequest listRequest];
[request start];
GHAssertNotNil([request containers], @"Failed to retrieve CDN container list");
}
- (void)testCDNContainerListWithParams {
[self authenticate];
ASICloudFilesCDNRequest *request = [ASICloudFilesCDNRequest listRequestWithLimit:2 marker:@"elcamino" enabledOnly:YES];
[request start];
GHAssertNotNil([request containers], @"Failed to retrieve CDN container list");
GHAssertTrue([[request containers] count] == 2, @"Failed to retrieve limited CDN container list");
}
////////
/*
- (void)testSkeleton {
... ...
This diff was suppressed by a .gitattributes entry.