#import "GetFlavorsRequest.h"
#import "APICallback.h"
#import "APILogEntry.h"
+#import "NSString+Conveniences.h"
static NSRecursiveLock *accessDetailsLock = nil;
- (void)notify {
NSString *observeName = [NSString stringWithFormat:@"%@ %@ %@", [self isSuccess] ? @"SUCCESS" : @"FAILURE", self.requestMethod, [self.url description]];
NSString *callbackName = [NSString stringWithFormat:@"%@ %@ %@ %@", [self isSuccess] ? @"SUCCESS" : @"FAILURE", self.requestMethod, [self.url description], self.callback.uuid];
-
+
NSDictionary *callbackUserInfo = [NSDictionary dictionaryWithObject:self forKey:@"response"];
NSNotification *observeNotification = [NSNotification notificationWithName:observeName object:nil userInfo:callbackUserInfo];
[request addRequestHeader:@"X-Auth-Token" value:[account authToken]];
[request addRequestHeader:@"Content-Type" value:@"application/json"];
[request setTimeOutSeconds:60];
+ [request setNumberOfTimesToRetryOnTimeout:5];
request.retriedCount = 0;
return request;
}
+ (id)getSharingAccountsRequest:(OpenStackAccount *)account {
- NSString *topLevelUrlString = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"GRNetStorageUrlPrefix"];
- NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@?format=json",topLevelUrlString]];
+ NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@?format=json",account.provider.authEndpointURL]];
return [OpenStackRequest request:account method:@"GET" url:url];
}
filesUrl = [NSString stringWithFormat:@"%@%@",
[urlString substringToIndex:authUserRange.location],
account.sharingAccount];
- } else {
+ } else
filesUrl = urlString;
- }
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@%@?format=json%@&now=%@",
filesUrl,
path,
account.shared ? @"&shared=" : @"",
- now]];
+ now]];
+
return [OpenStackRequest request:account method:method url:url];
}
return [OpenStackRequest request:account method:method url:url];
}
+
#pragma mark -
#pragma mark Auth Retry
- (void)authRetrySucceded:(OpenStackRequest *)retryRequest {
-
if ([self isKindOfClass:[GetFlavorsRequest class]]) {
NSLog(@"flavor request");
}
-
- self.account.authToken = [[retryRequest responseHeaders] objectForKey:@"X-Auth-Token"];
+ self.account.authToken = [[retryRequest responseHeaders] objectForKey:@"X-Auth-Token"];
[self.account persist];
// TODO: make this work for GetServersRequest, etc
// try the original request again!
retried = YES;
retriedRequest = [self copy];
+
[retriedRequest addRequestHeader:@"X-Auth-Token" value:self.account.authToken];
if (backupCompletionBlock) {
backupFailureBlock();
}];
}
+
[retriedRequest startSynchronous];
}
- (void)authRetryFailed:(OpenStackRequest *)retryRequest {
// if it fails due to bad connection, try again?
- NSLog(@"auth retry failed with status %i", retryRequest.responseStatusCode);
NSNotification *notification = [NSNotification notificationWithName:[self.account.manager notificationName:@"authRetryFailed" identifier:0] object:nil userInfo:[NSDictionary dictionaryWithObject:retryRequest forKey:@"request"]];
[[NSNotificationCenter defaultCenter] postNotification:notification];
}
}
- (void)failWithError:(NSError *)theError {
-
if (responseStatusCode == 401 && ![url isEqual:account.provider.authEndpointURL]) {
// auth is expired, so get a fresh token
- if (account) {
+ if (account && ![account.provider isGRNet]) {
OpenStackRequest *retryRequest = [OpenStackRequest authenticationRequest:account];
retryRequest.delegate = self;
retryRequest.didFinishSelector = @selector(authRetrySucceded:);
}
}
+
+
+ (OpenStackRequest *)authenticationRequest:(OpenStackAccount *)account {
OpenStackRequest *request = [[[OpenStackRequest alloc] initWithURL:account.provider.authEndpointURL] autorelease];
}
+ (OpenStackRequest *)createContainerRequest:(OpenStackAccount *)account container:(Container *)container {
- return [OpenStackRequest filesRequest:account method:@"PUT" path:[[NSString stringWithFormat:@"/%@", container.name] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
+ return [OpenStackRequest filesRequest:account method:@"PUT" path:[NSString stringWithFormat:@"/%@", [NSString encodeToPercentEscape:container.name]]];
}
+ (OpenStackRequest *)deleteContainerRequest:(OpenStackAccount *)account container:(Container *)container {
- return [OpenStackRequest filesRequest:account method:@"DELETE" path:[[NSString stringWithFormat:@"/%@", container.name] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
+ return [OpenStackRequest filesRequest:account method:@"DELETE" path:[NSString stringWithFormat:@"/%@", [NSString encodeToPercentEscape:container.name]]];
}
+ (OpenStackRequest *)getObjectsRequest:(OpenStackAccount *)account container:(Container *)container {
- return [OpenStackRequest filesRequest:account method:@"GET" path:[[NSString stringWithFormat:@"/%@", container.name] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
+ return [OpenStackRequest filesRequest:account method:@"GET" path:[NSString stringWithFormat:@"/%@", [NSString encodeToPercentEscape:container.name]]];
}
- (NSMutableDictionary *)objects {
SBJSON *parser = [[SBJSON alloc] init];
NSArray *jsonObjects = [parser objectWithString:[self responseString]];
+
NSMutableDictionary *objects = [[[NSMutableDictionary alloc] initWithCapacity:[jsonObjects count]] autorelease];
for (int i = 0; i < [jsonObjects count]; i++) {
}
+ (OpenStackRequest *)getObjectInfoRequest:(OpenStackAccount *)account container:(Container *)container object:(StorageObject *)object {
- return [OpenStackRequest filesRequest:account method:@"HEAD" path:[[NSString stringWithFormat:@"/%@/%@", container.name, object.fullPath] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
+ return [OpenStackRequest filesRequest:account method:@"HEAD" path:[NSString stringWithFormat:@"/%@/%@",[NSString encodeToPercentEscape:container.name], [NSString encodeToPercentEscape:object.fullPath charactersToEncode:@"!*'();:@&=+$,?%#[]"]]];
}
+ (OpenStackRequest *)getObjectRequest:(OpenStackAccount *)account container:(Container *)container object:(StorageObject *)object {
- return [OpenStackRequest filesRequest:account method:@"GET" path:[[NSString stringWithFormat:@"/%@/%@", container.name, object.fullPath] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
+ return [OpenStackRequest filesRequest:account method:@"GET" path:[NSString stringWithFormat:@"/%@/%@",[NSString encodeToPercentEscape:container.name], [NSString encodeToPercentEscape:object.fullPath charactersToEncode:@"!*'();:@&=+$,?%#[]"]]];
}
+ (OpenStackRequest *)writeObjectRequest:(OpenStackAccount *)account container:(Container *)container object:(StorageObject *)object {
if ([fullPath characterAtIndex:0] == '/') {
fullPath = [fullPath substringFromIndex:1];
}
+
+ OpenStackRequest *request = [OpenStackRequest filesRequest:account method:@"PUT" path:[NSString stringWithFormat:@"/%@/%@",[NSString encodeToPercentEscape:container.name], [NSString encodeToPercentEscape:fullPath charactersToEncode:@"!*'();:@&=+$,?%#[]"]]];
- OpenStackRequest *request = [OpenStackRequest filesRequest:account method:@"PUT" path:[[NSString stringWithFormat:@"/%@/%@", container.name, fullPath] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
+ if (object.sharing)
+ [request.requestHeaders setObject:object.sharing forKey:@"X-Object-Sharing"];
+
+ NSString *metadataKeyHeaderPrefix;
+ if ([fullPath length] == 0)
+ metadataKeyHeaderPrefix = @"X-Container-Meta-";
+ else
+ metadataKeyHeaderPrefix = @"X-Object-Meta-";
+
+ for (NSString *metadataKey in object.metadata) {
+ NSString *metadataKeyHeader = [NSString stringWithFormat:@"%@%@", metadataKeyHeaderPrefix, metadataKey];
+ metadataKeyHeader = [NSString encodeToPercentEscape:metadataKeyHeader];
+ NSString *metadataValue = [NSString encodeToPercentEscape:[object.metadata objectForKey:metadataKey]];
+ [request.requestHeaders setObject:metadataValue forKey:metadataKeyHeader];
+ }
+
[request setPostBody:[NSMutableData dataWithData:object.data]];
- [request.requestHeaders setObject:object.contentType forKey:@"Content-Type"];
+ [request.requestHeaders setObject:object.contentType forKey:@"Content-Type"];
return request;
}
+ (OpenStackRequest *)writeObjectMetadataRequest:(OpenStackAccount *)account container:(Container *)container object:(StorageObject *)object {
- NSString *fullPath = [NSString stringWithString:object.fullPath];
- if ([fullPath length] && ([fullPath characterAtIndex:0] == '/'))
+ NSString *fullPath = object.fullPath;
+ if ([fullPath length] != 0 && [fullPath characterAtIndex:0] == '/') {
fullPath = [fullPath substringFromIndex:1];
+ }
NSString *metadataKeyHeaderPrefix;
- if (![fullPath length])
+ if ([fullPath length] == 0)
metadataKeyHeaderPrefix = @"X-Container-Meta-";
else
metadataKeyHeaderPrefix = @"X-Object-Meta-";
- OpenStackRequest *request = [OpenStackRequest filesRequest:account method:@"POST" path:[[NSString stringWithFormat:@"/%@/%@", container.name, fullPath] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
-
+ OpenStackRequest *request = [OpenStackRequest filesRequest:account method:@"POST" path:[NSString stringWithFormat:@"/%@/%@",[NSString encodeToPercentEscape:container.name], [NSString encodeToPercentEscape:fullPath charactersToEncode:@"!*'();:@&=+$,?%#[]"]]];
+
for (NSString *metadataKey in object.metadata) {
NSString *metadataKeyHeader = [NSString stringWithFormat:@"%@%@", metadataKeyHeaderPrefix, metadataKey];
- [request.requestHeaders setObject:[object.metadata objectForKey:metadataKey] forKey:metadataKeyHeader];
+ metadataKeyHeader = [NSString encodeToPercentEscape:metadataKeyHeader];
+ NSString *metadataValue = [NSString encodeToPercentEscape:[object.metadata objectForKey:metadataKey]];
+ [request.requestHeaders setObject:metadataValue forKey:metadataKeyHeader];
}
if (!account.sharingAccount) {
- NSString *objectIsPublic = ([object.publicURI length]) ? @"true" : @"false";
+ NSString *objectIsPublic = ([object.publicURI length] > 0) ? @"true" : @"false";
[request.requestHeaders setObject:objectIsPublic forKey:@"X-Object-Public"];
- if (object.sharing)
- [request.requestHeaders setObject:object.sharing forKey:@"X-Object-Sharing"];
+ if (object.sharing) {
+ NSString *urlEncodedSharingString = [NSString encodeToPercentEscape:object.sharing];
+ [request.requestHeaders setObject:urlEncodedSharingString forKey:@"X-Object-Sharing"];
+ }
}
-
return request;
}
+
+ (OpenStackRequest *)deleteObjectRequest:(OpenStackAccount *)account container:(Container *)container object:(StorageObject *)object {
if ([object.fullPath characterAtIndex:0] == '/') {
- return [OpenStackRequest filesRequest:account method:@"DELETE" path:[[NSString stringWithFormat:@"/%@%@", container.name, object.fullPath] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
+ return [OpenStackRequest filesRequest:account method:@"DELETE" path:[NSString stringWithFormat:@"/%@%@",[NSString encodeToPercentEscape:container.name], [NSString encodeToPercentEscape:object.fullPath charactersToEncode:@"!*'();:@&=+$,?%#[]"]]];
} else {
- return [OpenStackRequest filesRequest:account method:@"DELETE" path:[[NSString stringWithFormat:@"/%@/%@", container.name, object.fullPath] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
+ return [OpenStackRequest filesRequest:account method:@"DELETE" path:[NSString stringWithFormat:@"/%@/%@",[NSString encodeToPercentEscape:container.name], [NSString encodeToPercentEscape:object.fullPath charactersToEncode:@"!*'();:@&=+$,?%#[]"]]];
}
}
+ (OpenStackRequest *)writeContainerPolicyRequest:(OpenStackAccount *)account container:(Container *)container
{
- OpenStackRequest *request = [OpenStackRequest filesRequest:account method:@"PUT" path:[[NSString stringWithFormat:@"/%@", container.name] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
+ OpenStackRequest *request = [OpenStackRequest filesRequest:account method:@"PUT" path:[NSString stringWithFormat:@"/%@", [NSString encodeToPercentEscape:container.name]]];
[request.requestHeaders setObject:container.versioning forKey:@"X-Container-Policy-Versioning"];
- [request.requestHeaders setObject:[NSString stringWithFormat:@"%lu", container.quota] forKey:@"X-Container-Policy-Quota"];
+ [request.requestHeaders setObject:[NSString stringWithFormat:@"%u", container.quota] forKey:@"X-Container-Policy-Quota"];
return request;
}
NSMutableDictionary *groups = [accountInfo objectForKey:@"groups"];
for (NSString *groupName in groups) {
- [request.requestHeaders setObject:[groups objectForKey:groupName] forKey:[NSString stringWithFormat:@"X-Account-Group-%@", groupName]];
+ NSString *group = [NSString encodeToPercentEscape:[groups objectForKey:groupName]];
+ groupName = [NSString encodeToPercentEscape:groupName];
+ [request.requestHeaders setObject:group forKey:[NSString stringWithFormat:@"X-Account-Group-%@", groupName]];
}
if ([groups count] == 0)
[request.requestHeaders setObject:@"" forKey:@"X-Account-Group-group"];
NSMutableDictionary *accountMetadata = [accountInfo objectForKey:@"metadata"];
for (NSString *metadataKey in accountMetadata) {
- [request.requestHeaders setObject:[accountMetadata objectForKey:metadataKey] forKey:[NSString stringWithFormat:@"X-Account-Meta-%@",metadataKey]];
+ NSString *metadataValue = [NSString encodeToPercentEscape:[accountMetadata objectForKey:metadataKey]];
+ metadataKey = [NSString encodeToPercentEscape:[accountMetadata objectForKey:metadataKey]];
+ [request.requestHeaders setObject:metadataValue forKey:[NSString stringWithFormat:@"X-Account-Meta-%@",metadataKey]];
}
return request;
}
+
#pragma mark -
#pragma mark Memory Management