Browse Source

Initial support for Gzip compression of HTTP Post Body

Mattt Thompson 14 years ago
parent
commit
c004ceb0f1

+ 32 - 0
AFNetworking/NSData+AFNetworking.h

@@ -0,0 +1,32 @@
+// NSData+AFNetworking.h
+//
+// Copyright (c) 2011 Gowalla (http://gowalla.com/)
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#import <Foundation/Foundation.h>
+
+extern NSString * const kAFZlibErrorDomain;
+
+@interface NSData (AFNetworking)
+
+- (NSData *)dataByGZipCompressingWithError:(NSError **)error;
+- (NSData *)dataByGZipDecompressingDataWithError:(NSError **)error;
+
+@end

+ 99 - 0
AFNetworking/NSData+AFNetworking.m

@@ -0,0 +1,99 @@
+// NSData+AFNetworking.m
+//
+// Copyright (c) 2011 Gowalla (http://gowalla.com/)
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#import "NSData+AFNetworking.h"
+#import <zlib.h>
+
+NSString * const kAFZlibErrorDomain = @"com.alamofire.zlib.error";
+
+static inline NSUInteger NSDataEstimatedCompressedLength(NSData *data) {
+    return [data length] / 2;
+}
+
+typedef enum {
+    GzipDeflate = -1,
+    GzipInflate = 1,
+} GzipOperation;
+
+@interface NSData (_AFNetworking)
++ (NSData *)dataByTransformingData:(NSData *)data 
+                usingGZipOperation:(GzipOperation)operation 
+                             error:(NSError **)error;
+@end
+
+@implementation NSData (_AFNetworking)
+
++ (NSData *)dataByTransformingData:(NSData *)data 
+                usingGZipOperation:(GzipOperation)operation 
+                             error:(NSError **)error
+{
+    z_stream zStream;
+	
+	NSUInteger estimatedLength = NSDataEstimatedCompressedLength(data);
+	NSMutableData *mutableData = [NSMutableData dataWithLength:estimatedLength];
+    
+	int status;
+	zStream.next_in = (Bytef *)[data bytes];
+	zStream.avail_in = (unsigned int)[data length];
+	zStream.avail_out = 0;
+    
+	NSInteger bytesProcessedAlready = zStream.total_out;
+	while (zStream.avail_out == 0) {
+		if (zStream.total_out - bytesProcessedAlready >= [mutableData length]) {
+			[mutableData increaseLengthBy:estimatedLength / 2];
+		}
+		
+		zStream.next_out = [mutableData mutableBytes] + zStream.total_out-bytesProcessedAlready;
+		zStream.avail_out = (unsigned int)([mutableData length] - (zStream.total_out-bytesProcessedAlready));
+		status = deflate(&zStream, Z_FINISH);
+		
+		if (status == Z_STREAM_END) {
+			break;
+		} else if (status != Z_OK) {
+            if (error) {
+                *error = [NSError errorWithDomain:kAFZlibErrorDomain code:status userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"Compression of data failed with code %hi", status] forKey:NSLocalizedDescriptionKey]];
+            }
+            
+			return nil;
+		}
+	}
+    
+	[mutableData setLength:zStream.total_out - bytesProcessedAlready];
+    
+    return mutableData;
+}
+
+@end
+
+#pragma mark -
+
+@implementation NSData (AFNetworking)
+
+- (NSData *)dataByGZipCompressingWithError:(NSError **)error {
+    return [NSData dataByTransformingData:self usingGZipOperation:GzipDeflate error:error];
+}
+
+- (NSData *)dataByGZipDecompressingDataWithError:(NSError **)error {
+    return [NSData dataByTransformingData:self usingGZipOperation:GzipInflate error:error];
+}
+
+@end

+ 2 - 1
AFNetworking/NSMutableURLRequest+AFNetworking.h

@@ -27,6 +27,7 @@
 - (void)setHTTPBodyWithData:(NSData *)data 
                    mimeType:(NSString *)mimeType 
           forParameterNamed:(NSString *)parameterName 
-                 parameters:(NSDictionary *)parameters;
+                 parameters:(NSDictionary *)parameters
+             useCompression:(BOOL)useCompression;
 
 @end

+ 16 - 2
AFNetworking/NSMutableURLRequest+AFNetworking.m

@@ -21,13 +21,15 @@
 // THE SOFTWARE.
 
 #import "NSMutableURLRequest+AFNetworking.h"
+#import "NSData+AFNetworking.h"
 
 @implementation NSMutableURLRequest (AFNetworking)
 
 - (void)setHTTPBodyWithData:(NSData *)data 
                    mimeType:(NSString *)mimeType 
           forParameterNamed:(NSString *)parameterName 
