Revision 45f2fce6 Classes/OpenStackRequest.m
b/Classes/OpenStackRequest.m | ||
---|---|---|
23 | 23 |
#import "GetFlavorsRequest.h" |
24 | 24 |
#import "APICallback.h" |
25 | 25 |
#import "APILogEntry.h" |
26 |
#import "NSString+Conveniences.h" |
|
26 | 27 |
|
27 | 28 |
|
28 | 29 |
static NSRecursiveLock *accessDetailsLock = nil; |
... | ... | |
44 | 45 |
- (void)notify { |
45 | 46 |
NSString *observeName = [NSString stringWithFormat:@"%@ %@ %@", [self isSuccess] ? @"SUCCESS" : @"FAILURE", self.requestMethod, [self.url description]]; |
46 | 47 |
NSString *callbackName = [NSString stringWithFormat:@"%@ %@ %@ %@", [self isSuccess] ? @"SUCCESS" : @"FAILURE", self.requestMethod, [self.url description], self.callback.uuid]; |
47 |
|
|
48 |
|
|
48 | 49 |
NSDictionary *callbackUserInfo = [NSDictionary dictionaryWithObject:self forKey:@"response"]; |
49 | 50 |
|
50 | 51 |
NSNotification *observeNotification = [NSNotification notificationWithName:observeName object:nil userInfo:callbackUserInfo]; |
... | ... | |
149 | 150 |
[request addRequestHeader:@"X-Auth-Token" value:[account authToken]]; |
150 | 151 |
[request addRequestHeader:@"Content-Type" value:@"application/json"]; |
151 | 152 |
[request setTimeOutSeconds:60]; |
153 |
[request setNumberOfTimesToRetryOnTimeout:5]; |
|
152 | 154 |
request.retriedCount = 0; |
153 | 155 |
return request; |
154 | 156 |
} |
155 | 157 |
|
156 | 158 |
+ (id)getSharingAccountsRequest:(OpenStackAccount *)account { |
157 |
NSString *topLevelUrlString = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"GRNetStorageUrlPrefix"]; |
|
158 |
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@?format=json",topLevelUrlString]]; |
|
159 |
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@?format=json",account.provider.authEndpointURL]]; |
|
159 | 160 |
return [OpenStackRequest request:account method:@"GET" url:url]; |
160 | 161 |
} |
161 | 162 |
|
... | ... | |
175 | 176 |
filesUrl = [NSString stringWithFormat:@"%@%@", |
176 | 177 |
[urlString substringToIndex:authUserRange.location], |
177 | 178 |
account.sharingAccount]; |
178 |
} else {
|
|
179 |
} else |
|
179 | 180 |
filesUrl = urlString; |
180 |
} |
|
181 | 181 |
|
182 | 182 |
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@%@?format=json%@&now=%@", |
183 | 183 |
filesUrl, |
184 | 184 |
path, |
185 | 185 |
account.shared ? @"&shared=" : @"", |
186 |
now]]; |
|
186 |
now]]; |
|
187 |
|
|
187 | 188 |
return [OpenStackRequest request:account method:method url:url]; |
188 | 189 |
} |
189 | 190 |
|
... | ... | |
193 | 194 |
return [OpenStackRequest request:account method:method url:url]; |
194 | 195 |
} |
195 | 196 |
|
197 |
|
|
196 | 198 |
#pragma mark - |
197 | 199 |
#pragma mark Auth Retry |
198 | 200 |
|
199 | 201 |
- (void)authRetrySucceded:(OpenStackRequest *)retryRequest { |
200 |
|
|
201 | 202 |
if ([self isKindOfClass:[GetFlavorsRequest class]]) { |
202 | 203 |
NSLog(@"flavor request"); |
203 | 204 |
} |
204 |
|
|
205 |
self.account.authToken = [[retryRequest responseHeaders] objectForKey:@"X-Auth-Token"]; |
|
205 |
self.account.authToken = [[retryRequest responseHeaders] objectForKey:@"X-Auth-Token"]; |
|
206 | 206 |
[self.account persist]; |
207 | 207 |
|
208 | 208 |
// TODO: make this work for GetServersRequest, etc |
... | ... | |
210 | 210 |
// try the original request again! |
211 | 211 |
retried = YES; |
212 | 212 |
retriedRequest = [self copy]; |
213 |
|
|
213 | 214 |
[retriedRequest addRequestHeader:@"X-Auth-Token" value:self.account.authToken]; |
214 | 215 |
|
215 | 216 |
if (backupCompletionBlock) { |
... | ... | |
222 | 223 |
backupFailureBlock(); |
223 | 224 |
}]; |
224 | 225 |
} |
226 |
|
|
225 | 227 |
[retriedRequest startSynchronous]; |
226 | 228 |
} |
227 | 229 |
|
228 | 230 |
- (void)authRetryFailed:(OpenStackRequest *)retryRequest { |
229 | 231 |
// if it fails due to bad connection, try again? |
230 |
NSLog(@"auth retry failed with status %i", retryRequest.responseStatusCode); |
|
231 | 232 |
NSNotification *notification = [NSNotification notificationWithName:[self.account.manager notificationName:@"authRetryFailed" identifier:0] object:nil userInfo:[NSDictionary dictionaryWithObject:retryRequest forKey:@"request"]]; |
232 | 233 |
[[NSNotificationCenter defaultCenter] postNotification:notification]; |
233 | 234 |
} |
... | ... | |
248 | 249 |
} |
249 | 250 |
|
250 | 251 |
- (void)failWithError:(NSError *)theError { |
251 |
|
|
252 | 252 |
if (responseStatusCode == 401 && ![url isEqual:account.provider.authEndpointURL]) { |
253 | 253 |
// auth is expired, so get a fresh token |
254 |
if (account) { |
|
254 |
if (account && ![account.provider isGRNet]) {
|
|
255 | 255 |
OpenStackRequest *retryRequest = [OpenStackRequest authenticationRequest:account]; |
256 | 256 |
retryRequest.delegate = self; |
257 | 257 |
retryRequest.didFinishSelector = @selector(authRetrySucceded:); |
... | ... | |
320 | 320 |
} |
321 | 321 |
} |
322 | 322 |
|
323 |
|
|
324 |
|
|
323 | 325 |
+ (OpenStackRequest *)authenticationRequest:(OpenStackAccount *)account { |
324 | 326 |
|
325 | 327 |
OpenStackRequest *request = [[[OpenStackRequest alloc] initWithURL:account.provider.authEndpointURL] autorelease]; |
... | ... | |
628 | 630 |
} |
629 | 631 |
|
630 | 632 |
+ (OpenStackRequest *)createContainerRequest:(OpenStackAccount *)account container:(Container *)container { |
631 |
return [OpenStackRequest filesRequest:account method:@"PUT" path:[[NSString stringWithFormat:@"/%@", container.name] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
|
|
633 |
return [OpenStackRequest filesRequest:account method:@"PUT" path:[NSString stringWithFormat:@"/%@", [NSString encodeToPercentEscape:container.name]]];
|
|
632 | 634 |
} |
633 | 635 |
|
634 | 636 |
+ (OpenStackRequest *)deleteContainerRequest:(OpenStackAccount *)account container:(Container *)container { |
635 |
return [OpenStackRequest filesRequest:account method:@"DELETE" path:[[NSString stringWithFormat:@"/%@", container.name] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
|
|
637 |
return [OpenStackRequest filesRequest:account method:@"DELETE" path:[NSString stringWithFormat:@"/%@", [NSString encodeToPercentEscape:container.name]]];
|
|
636 | 638 |
} |
637 | 639 |
|
638 | 640 |
+ (OpenStackRequest *)getObjectsRequest:(OpenStackAccount *)account container:(Container *)container { |
639 |
return [OpenStackRequest filesRequest:account method:@"GET" path:[[NSString stringWithFormat:@"/%@", container.name] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
|
|
641 |
return [OpenStackRequest filesRequest:account method:@"GET" path:[NSString stringWithFormat:@"/%@", [NSString encodeToPercentEscape:container.name]]];
|
|
640 | 642 |
} |
641 | 643 |
|
642 | 644 |
- (NSMutableDictionary *)objects { |
643 | 645 |
SBJSON *parser = [[SBJSON alloc] init]; |
644 | 646 |
NSArray *jsonObjects = [parser objectWithString:[self responseString]]; |
647 |
|
|
645 | 648 |
NSMutableDictionary *objects = [[[NSMutableDictionary alloc] initWithCapacity:[jsonObjects count]] autorelease]; |
646 | 649 |
|
647 | 650 |
for (int i = 0; i < [jsonObjects count]; i++) { |
... | ... | |
655 | 658 |
} |
656 | 659 |
|
657 | 660 |
+ (OpenStackRequest *)getObjectInfoRequest:(OpenStackAccount *)account container:(Container *)container object:(StorageObject *)object { |
658 |
return [OpenStackRequest filesRequest:account method:@"HEAD" path:[[NSString stringWithFormat:@"/%@/%@", container.name, object.fullPath] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
|
|
661 |
return [OpenStackRequest filesRequest:account method:@"HEAD" path:[NSString stringWithFormat:@"/%@/%@",[NSString encodeToPercentEscape:container.name], [NSString encodeToPercentEscape:object.fullPath charactersToEncode:@"!*'();:@&=+$,?%#[]"]]];
|
|
659 | 662 |
} |
660 | 663 |
|
661 | 664 |
+ (OpenStackRequest *)getObjectRequest:(OpenStackAccount *)account container:(Container *)container object:(StorageObject *)object { |
662 |
return [OpenStackRequest filesRequest:account method:@"GET" path:[[NSString stringWithFormat:@"/%@/%@", container.name, object.fullPath] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
|
|
665 |
return [OpenStackRequest filesRequest:account method:@"GET" path:[NSString stringWithFormat:@"/%@/%@",[NSString encodeToPercentEscape:container.name], [NSString encodeToPercentEscape:object.fullPath charactersToEncode:@"!*'();:@&=+$,?%#[]"]]];
|
|
663 | 666 |
} |
664 | 667 |
|
665 | 668 |
+ (OpenStackRequest *)writeObjectRequest:(OpenStackAccount *)account container:(Container *)container object:(StorageObject *)object { |
... | ... | |
667 | 670 |
if ([fullPath characterAtIndex:0] == '/') { |
668 | 671 |
fullPath = [fullPath substringFromIndex:1]; |
669 | 672 |
} |
673 |
|
|
674 |
OpenStackRequest *request = [OpenStackRequest filesRequest:account method:@"PUT" path:[NSString stringWithFormat:@"/%@/%@",[NSString encodeToPercentEscape:container.name], [NSString encodeToPercentEscape:fullPath charactersToEncode:@"!*'();:@&=+$,?%#[]"]]]; |
|
670 | 675 |
|
671 |
OpenStackRequest *request = [OpenStackRequest filesRequest:account method:@"PUT" path:[[NSString stringWithFormat:@"/%@/%@", container.name, fullPath] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; |
|
676 |
if (object.sharing) |
|
677 |
[request.requestHeaders setObject:object.sharing forKey:@"X-Object-Sharing"]; |
|
678 |
|
|
679 |
NSString *metadataKeyHeaderPrefix; |
|
680 |
if ([fullPath length] == 0) |
|
681 |
metadataKeyHeaderPrefix = @"X-Container-Meta-"; |
|
682 |
else |
|
683 |
metadataKeyHeaderPrefix = @"X-Object-Meta-"; |
|
684 |
|
|
685 |
for (NSString *metadataKey in object.metadata) { |
|
686 |
NSString *metadataKeyHeader = [NSString stringWithFormat:@"%@%@", metadataKeyHeaderPrefix, metadataKey]; |
|
687 |
metadataKeyHeader = [NSString encodeToPercentEscape:metadataKeyHeader]; |
|
688 |
NSString *metadataValue = [NSString encodeToPercentEscape:[object.metadata objectForKey:metadataKey]]; |
|
689 |
[request.requestHeaders setObject:metadataValue forKey:metadataKeyHeader]; |
|
690 |
} |
|
691 |
|
|
672 | 692 |
[request setPostBody:[NSMutableData dataWithData:object.data]]; |
673 |
[request.requestHeaders setObject:object.contentType forKey:@"Content-Type"]; |
|
693 |
[request.requestHeaders setObject:object.contentType forKey:@"Content-Type"];
|
|
674 | 694 |
return request; |
675 | 695 |
} |
676 | 696 |
|
677 | 697 |
+ (OpenStackRequest *)writeObjectMetadataRequest:(OpenStackAccount *)account container:(Container *)container object:(StorageObject *)object { |
678 |
NSString *fullPath = [NSString stringWithString:object.fullPath];
|
|
679 |
if ([fullPath length] && ([fullPath characterAtIndex:0] == '/'))
|
|
698 |
NSString *fullPath = object.fullPath;
|
|
699 |
if ([fullPath length] != 0 && [fullPath characterAtIndex:0] == '/') {
|
|
680 | 700 |
fullPath = [fullPath substringFromIndex:1]; |
701 |
} |
|
681 | 702 |
|
682 | 703 |
NSString *metadataKeyHeaderPrefix; |
683 |
if (![fullPath length])
|
|
704 |
if ([fullPath length] == 0)
|
|
684 | 705 |
metadataKeyHeaderPrefix = @"X-Container-Meta-"; |
685 | 706 |
else |
686 | 707 |
metadataKeyHeaderPrefix = @"X-Object-Meta-"; |
687 | 708 |
|
688 |
OpenStackRequest *request = [OpenStackRequest filesRequest:account method:@"POST" path:[[NSString stringWithFormat:@"/%@/%@", container.name, fullPath] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
|
|
689 |
|
|
709 |
OpenStackRequest *request = [OpenStackRequest filesRequest:account method:@"POST" path:[NSString stringWithFormat:@"/%@/%@",[NSString encodeToPercentEscape:container.name], [NSString encodeToPercentEscape:fullPath charactersToEncode:@"!*'();:@&=+$,?%#[]"]]];
|
|
710 |
|
|
690 | 711 |
for (NSString *metadataKey in object.metadata) { |
691 | 712 |
NSString *metadataKeyHeader = [NSString stringWithFormat:@"%@%@", metadataKeyHeaderPrefix, metadataKey]; |
692 |
[request.requestHeaders setObject:[object.metadata objectForKey:metadataKey] forKey:metadataKeyHeader]; |
|
713 |
metadataKeyHeader = [NSString encodeToPercentEscape:metadataKeyHeader]; |
|
714 |
NSString *metadataValue = [NSString encodeToPercentEscape:[object.metadata objectForKey:metadataKey]]; |
|
715 |
[request.requestHeaders setObject:metadataValue forKey:metadataKeyHeader]; |
|
693 | 716 |
} |
694 | 717 |
if (!account.sharingAccount) { |
695 |
NSString *objectIsPublic = ([object.publicURI length]) ? @"true" : @"false"; |
|
718 |
NSString *objectIsPublic = ([object.publicURI length] > 0) ? @"true" : @"false";
|
|
696 | 719 |
[request.requestHeaders setObject:objectIsPublic forKey:@"X-Object-Public"]; |
697 | 720 |
|
698 |
if (object.sharing) |
|
699 |
[request.requestHeaders setObject:object.sharing forKey:@"X-Object-Sharing"]; |
|
721 |
if (object.sharing) { |
|
722 |
NSString *urlEncodedSharingString = [NSString encodeToPercentEscape:object.sharing]; |
|
723 |
[request.requestHeaders setObject:urlEncodedSharingString forKey:@"X-Object-Sharing"]; |
|
724 |
} |
|
700 | 725 |
} |
701 |
|
|
702 | 726 |
return request; |
703 | 727 |
} |
704 | 728 |
|
729 |
|
|
705 | 730 |
+ (OpenStackRequest *)deleteObjectRequest:(OpenStackAccount *)account container:(Container *)container object:(StorageObject *)object { |
706 | 731 |
if ([object.fullPath characterAtIndex:0] == '/') { |
707 |
return [OpenStackRequest filesRequest:account method:@"DELETE" path:[[NSString stringWithFormat:@"/%@%@", container.name, object.fullPath] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
|
|
732 |
return [OpenStackRequest filesRequest:account method:@"DELETE" path:[NSString stringWithFormat:@"/%@%@",[NSString encodeToPercentEscape:container.name], [NSString encodeToPercentEscape:object.fullPath charactersToEncode:@"!*'();:@&=+$,?%#[]"]]];
|
|
708 | 733 |
} else { |
709 |
return [OpenStackRequest filesRequest:account method:@"DELETE" path:[[NSString stringWithFormat:@"/%@/%@", container.name, object.fullPath] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
|
|
734 |
return [OpenStackRequest filesRequest:account method:@"DELETE" path:[NSString stringWithFormat:@"/%@/%@",[NSString encodeToPercentEscape:container.name], [NSString encodeToPercentEscape:object.fullPath charactersToEncode:@"!*'();:@&=+$,?%#[]"]]];
|
|
710 | 735 |
} |
711 | 736 |
} |
712 | 737 |
|
713 | 738 |
+ (OpenStackRequest *)writeContainerPolicyRequest:(OpenStackAccount *)account container:(Container *)container |
714 | 739 |
{ |
715 |
OpenStackRequest *request = [OpenStackRequest filesRequest:account method:@"PUT" path:[[NSString stringWithFormat:@"/%@", container.name] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
|
|
740 |
OpenStackRequest *request = [OpenStackRequest filesRequest:account method:@"PUT" path:[NSString stringWithFormat:@"/%@", [NSString encodeToPercentEscape:container.name]]];
|
|
716 | 741 |
|
717 | 742 |
[request.requestHeaders setObject:container.versioning forKey:@"X-Container-Policy-Versioning"]; |
718 |
[request.requestHeaders setObject:[NSString stringWithFormat:@"%lu", container.quota] forKey:@"X-Container-Policy-Quota"];
|
|
743 |
[request.requestHeaders setObject:[NSString stringWithFormat:@"%u", container.quota] forKey:@"X-Container-Policy-Quota"]; |
|
719 | 744 |
|
720 | 745 |
return request; |
721 | 746 |
} |
... | ... | |
726 | 751 |
|
727 | 752 |
NSMutableDictionary *groups = [accountInfo objectForKey:@"groups"]; |
728 | 753 |
for (NSString *groupName in groups) { |
729 |
[request.requestHeaders setObject:[groups objectForKey:groupName] forKey:[NSString stringWithFormat:@"X-Account-Group-%@", groupName]]; |
|
754 |
NSString *group = [NSString encodeToPercentEscape:[groups objectForKey:groupName]]; |
|
755 |
groupName = [NSString encodeToPercentEscape:groupName]; |
|
756 |
[request.requestHeaders setObject:group forKey:[NSString stringWithFormat:@"X-Account-Group-%@", groupName]]; |
|
730 | 757 |
} |
731 | 758 |
if ([groups count] == 0) |
732 | 759 |
[request.requestHeaders setObject:@"" forKey:@"X-Account-Group-group"]; |
733 | 760 |
|
734 | 761 |
NSMutableDictionary *accountMetadata = [accountInfo objectForKey:@"metadata"]; |
735 | 762 |
for (NSString *metadataKey in accountMetadata) { |
736 |
[request.requestHeaders setObject:[accountMetadata objectForKey:metadataKey] forKey:[NSString stringWithFormat:@"X-Account-Meta-%@",metadataKey]]; |
|
763 |
NSString *metadataValue = [NSString encodeToPercentEscape:[accountMetadata objectForKey:metadataKey]]; |
|
764 |
metadataKey = [NSString encodeToPercentEscape:[accountMetadata objectForKey:metadataKey]]; |
|
765 |
[request.requestHeaders setObject:metadataValue forKey:[NSString stringWithFormat:@"X-Account-Meta-%@",metadataKey]]; |
|
737 | 766 |
} |
738 | 767 |
|
739 | 768 |
return request; |
740 | 769 |
} |
741 | 770 |
|
771 |
|
|
742 | 772 |
#pragma mark - |
743 | 773 |
#pragma mark Memory Management |
744 | 774 |
|
Also available in: Unified diff