Statistics
| Branch: | Revision:

root / asi-http-request-with-pithos / Classes / Pithos / ASIPithosRequest.m @ 6ba383d0

History | View | Annotate | Download (12.7 kB)

1
//  ASIPithosRequest.m
2
//  Based on ASICloudFilesRequest.m
3
//  Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
4
//
5
// Copyright 2011 GRNET S.A. All rights reserved.
6
//
7
// Redistribution and use in source and binary forms, with or
8
// without modification, are permitted provided that the following
9
// conditions are met:
10
// 
11
//   1. Redistributions of source code must retain the above
12
//      copyright notice, this list of conditions and the following
13
//      disclaimer.
14
// 
15
//   2. Redistributions in binary form must reproduce the above
16
//      copyright notice, this list of conditions and the following
17
//      disclaimer in the documentation and/or other materials
18
//      provided with the distribution.
19
// 
20
// THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
21
// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
24
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
27
// USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28
// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31
// POSSIBILITY OF SUCH DAMAGE.
32
// 
33
// The views and conclusions contained in the software and
34
// documentation are those of the authors and should not be
35
// interpreted as representing official policies, either expressed
36
// or implied, of GRNET S.A.
37

    
38
#import "ASIPithosRequest.h"
39
#import "ASIPithosAccount.h"
40

    
41
static NSString *authURL = nil;
42
static NSString *authUser = nil;
43
static NSString *authKey = nil;
44

    
45
static NSString *storageURLPrefix = nil;
46
static NSString *storageURL = nil;
47
static NSString *authToken = nil;
48

    
49
static NSString *publicURLPrefix = nil;
50

    
51
static NSRecursiveLock *accessDetailsLock = nil;
52

    
53
@implementation ASIPithosRequest
54
@synthesize currentElement, currentContent, currentAccount;
55

    
56
+ (void)initialize {
57
	if (self == [ASIPithosRequest class]) {
58
		accessDetailsLock = [[NSRecursiveLock alloc] init];
59
	}
60
}
61

    
62
#pragma mark -
63
#pragma mark Constructors
64

    
65
+ (id)authRequestWithMethod:(NSString *)method queryString:(NSString *)queryString useAuthToken:(BOOL)useAuthToken {
66
    NSString *urlString = [NSString stringWithString:authURL];
67
    if (queryString)
68
        urlString = [urlString stringByAppendingString:queryString];
69
    
70
	ASIPithosRequest *request = [[[self alloc] initWithURL:[NSURL URLWithString:urlString]] autorelease];
71
	[request setRequestMethod:method];
72
    if (useAuthToken)
73
        [request addRequestHeader:@"X-Auth-Token" value:authToken];
74
	return request;
75
}
76

    
77
+ (id)authRequestWithMethod:(NSString *)method useAuthToken:(BOOL)useAuthToken {
78
	return [self authRequestWithMethod:method queryString:nil useAuthToken:useAuthToken];
79
}
80

    
81
#pragma mark -
82
#pragma mark Memory Management
83

    
84
- (void)dealloc {
85
	[currentAccount release];
86
    [currentContent release];
87
    [currentElement release];
88
    [sharingAccounts release];
89
	[super dealloc];
90
}
91

    
92
#pragma mark -
93
#pragma mark Properties
94

    
95
+ (NSString *)authURL {
96
    return authURL;
97
}
98

    
99
+ (void)setAuthURL:(NSString *)newAuthURL {
100
	[accessDetailsLock lock];
101
	[authURL release];
102
	authURL = [newAuthURL retain];
103
	[accessDetailsLock unlock];
104
}
105

    
106
+ (NSString *)authUser {
107
	return authUser;
108
}
109

    
110
+ (void)setAuthUser:(NSString *)newAuthUser {
111
	[accessDetailsLock lock];
112
	[authUser release];
113
	authUser = [newAuthUser retain];
114
	[accessDetailsLock unlock];
115
}
116

    
117
+ (NSString *)authKey {
118
	return authKey;
119
}
120

    
121
+ (void)setAuthKey:(NSString *)newAuthKey {
122
	[accessDetailsLock lock];
123
	[authKey release];
124
	authKey = [newAuthKey retain];
125
	[accessDetailsLock unlock];
126
}
127

    
128
+ (NSString *)storageURLPrefix {
129
    return storageURLPrefix;
130
}
131

    
132
+ (void)setStorageURLPrefix:(NSString *)newStorageURLPrefix {
133
	[accessDetailsLock lock];
134
	[storageURLPrefix release];
135
	storageURLPrefix = [newStorageURLPrefix retain];
136
	[accessDetailsLock unlock];
137
}
138

    
139
+ (NSString *)storageURL {
140
    if (storageURL)
141
        return storageURL;
142
    else if (storageURLPrefix && authUser)
143
        return [NSString stringWithFormat:@"%@/%@", storageURLPrefix, [authUser stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
144
    return nil;
145
}
146

    
147
+ (void)setStorageURL:(NSString *)newStorageURL {
148
	[accessDetailsLock lock];
149
	[storageURL release];
150
	storageURL = [newStorageURL retain];
151
	[accessDetailsLock unlock];
152
}
153

    
154
+ (NSString *)authToken {
155
	return authToken;
156
}
157

    
158
+ (void)setAuthToken:(NSString *)newAuthToken {
159
	[accessDetailsLock lock];
160
	[authToken release];
161
	authToken = [newAuthToken retain];
162
	[accessDetailsLock unlock];
163
}
164

    
165
+ (NSString *)storageURLWithAuthUser:(NSString *)anAuthUser {
166
    if (storageURLPrefix)
167
        return [NSString stringWithFormat:@"%@/%@", storageURLPrefix, [anAuthUser stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
168
    return nil;
169
}
170

    
171
+ (NSString *)publicURLPrefix {
172
    return publicURLPrefix;
173
}
174

    
175
+ (void)setPublicURLPrefix:(NSString *)newPublicURLPrefix {
176
    [accessDetailsLock lock];
177
	[publicURLPrefix release];
178
	publicURLPrefix = [newPublicURLPrefix retain];
179
	[accessDetailsLock unlock];
180
}
181

    
182
#pragma mark -
183
#pragma mark Authentication
184

    
185
+ (id)authenticationRequest {
186
	[accessDetailsLock lock];
187
    ASIPithosRequest *request = [self authRequestWithMethod:@"GET" useAuthToken:NO];
188
	[request addRequestHeader:@"X-Auth-User" value:authUser];
189
	[request addRequestHeader:@"X-Auth-Key" value:authKey];
190
	[accessDetailsLock unlock];
191
	return request;
192
}
193

    
194
+ (NSError *)authenticate {
195
	[accessDetailsLock lock];
196
	ASIPithosRequest *request = [self authenticationRequest];
197
	[request startSynchronous];
198
	
199
	if (![request error]) {
200
		NSDictionary *responseHeaders = [request responseHeaders];
201
        [ASIPithosRequest setAuthToken:[responseHeaders objectForKey:@"X-Auth-Token"]];
202
        [ASIPithosRequest setStorageURL:[responseHeaders objectForKey:@"X-Storage-Url"]];
203
	}
204
	[accessDetailsLock unlock];
205
	return [request error];
206
}
207

    
208
#pragma mark -
209
#pragma mark GET
210

    
211
// GET authURL
212
+ (id)listSharingAccountsRequest {
213
    return [self authRequestWithMethod:@"GET" queryString:@"?format=xml" useAuthToken:YES];
214
}
215

    
216
// GET authURL?[limit=limit]&[marker=marker]
217
+ (id)listSharingAccountsRequestWith:(NSUInteger)limit marker:(NSString *)marker {
218
    NSString *queryString = @"?format=xml";
219
	if (limit && (limit > 0))
220
		queryString = [queryString stringByAppendingString:[NSString stringWithFormat:@"&limit=%lu", limit]];
221
	if (marker)
222
		queryString = [queryString stringByAppendingString:[NSString stringWithFormat:@"&marker=%@", [marker stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];
223
    
224
    return [self authRequestWithMethod:@"GET" queryString:queryString useAuthToken:YES];
225
}
226

    
227
- (NSArray *)sharingAccounts {
228
    if (sharingAccounts == nil) {
229
        sharingAccounts = [[NSMutableArray alloc] init];
230
        
231
        NSXMLParser *parser = [[[NSXMLParser alloc] initWithData:[self responseData]] autorelease];
232
        [parser setDelegate:self];
233
        [parser setShouldProcessNamespaces:NO];
234
        [parser setShouldReportNamespacePrefixes:NO];
235
        [parser setShouldResolveExternalEntities:NO];
236
        [parser parse];
237
    }    
238
	return sharingAccounts;
239
}
240

    
241
#pragma mark -
242
#pragma mark NSXMLParserDelegate
243

    
244
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
245
	self.currentElement = elementName;
246
	if ([elementName isEqualToString:@"account"]) {
247
		self.currentAccount = [ASIPithosAccount account];
248
	}
249
    
250
	self.currentContent = @"";
251
}
252

    
253
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
254
	if ([elementName isEqualToString:@"name"]) {
255
        currentAccount.name = currentContent;
256
    } else if ([elementName isEqualToString:@"last_modified"]) {
257
        currentAccount.lastModified = [[self dateFormatterWithFormatId:0] dateFromString:currentContent];
258
	} else if ([elementName isEqualToString:@"account"]) {
259
		[sharingAccounts addObject:currentAccount];
260
        self.currentAccount = nil;
261
	}
262
}
263

    
264
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
265
    self.currentContent = [currentContent stringByAppendingString:string];
266
}
267

    
268
#pragma mark -
269
#pragma mark Date Formatters
270

    
271
// We store our date formatters in the calling thread's dictionary
272
// NSDateFormatter is not thread-safe, this approach ensures each formatter is only used on a single thread
273
// Each formatter can be reused many times in parsing a single response, so it would be expensive to keep creating new date formatters
274

    
275
-(NSDateFormatter *)dateFormatterWithFormatId:(NSUInteger)formatId {
276
    NSMutableDictionary *threadDict = [[NSThread currentThread] threadDictionary];
277
    NSString *dateFormatterKey = [NSString stringWithFormat:@"ASIPithosDateFormatter%lu", formatId];
278
    NSDateFormatter *dateFormatter = [threadDict objectForKey:dateFormatterKey];
279
	if (dateFormatter == nil) {
280
        switch (formatId) {
281
            case 0:
282
                // date format: 2009-11-04T19:46:20.192723
283
                // Needed for last_modified
284
                dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
285
                [dateFormatter setLocale:[[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"] autorelease]];
286
                [dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss"];
287
                [threadDict setObject:dateFormatter forKey:dateFormatterKey];
288
                break;
289
            case 1:
290
                // date format: Wed, 20 Jul 2011 13:39:19 GMT
291
                // Needed for reading X-Account-Until-Timestamp, Last-Modified
292
                dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
293
                [dateFormatter setLocale:[[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"] autorelease]];
294
                [dateFormatter setDateFormat:@"eee, dd MMM yyyy HH:mm:ss zzz"];
295
                [threadDict setObject:dateFormatter forKey:dateFormatterKey];
296
                break;
297
            case 2:
298
                // date to format: Thu Jul 21 10:54:45 2010
299
                // Can be used to write If-Modified-Since, If-Unmodified-Since in the request headers
300
                dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
301
                [dateFormatter setLocale:[[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"] autorelease]];
302
                [dateFormatter setDateFormat:@"eee MMM dd HH:mm:ss yyyy"];
303
                [threadDict setObject:dateFormatter forKey:dateFormatterKey];
304
                break;
305
            default:
306
                break;
307
        }
308
    }
309
    return dateFormatter;
310
}
311

    
312
#pragma mark -
313
#pragma mark Extra Headers
314

    
315
- (void)addRequestIfModifiedSinceHeader:(NSDate *)sinceTimestamp {
316
    if (sinceTimestamp)
317
        [self addRequestHeader:@"If-Modified-Since" value:[[self dateFormatterWithFormatId:2] stringFromDate:sinceTimestamp]];        
318
}
319

    
320
- (void)addRequestIfUnmodifiedSinceHeader:(NSDate *)sinceTimestamp {
321
    if (sinceTimestamp)
322
        [self addRequestHeader:@"If-Unmodified-Since" value:[[self dateFormatterWithFormatId:2] stringFromDate:sinceTimestamp]];
323
}
324

    
325
- (void)addRequestIfMatchHeader:(NSString *)matchETag {
326
    if (matchETag)
327
        [self addRequestHeader:@"If-Match" value:matchETag];
328
}
329

    
330
- (void)addRequestIfNoneMatchHeader:(NSString *)matchETag {
331
    if (matchETag)
332
        [self addRequestHeader:@"If-None-Match" value:matchETag];
333
}
334

    
335
- (void)addRequestRangeHeader:(NSString *)rangeString {
336
    if (rangeString)
337
        [self addRequestHeader:@"Range" value:rangeString];    
338
}
339

    
340
- (void)addRequestRangeHeader:(NSString *)rangeString ifRangeETag:(NSString *)rangeETag {
341
    if (rangeString) {
342
        [self addRequestHeader:@"Range" value:rangeString];
343
        if (rangeETag)
344
            [self addRequestHeader:@"If-Range" value:rangeETag];
345
    }
346
}
347

    
348
- (void)addRequestRangeHeader:(NSString *)rangeString ifRangeTimestamp:(NSDate *)rangeTimestamp {
349
    if (rangeString) {
350
        [self addRequestHeader:@"Range" value:rangeString];
351
        if (rangeTimestamp)
352
            [self addRequestHeader:@"If-Range" value:[[self dateFormatterWithFormatId:2] stringFromDate:rangeTimestamp]];
353
    }
354
}
355

    
356
#pragma mark -
357
#pragma mark Internal
358

    
359
- (NSMutableDictionary *)getHeadersDictionaryForPrefix:(NSString *)prefix {
360
    NSMutableDictionary *headersDictionary = [NSMutableDictionary dictionary];
361
    for (NSString *key in [[self responseHeaders] keyEnumerator]) {
362
        NSRange prefixRange = [key rangeOfString:prefix];
363
        if (prefixRange.location == 0) {
364
            [headersDictionary setObject:[[self responseHeaders] objectForKey:key] forKey:[key substringFromIndex:prefix.length]];
365
        }
366
    }
367
    return headersDictionary;
368
}
369

    
370
@end