-                 parameters:(NSDictionary *)parameters 
+                 parameters:(NSDictionary *)parameters
+             useCompression:(BOOL)useCompression
 {
 	if ([[self HTTPMethod] isEqualToString:@"GET"]) {
 		[self setHTTPMethod:@"POST"];
@@ -56,7 +58,19 @@
 	[mutableData appendData:data];
 	[mutableData appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
 	
-	[self setHTTPBody:mutableData];
+    if (useCompression) {
+        NSError *error = nil;
+        NSData *compressedData = [mutableData dataByGZipCompressingWithError:&error];
+        
+        if (!error && compressedData) {
+            [self setHTTPBody:compressedData];
+            
+            // Content-Encoding HTTP Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.11
+            [self setValue:@"gzip" forHTTPHeaderField:@"Content-Encoding"];
+        }
+    } else {
+        [self setHTTPBody:mutableData];
+    }
 }
 
 @end

+ 10 - 0
Example/AFNetworking Example.xcodeproj/project.pbxproj

@@ -9,6 +9,8 @@
 /* Begin PBXBuildFile section */
 		F85CE2D413EC478F00BFAE01 /* NSString+AFNetworking.m in Sources */ = {isa = PBXBuildFile; fileRef = F85CE2D313EC478F00BFAE01 /* NSString+AFNetworking.m */; };
 		F85CE2DC13EC4A4200BFAE01 /* NSMutableURLRequest+AFNetworking.m in Sources */ = {isa = PBXBuildFile; fileRef = F85CE2DB13EC4A4200BFAE01 /* NSMutableURLRequest+AFNetworking.m */; };
+		F85CE55513EC759200BFAE01 /* NSData+AFNetworking.m in Sources */ = {isa = PBXBuildFile; fileRef = F85CE55413EC759200BFAE01 /* NSData+AFNetworking.m */; };
+		F85CE55B13EC771100BFAE01 /* libz.1.2.5.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = F85CE55A13EC771100BFAE01 /* libz.1.2.5.dylib */; settings = {ATTRIBUTES = (Weak, ); }; };
 		F874B5D913E0AA6500B28E3E /* AFHTTPRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = F874B5C913E0AA6500B28E3E /* AFHTTPRequestOperation.m */; };
 		F874B5DA13E0AA6500B28E3E /* AFImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = F874B5CA13E0AA6500B28E3E /* AFImageCache.m */; };
 		F874B5DB13E0AA6500B28E3E /* AFImageRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = F874B5CB13E0AA6500B28E3E /* AFImageRequestOperation.m */; };
@@ -38,6 +40,9 @@
 		F85CE2D313EC478F00BFAE01 /* NSString+AFNetworking.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSString+AFNetworking.m"; path = "../AFNetworking/NSString+AFNetworking.m"; sourceTree = "<group>"; };
 		F85CE2DA13EC4A4200BFAE01 /* NSMutableURLRequest+AFNetworking.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSMutableURLRequest+AFNetworking.h"; path = "../AFNetworking/NSMutableURLRequest+AFNetworking.h"; sourceTree = "<group>"; };
 		F85CE2DB13EC4A4200BFAE01 /* NSMutableURLRequest+AFNetworking.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSMutableURLRequest+AFNetworking.m"; path = "../AFNetworking/NSMutableURLRequest+AFNetworking.m"; sourceTree = "<group>"; };
+		F85CE55313EC759100BFAE01 /* NSData+AFNetworking.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSData+AFNetworking.h"; path = "../AFNetworking/NSData+AFNetworking.h"; sourceTree = "<group>"; };
+		F85CE55413EC759200BFAE01 /* NSData+AFNetworking.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSData+AFNetworking.m"; path = "../AFNetworking/NSData+AFNetworking.m"; sourceTree = "<group>"; };
+		F85CE55A13EC771100BFAE01 /* libz.1.2.5.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.1.2.5.dylib; path = usr/lib/libz.1.2.5.dylib; sourceTree = SDKROOT; };
 		F874B5C913E0AA6500B28E3E /* AFHTTPRequestOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AFHTTPRequestOperation.m; path = ../AFNetworking/AFHTTPRequestOperation.m; sourceTree = "<group>"; };
 		F874B5CA13E0AA6500B28E3E /* AFImageCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AFImageCache.m; path = ../AFNetworking/AFImageCache.m; sourceTree = "<group>"; };
 		F874B5CB13E0AA6500B28E3E /* AFImageRequestOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AFImageRequestOperation.m; path = ../AFNetworking/AFImageRequestOperation.m; sourceTree = "<group>"; };
@@ -88,6 +93,7 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				F85CE55B13EC771100BFAE01 /* libz.1.2.5.dylib in Frameworks */,
 				F8E469651395739D00DB05C8 /* UIKit.framework in Frameworks */,
 				F8E469671395739D00DB05C8 /* Foundation.framework in Frameworks */,
 				F8E469691395739D00DB05C8 /* CoreGraphics.framework in Frameworks */,
@@ -109,6 +115,8 @@
 				F874B5CF13E0AA6500B28E3E /* UIImage+AFNetworking.m */,
 				F874B5D813E0AA6500B28E3E /* UIImageView+AFNetworking.h */,
 				F874B5D013E0AA6500B28E3E /* UIImageView+AFNetworking.m */,
+				F85CE55313EC759100BFAE01 /* NSData+AFNetworking.h */,
+				F85CE55413EC759200BFAE01 /* NSData+AFNetworking.m */,
 			);
 			name = Categories;
 			sourceTree = "<group>";
@@ -186,6 +194,7 @@
 		F8E469631395739D00DB05C8 /* Frameworks */ = {
 			isa = PBXGroup;
 			children = (
+				F85CE55A13EC771100BFAE01 /* libz.1.2.5.dylib */,
 				F8E469E413957E0400DB05C8 /* SystemConfiguration.framework */,
 				F8E469E213957DF700DB05C8 /* SystemConfiguration.framework */,
 				F8E469E013957DF100DB05C8 /* Security.framework */,
@@ -351,6 +360,7 @@
 				F874B5E013E0AA6500B28E3E /* UIImageView+AFNetworking.m in Sources */,
 				F85CE2D413EC478F00BFAE01 /* NSString+AFNetworking.m in Sources */,
 				F85CE2DC13EC4A4200BFAE01 /* NSMutableURLRequest+AFNetworking.m in Sources */,
+				F85CE55513EC759200BFAE01 /* NSData+AFNetworking.m in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};

File diff suppressed because it is too large
+ 174 - 141
Example/AFNetworking Example.xcodeproj/project.xcworkspace/xcuserdata/mattt.xcuserdatad/UserInterfaceState.xcuserstate


Some files were not shown because too many files changed in this diff