Ben Copsey

Add test for S3 gzipped content

Tweaks to use accessor for cancelledLock
@@ -72,6 +72,7 @@ static NSError *ASITooMuchRedirectionError; @@ -72,6 +72,7 @@ static NSError *ASITooMuchRedirectionError;
72 @property (assign, nonatomic) int redirectCount; 72 @property (assign, nonatomic) int redirectCount;
73 @property (retain, nonatomic) NSData *compressedPostBody; 73 @property (retain, nonatomic) NSData *compressedPostBody;
74 @property (retain, nonatomic) NSString *compressedPostBodyFilePath; 74 @property (retain, nonatomic) NSString *compressedPostBodyFilePath;
  75 + @property (retain) NSConditionLock *authenticationLock;
75 @end 76 @end
76 77
77 @implementation ASIHTTPRequest 78 @implementation ASIHTTPRequest
@@ -428,15 +429,14 @@ static NSError *ASITooMuchRedirectionError; @@ -428,15 +429,14 @@ static NSError *ASITooMuchRedirectionError;
428 429
429 - (void)startRequest 430 - (void)startRequest
430 { 431 {
431 - [cancelledLock lock]; 432 + [[self cancelledLock] lock];
432 433
433 if ([self isCancelled]) { 434 if ([self isCancelled]) {
434 - [cancelledLock unlock]; 435 + [[self cancelledLock] unlock];
435 return; 436 return;
436 } 437 }
437 438
438 - [authenticationLock release]; 439 + [self setAuthenticationLock:[[[NSConditionLock alloc] initWithCondition:1] autorelease]];
439 - authenticationLock = [[NSConditionLock alloc] initWithCondition:1];  
440 440
441 [self setComplete:NO]; 441 [self setComplete:NO];
442 [self setTotalBytesRead:0]; 442 [self setTotalBytesRead:0];
@@ -470,7 +470,7 @@ static NSError *ASITooMuchRedirectionError; @@ -470,7 +470,7 @@ static NSError *ASITooMuchRedirectionError;
470 readStream = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, request); 470 readStream = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, request);
471 } 471 }
472 if (!readStream) { 472 if (!readStream) {
473 - [cancelledLock unlock]; 473 + [[self cancelledLock] unlock];
474 [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIInternalErrorWhileBuildingRequestType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Unable to create read stream",NSLocalizedDescriptionKey,nil]]]; 474 [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIInternalErrorWhileBuildingRequestType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Unable to create read stream",NSLocalizedDescriptionKey,nil]]];
475 return; 475 return;
476 } 476 }
@@ -502,7 +502,7 @@ static NSError *ASITooMuchRedirectionError; @@ -502,7 +502,7 @@ static NSError *ASITooMuchRedirectionError;
502 if (!CFReadStreamSetClient(readStream, kNetworkEvents, ReadStreamClientCallBack, &ctxt)) { 502 if (!CFReadStreamSetClient(readStream, kNetworkEvents, ReadStreamClientCallBack, &ctxt)) {
503 CFRelease(readStream); 503 CFRelease(readStream);
504 readStream = NULL; 504 readStream = NULL;
505 - [cancelledLock unlock]; 505 + [[self cancelledLock] unlock];
506 [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIInternalErrorWhileBuildingRequestType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Unable to setup read stream",NSLocalizedDescriptionKey,nil]]]; 506 [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIInternalErrorWhileBuildingRequestType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Unable to setup read stream",NSLocalizedDescriptionKey,nil]]];
507 return; 507 return;
508 } 508 }
@@ -516,11 +516,11 @@ static NSError *ASITooMuchRedirectionError; @@ -516,11 +516,11 @@ static NSError *ASITooMuchRedirectionError;
516 CFReadStreamUnscheduleFromRunLoop(readStream, CFRunLoopGetCurrent(), ASIHTTPRequestRunMode); 516 CFReadStreamUnscheduleFromRunLoop(readStream, CFRunLoopGetCurrent(), ASIHTTPRequestRunMode);
517 CFRelease(readStream); 517 CFRelease(readStream);
518 readStream = NULL; 518 readStream = NULL;
519 - [cancelledLock unlock]; 519 + [[self cancelledLock] unlock];
520 [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIInternalErrorWhileBuildingRequestType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Unable to start HTTP connection",NSLocalizedDescriptionKey,nil]]]; 520 [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIInternalErrorWhileBuildingRequestType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Unable to start HTTP connection",NSLocalizedDescriptionKey,nil]]];
521 return; 521 return;
522 } 522 }
523 - [cancelledLock unlock]; 523 + [[self cancelledLock] unlock];
524 524
525 525
526 if (shouldResetProgressIndicators) { 526 if (shouldResetProgressIndicators) {
@@ -606,7 +606,7 @@ static NSError *ASITooMuchRedirectionError; @@ -606,7 +606,7 @@ static NSError *ASITooMuchRedirectionError;
606 // Cancel loading and clean up 606 // Cancel loading and clean up
607 - (void)cancelLoad 607 - (void)cancelLoad
608 { 608 {
609 - [cancelledLock lock]; 609 + [[self cancelledLock] lock];
610 if (readStream) { 610 if (readStream) {
611 CFReadStreamClose(readStream); 611 CFReadStreamClose(readStream);
612 CFReadStreamSetClient(readStream, kCFStreamEventNone, NULL, NULL); 612 CFReadStreamSetClient(readStream, kCFStreamEventNone, NULL, NULL);
@@ -636,7 +636,7 @@ static NSError *ASITooMuchRedirectionError; @@ -636,7 +636,7 @@ static NSError *ASITooMuchRedirectionError;
636 } 636 }
637 637
638 [self setResponseHeaders:nil]; 638 [self setResponseHeaders:nil];
639 - [cancelledLock unlock]; 639 + [[self cancelledLock] unlock];
640 } 640 }
641 641
642 642
@@ -738,9 +738,9 @@ static NSError *ASITooMuchRedirectionError; @@ -738,9 +738,9 @@ static NSError *ASITooMuchRedirectionError;
738 738
739 - (void)updateUploadProgress 739 - (void)updateUploadProgress
740 { 740 {
741 - [cancelledLock lock]; 741 + [[self cancelledLock] lock];
742 if ([self isCancelled]) { 742 if ([self isCancelled]) {
743 - [cancelledLock unlock]; 743 + [[self cancelledLock] unlock];
744 return; 744 return;
745 } 745 }
746 746
@@ -763,7 +763,7 @@ static NSError *ASITooMuchRedirectionError; @@ -763,7 +763,7 @@ static NSError *ASITooMuchRedirectionError;
763 763
764 764
765 765
766 - [cancelledLock unlock]; 766 + [[self cancelledLock] unlock];
767 767
768 if (totalBytesSent == 0) { 768 if (totalBytesSent == 0) {
769 return; 769 return;
@@ -1250,7 +1250,7 @@ static NSError *ASITooMuchRedirectionError; @@ -1250,7 +1250,7 @@ static NSError *ASITooMuchRedirectionError;
1250 [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIInternalErrorWhileApplyingCredentialsType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Failed to apply credentials to request",NSLocalizedDescriptionKey,nil]]]; 1250 [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIInternalErrorWhileApplyingCredentialsType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Failed to apply credentials to request",NSLocalizedDescriptionKey,nil]]];
1251 } 1251 }
1252 1252
1253 - // Are a user name & password needed? 1253 + // Are a user name & password needed?
1254 } else if (CFHTTPAuthenticationRequiresUserNameAndPassword(requestAuthentication)) { 1254 } else if (CFHTTPAuthenticationRequiresUserNameAndPassword(requestAuthentication)) {
1255 1255
1256 NSMutableDictionary *newCredentials = [self findCredentials]; 1256 NSMutableDictionary *newCredentials = [self findCredentials];
@@ -1341,7 +1341,7 @@ static NSError *ASITooMuchRedirectionError; @@ -1341,7 +1341,7 @@ static NSError *ASITooMuchRedirectionError;
1341 if (bytesRead < 0) { 1341 if (bytesRead < 0) {
1342 [self handleStreamError]; 1342 [self handleStreamError];
1343 1343
1344 - // If zero bytes were read, wait for the EOF to come. 1344 + // If zero bytes were read, wait for the EOF to come.
1345 } else if (bytesRead) { 1345 } else if (bytesRead) {
1346 1346
1347 [self setTotalBytesRead:[self totalBytesRead]+bytesRead]; 1347 [self setTotalBytesRead:[self totalBytesRead]+bytesRead];
@@ -1361,7 +1361,7 @@ static NSError *ASITooMuchRedirectionError; @@ -1361,7 +1361,7 @@ static NSError *ASITooMuchRedirectionError;
1361 } 1361 }
1362 [fileDownloadOutputStream write:buffer maxLength:bytesRead]; 1362 [fileDownloadOutputStream write:buffer maxLength:bytesRead];
1363 1363
1364 - //Otherwise, let's add the data to our in-memory store 1364 + //Otherwise, let's add the data to our in-memory store
1365 } else { 1365 } else {
1366 [rawResponseData appendBytes:buffer length:bytesRead]; 1366 [rawResponseData appendBytes:buffer length:bytesRead];
1367 } 1367 }
@@ -1571,7 +1571,6 @@ static NSError *ASITooMuchRedirectionError; @@ -1571,7 +1571,6 @@ static NSError *ASITooMuchRedirectionError;
1571 [ASIHTTPRequest setSessionCookies:nil]; 1571 [ASIHTTPRequest setSessionCookies:nil];
1572 } 1572 }
1573 1573
1574 -  
1575 #pragma mark gzip decompression 1574 #pragma mark gzip decompression
1576 1575
1577 // 1576 //
@@ -1656,7 +1655,7 @@ static NSError *ASITooMuchRedirectionError; @@ -1656,7 +1655,7 @@ static NSError *ASITooMuchRedirectionError;
1656 // http://www.zlib.net/zpipe.c 1655 // http://www.zlib.net/zpipe.c
1657 // 1656 //
1658 #define CHUNK 16384 1657 #define CHUNK 16384
1659 -#define SET_BINARY_MODE(file) 1658 +
1660 + (int)uncompressZippedDataFromSource:(FILE *)source toDestination:(FILE *)dest 1659 + (int)uncompressZippedDataFromSource:(FILE *)source toDestination:(FILE *)dest
1661 { 1660 {
1662 int ret; 1661 int ret;
@@ -1906,4 +1905,5 @@ static NSError *ASITooMuchRedirectionError; @@ -1906,4 +1905,5 @@ static NSError *ASITooMuchRedirectionError;
1906 @synthesize needsRedirect; 1905 @synthesize needsRedirect;
1907 @synthesize redirectCount; 1906 @synthesize redirectCount;
1908 @synthesize shouldCompressRequestBody; 1907 @synthesize shouldCompressRequestBody;
  1908 +@synthesize authenticationLock;
1909 @end 1909 @end
@@ -731,5 +731,4 @@ @@ -731,5 +731,4 @@
731 731
732 } 732 }
733 733
734 -  
735 @end 734 @end
@@ -121,7 +121,7 @@ static NSString *bucket = @""; @@ -121,7 +121,7 @@ static NSString *bucket = @"";
121 121
122 NSString *path = @"/test"; 122 NSString *path = @"/test";
123 123
124 - // Create the fle 124 + // Create the file
125 NSString *text = @"This is my content"; 125 NSString *text = @"This is my content";
126 NSString *filePath = [[[[NSBundle mainBundle] bundlePath] stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"testfile.txt"]; 126 NSString *filePath = [[[[NSBundle mainBundle] bundlePath] stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"testfile.txt"];
127 [[text dataUsingEncoding:NSUTF8StringEncoding] writeToFile:filePath atomically:NO]; 127 [[text dataUsingEncoding:NSUTF8StringEncoding] writeToFile:filePath atomically:NO];
@@ -205,6 +205,47 @@ static NSString *bucket = @""; @@ -205,6 +205,47 @@ static NSString *bucket = @"";
205 GHAssertTrue(success, @"Got the wrong error message"); 205 GHAssertTrue(success, @"Got the wrong error message");
206 } 206 }
207 207
  208 +// Will upload a file to S3, gzipping it before uploading
  209 +// The file will be stored deflate, and automatically inflated when downloaded
  210 +// This means the file will take up less storage space, and will upload and download faster
  211 +// The file should still be accessible by any HTTP client that supports gzipped responses (eg browsers, NSURLConnection, etc)
  212 +- (void)testGZippedContent
  213 +{
  214 + // Create the file
  215 + NSString *text = @"This is my content This is my content This is my content This is my content This is my content This is my content";
  216 + NSString *filePath = [[[[NSBundle mainBundle] bundlePath] stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"testfile.txt"];
  217 + [[text dataUsingEncoding:NSUTF8StringEncoding] writeToFile:filePath atomically:NO];
  218 +
  219 + NSString *path = @"/gzipped-data";
  220 + ASIS3Request *request = [ASIS3Request PUTRequestForFile:filePath withBucket:bucket path:path];
  221 + [request setSecretAccessKey:secretAccessKey];
  222 + [request setAccessKey:accessKey];
  223 + [request setShouldCompressRequestBody:YES];
  224 + [request setAccessPolicy:ASIS3AccessPolicyPublicRead]; // We'll make it public
  225 + [request start];
  226 + BOOL success = [[request responseString] isEqualToString:@""];
  227 + GHAssertTrue(success,@"Failed to PUT the gzipped file");
  228 +
  229 + // GET the file
  230 + request = [ASIS3Request requestWithBucket:bucket path:path];
  231 + [request setSecretAccessKey:secretAccessKey];
  232 + [request setAccessKey:accessKey];
  233 + [request start];
  234 + success = [[request responseString] isEqualToString:text];
  235 + GHAssertTrue(success,@"Failed to GET the correct data from S3");
  236 +
  237 + success = [[[request responseHeaders] valueForKey:@"Content-Encoding"] isEqualToString:@"gzip"];
  238 + GHAssertTrue(success,@"Failed to GET the correct data from S3");
  239 +
  240 + // Now grab the data using something other than ASIHTTPRequest to ensure other HTTP clients can parse the gzipped content
  241 + NSData *data = [NSURLConnection sendSynchronousRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://%@.s3.amazonaws.com/gzipped-data",bucket]]] returningResponse:NULL error:NULL];
  242 + NSString *string = [[[NSString alloc] initWithBytes:[data bytes] length:[data length] encoding:NSUTF8StringEncoding] autorelease];
  243 + success = [string isEqualToString:text];
  244 + GHAssertTrue(success,@"Failed to GET the correct data from S3");
  245 +
  246 +}
  247 +
  248 +
208 - (void)testListRequest 249 - (void)testListRequest
209 { 250 {
210 251