<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>Vendor/ASIHTTPRequest/ASINSStringAdditions.h</filename>
    </added>
    <added>
      <filename>Vendor/ASIHTTPRequest/ASINSStringAdditions.m</filename>
    </added>
    <added>
      <filename>Vendor/ASIHTTPRequest/ASIS3BucketObject.h</filename>
    </added>
    <added>
      <filename>Vendor/ASIHTTPRequest/ASIS3BucketObject.m</filename>
    </added>
    <added>
      <filename>Vendor/ASIHTTPRequest/ASIS3ListRequest.h</filename>
    </added>
    <added>
      <filename>Vendor/ASIHTTPRequest/ASIS3ListRequest.m</filename>
    </added>
    <added>
      <filename>Vendor/ASIHTTPRequest/ASIS3Request.h</filename>
    </added>
    <added>
      <filename>Vendor/ASIHTTPRequest/ASIS3Request.m</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -89,16 +89,20 @@
 		01A9664E0F315F4000A60A5C /* Add All.png in Resources */ = {isa = PBXBuildFile; fileRef = 01A9664D0F315F4000A60A5C /* Add All.png */; };
 		01ABF7D70F147AB400EE7142 /* ScribdAPI.plist in Resources */ = {isa = PBXBuildFile; fileRef = 01ABF7D60F147AB400EE7142 /* ScribdAPI.plist */; };
 		01ABF7FA0F147DCC00EE7142 /* SUSessionHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 01ABF7F90F147DCC00EE7142 /* SUSessionHelper.m */; };
-		01AF5FFE0F1D27D300D51D07 /* ASIFormDataRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 01AF5FF20F1D27D300D51D07 /* ASIFormDataRequest.m */; };
-		01AF5FFF0F1D27D300D51D07 /* ASIHTTPRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 01AF5FF40F1D27D300D51D07 /* ASIHTTPRequest.m */; };
-		01AF60000F1D27D300D51D07 /* ASINetworkQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 01AF5FF60F1D27D300D51D07 /* ASINetworkQueue.m */; };
-		01AF60010F1D27D300D51D07 /* NSHTTPCookieAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 01AF5FF80F1D27D300D51D07 /* NSHTTPCookieAdditions.m */; };
 		01AF60020F1D27D300D51D07 /* DBPrefsWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 01AF5FFB0F1D27D300D51D07 /* DBPrefsWindowController.m */; };
 		01AF60050F1D284900D51D07 /* SUPreferencesWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 01AF60040F1D284900D51D07 /* SUPreferencesWindowController.m */; };
 		01AF60440F1D321100D51D07 /* Preferences.xib in Resources */ = {isa = PBXBuildFile; fileRef = 01AF60430F1D321100D51D07 /* Preferences.xib */; };
 		01BF112B0F2AD45A007CED18 /* Go Clicked.png in Resources */ = {isa = PBXBuildFile; fileRef = 01BF11280F2AD45A007CED18 /* Go Clicked.png */; };
 		01BF112C0F2AD45A007CED18 /* Caution Clicked.png in Resources */ = {isa = PBXBuildFile; fileRef = 01BF11290F2AD45A007CED18 /* Caution Clicked.png */; };
 		01BF112D0F2AD45A007CED18 /* Error Clicked.png in Resources */ = {isa = PBXBuildFile; fileRef = 01BF112A0F2AD45A007CED18 /* Error Clicked.png */; };
+		01C1B9E51022BAD900C4BDAE /* ASIFormDataRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 01C1B9D81022BAD900C4BDAE /* ASIFormDataRequest.m */; };
+		01C1B9E61022BAD900C4BDAE /* ASIHTTPRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 01C1B9DA1022BAD900C4BDAE /* ASIHTTPRequest.m */; };
+		01C1B9E71022BAD900C4BDAE /* ASINetworkQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 01C1B9DC1022BAD900C4BDAE /* ASINetworkQueue.m */; };
+		01C1B9E81022BAD900C4BDAE /* ASINSStringAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 01C1B9DE1022BAD900C4BDAE /* ASINSStringAdditions.m */; };
+		01C1B9E91022BAD900C4BDAE /* ASIS3BucketObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 01C1B9E01022BAD900C4BDAE /* ASIS3BucketObject.m */; };
+		01C1B9EA1022BAD900C4BDAE /* ASIS3ListRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 01C1B9E21022BAD900C4BDAE /* ASIS3ListRequest.m */; };
+		01C1B9EB1022BAD900C4BDAE /* ASIS3Request.m in Sources */ = {isa = PBXBuildFile; fileRef = 01C1B9E41022BAD900C4BDAE /* ASIS3Request.m */; };
+		01C1B9FA1022BC1000C4BDAE /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 01C1B9F91022BC1000C4BDAE /* SystemConfiguration.framework */; };
 		01E062A40F43DE130026A075 /* NSApplication_SUAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 01E062A30F43DE130026A075 /* NSApplication_SUAdditions.m */; };
 		01E821340F293BB100473993 /* Caution.png in Resources */ = {isa = PBXBuildFile; fileRef = 01E821310F293BB100473993 /* Caution.png */; };
 		01E821350F293BB100473993 /* Error.png in Resources */ = {isa = PBXBuildFile; fileRef = 01E821320F293BB100473993 /* Error.png */; };
@@ -256,14 +260,6 @@
 		01A9664D0F315F4000A60A5C /* Add All.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = &quot;Add All.png&quot;; sourceTree = &quot;&lt;group&gt;&quot;; };
 		01ABF7F80F147DCC00EE7142 /* SUSessionHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SUSessionHelper.h; sourceTree = &quot;&lt;group&gt;&quot;; };
 		01ABF7F90F147DCC00EE7142 /* SUSessionHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SUSessionHelper.m; sourceTree = &quot;&lt;group&gt;&quot;; };
-		01AF5FF10F1D27D300D51D07 /* ASIFormDataRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIFormDataRequest.h; sourceTree = &quot;&lt;group&gt;&quot;; };
-		01AF5FF20F1D27D300D51D07 /* ASIFormDataRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASIFormDataRequest.m; sourceTree = &quot;&lt;group&gt;&quot;; };
-		01AF5FF30F1D27D300D51D07 /* ASIHTTPRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIHTTPRequest.h; sourceTree = &quot;&lt;group&gt;&quot;; };
-		01AF5FF40F1D27D300D51D07 /* ASIHTTPRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASIHTTPRequest.m; sourceTree = &quot;&lt;group&gt;&quot;; };
-		01AF5FF50F1D27D300D51D07 /* ASINetworkQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASINetworkQueue.h; sourceTree = &quot;&lt;group&gt;&quot;; };
-		01AF5FF60F1D27D300D51D07 /* ASINetworkQueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASINetworkQueue.m; sourceTree = &quot;&lt;group&gt;&quot;; };
-		01AF5FF70F1D27D300D51D07 /* NSHTTPCookieAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSHTTPCookieAdditions.h; sourceTree = &quot;&lt;group&gt;&quot;; };
-		01AF5FF80F1D27D300D51D07 /* NSHTTPCookieAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSHTTPCookieAdditions.m; sourceTree = &quot;&lt;group&gt;&quot;; };
 		01AF5FFA0F1D27D300D51D07 /* DBPrefsWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DBPrefsWindowController.h; sourceTree = &quot;&lt;group&gt;&quot;; };
 		01AF5FFB0F1D27D300D51D07 /* DBPrefsWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DBPrefsWindowController.m; sourceTree = &quot;&lt;group&gt;&quot;; };
 		01AF5FFD0F1D27D300D51D07 /* QuickLook.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QuickLook.h; sourceTree = &quot;&lt;group&gt;&quot;; };
@@ -273,6 +269,21 @@
 		01BF11280F2AD45A007CED18 /* Go Clicked.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = &quot;Go Clicked.png&quot;; sourceTree = &quot;&lt;group&gt;&quot;; };
 		01BF11290F2AD45A007CED18 /* Caution Clicked.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = &quot;Caution Clicked.png&quot;; sourceTree = &quot;&lt;group&gt;&quot;; };
 		01BF112A0F2AD45A007CED18 /* Error Clicked.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = &quot;Error Clicked.png&quot;; sourceTree = &quot;&lt;group&gt;&quot;; };
+		01C1B9D71022BAD900C4BDAE /* ASIFormDataRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIFormDataRequest.h; sourceTree = &quot;&lt;group&gt;&quot;; };
+		01C1B9D81022BAD900C4BDAE /* ASIFormDataRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASIFormDataRequest.m; sourceTree = &quot;&lt;group&gt;&quot;; };
+		01C1B9D91022BAD900C4BDAE /* ASIHTTPRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIHTTPRequest.h; sourceTree = &quot;&lt;group&gt;&quot;; };
+		01C1B9DA1022BAD900C4BDAE /* ASIHTTPRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASIHTTPRequest.m; sourceTree = &quot;&lt;group&gt;&quot;; };
+		01C1B9DB1022BAD900C4BDAE /* ASINetworkQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASINetworkQueue.h; sourceTree = &quot;&lt;group&gt;&quot;; };
+		01C1B9DC1022BAD900C4BDAE /* ASINetworkQueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASINetworkQueue.m; sourceTree = &quot;&lt;group&gt;&quot;; };
+		01C1B9DD1022BAD900C4BDAE /* ASINSStringAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASINSStringAdditions.h; sourceTree = &quot;&lt;group&gt;&quot;; };
+		01C1B9DE1022BAD900C4BDAE /* ASINSStringAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASINSStringAdditions.m; sourceTree = &quot;&lt;group&gt;&quot;; };
+		01C1B9DF1022BAD900C4BDAE /* ASIS3BucketObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIS3BucketObject.h; sourceTree = &quot;&lt;group&gt;&quot;; };
+		01C1B9E01022BAD900C4BDAE /* ASIS3BucketObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASIS3BucketObject.m; sourceTree = &quot;&lt;group&gt;&quot;; };
+		01C1B9E11022BAD900C4BDAE /* ASIS3ListRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIS3ListRequest.h; sourceTree = &quot;&lt;group&gt;&quot;; };
+		01C1B9E21022BAD900C4BDAE /* ASIS3ListRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASIS3ListRequest.m; sourceTree = &quot;&lt;group&gt;&quot;; };
+		01C1B9E31022BAD900C4BDAE /* ASIS3Request.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIS3Request.h; sourceTree = &quot;&lt;group&gt;&quot;; };
+		01C1B9E41022BAD900C4BDAE /* ASIS3Request.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASIS3Request.m; sourceTree = &quot;&lt;group&gt;&quot;; };
+		01C1B9F91022BC1000C4BDAE /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = /System/Library/Frameworks/SystemConfiguration.framework; sourceTree = &quot;&lt;absolute&gt;&quot;; };
 		01E062A20F43DE130026A075 /* NSApplication_SUAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSApplication_SUAdditions.h; sourceTree = &quot;&lt;group&gt;&quot;; };
 		01E062A30F43DE130026A075 /* NSApplication_SUAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSApplication_SUAdditions.m; sourceTree = &quot;&lt;group&gt;&quot;; };
 		01E821310F293BB100473993 /* Caution.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Caution.png; sourceTree = &quot;&lt;group&gt;&quot;; };
@@ -299,6 +310,7 @@
 				012385FE0F2AB3D7007D2B54 /* Security.framework in Frameworks */,
 				01377DFB0F60F07C00C9121E /* QuartzCore.framework in Frameworks */,
 				017C85890F6F98E10013D7D0 /* libz.dylib in Frameworks */,
+				01C1B9FA1022BC1000C4BDAE /* SystemConfiguration.framework in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -551,7 +563,7 @@
 		01AF5FEF0F1D27D300D51D07 /* Vendor */ = {
 			isa = PBXGroup;
 			children = (
-				01AF5FF00F1D27D300D51D07 /* ASIHTTPRequest */,
+				01C1B9D61022BAD900C4BDAE /* ASIHTTPRequest */,
 				01AF5FF90F1D27D300D51D07 /* DBPrefsWindow */,
 				012384670F2AAE1F007D2B54 /* EMKeychain */,
 				01AF5FFC0F1D27D300D51D07 /* QuickLook */,
@@ -560,21 +572,6 @@
 			path = Vendor;
 			sourceTree = &quot;&lt;group&gt;&quot;;
 		};
-		01AF5FF00F1D27D300D51D07 /* ASIHTTPRequest */ = {
-			isa = PBXGroup;
-			children = (
-				01AF5FF10F1D27D300D51D07 /* ASIFormDataRequest.h */,
-				01AF5FF20F1D27D300D51D07 /* ASIFormDataRequest.m */,
-				01AF5FF30F1D27D300D51D07 /* ASIHTTPRequest.h */,
-				01AF5FF40F1D27D300D51D07 /* ASIHTTPRequest.m */,
-				01AF5FF50F1D27D300D51D07 /* ASINetworkQueue.h */,
-				01AF5FF60F1D27D300D51D07 /* ASINetworkQueue.m */,
-				01AF5FF70F1D27D300D51D07 /* NSHTTPCookieAdditions.h */,
-				01AF5FF80F1D27D300D51D07 /* NSHTTPCookieAdditions.m */,
-			);
-			path = ASIHTTPRequest;
-			sourceTree = &quot;&lt;group&gt;&quot;;
-		};
 		01AF5FF90F1D27D300D51D07 /* DBPrefsWindow */ = {
 			isa = PBXGroup;
 			children = (
@@ -592,9 +589,31 @@
 			path = QuickLook;
 			sourceTree = &quot;&lt;group&gt;&quot;;
 		};
+		01C1B9D61022BAD900C4BDAE /* ASIHTTPRequest */ = {
+			isa = PBXGroup;
+			children = (
+				01C1B9D71022BAD900C4BDAE /* ASIFormDataRequest.h */,
+				01C1B9D81022BAD900C4BDAE /* ASIFormDataRequest.m */,
+				01C1B9D91022BAD900C4BDAE /* ASIHTTPRequest.h */,
+				01C1B9DA1022BAD900C4BDAE /* ASIHTTPRequest.m */,
+				01C1B9DB1022BAD900C4BDAE /* ASINetworkQueue.h */,
+				01C1B9DC1022BAD900C4BDAE /* ASINetworkQueue.m */,
+				01C1B9DD1022BAD900C4BDAE /* ASINSStringAdditions.h */,
+				01C1B9DE1022BAD900C4BDAE /* ASINSStringAdditions.m */,
+				01C1B9DF1022BAD900C4BDAE /* ASIS3BucketObject.h */,
+				01C1B9E01022BAD900C4BDAE /* ASIS3BucketObject.m */,
+				01C1B9E11022BAD900C4BDAE /* ASIS3ListRequest.h */,
+				01C1B9E21022BAD900C4BDAE /* ASIS3ListRequest.m */,
+				01C1B9E31022BAD900C4BDAE /* ASIS3Request.h */,
+				01C1B9E41022BAD900C4BDAE /* ASIS3Request.m */,
+			);
+			path = ASIHTTPRequest;
+			sourceTree = &quot;&lt;group&gt;&quot;;
+		};
 		1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = {
 			isa = PBXGroup;
 			children = (
+				01C1B9F91022BC1000C4BDAE /* SystemConfiguration.framework */,
 				017C85880F6F98E10013D7D0 /* libz.dylib */,
 				01377DFA0F60F07C00C9121E /* QuartzCore.framework */,
 				1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */,
@@ -753,10 +772,6 @@
 				0128AF490F1478F300EC3C28 /* SUConstants.m in Sources */,
 				01ABF7FA0F147DCC00EE7142 /* SUSessionHelper.m in Sources */,
 				0132C0970F16C3A6000B17C5 /* SUAboutWindowController.m in Sources */,
-				01AF5FFE0F1D27D300D51D07 /* ASIFormDataRequest.m in Sources */,
-				01AF5FFF0F1D27D300D51D07 /* ASIHTTPRequest.m in Sources */,
-				01AF60000F1D27D300D51D07 /* ASINetworkQueue.m in Sources */,
-				01AF60010F1D27D300D51D07 /* NSHTTPCookieAdditions.m in Sources */,
 				01AF60020F1D27D300D51D07 /* DBPrefsWindowController.m in Sources */,
 				01AF60050F1D284900D51D07 /* SUPreferencesWindowController.m in Sources */,
 				012E5E740F20837C0037ECDA /* SUInformationDrawerDelegate.m in Sources */,
@@ -792,6 +807,13 @@
 				0175F3230F72438B0046C032 /* Scribd_Uploader_DataModel 210-220.xcmappingmodel in Sources */,
 				0175F32C0F7244CF0046C032 /* SUConversionStatusTracker.m in Sources */,
 				0103D6741022B88B00D8968C /* TMMoveToApplicationsFolder.m in Sources */,
+				01C1B9E51022BAD900C4BDAE /* ASIFormDataRequest.m in Sources */,
+				01C1B9E61022BAD900C4BDAE /* ASIHTTPRequest.m in Sources */,
+				01C1B9E71022BAD900C4BDAE /* ASINetworkQueue.m in Sources */,
+				01C1B9E81022BAD900C4BDAE /* ASINSStringAdditions.m in Sources */,
+				01C1B9E91022BAD900C4BDAE /* ASIS3BucketObject.m in Sources */,
+				01C1B9EA1022BAD900C4BDAE /* ASIS3ListRequest.m in Sources */,
+				01C1B9EB1022BAD900C4BDAE /* ASIS3Request.m in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};</diff>
      <filename>Scribd Uploader.xcodeproj/project.pbxproj</filename>
    </modified>
    <modified>
      <diff>@@ -5,7 +5,10 @@
 #import &lt;QuartzCore/QuartzCore.h&gt;
 #endif
 
+#import &quot;ASIHTTPRequest.h&quot;
 #import &quot;ASIFormDataRequest.h&quot;
+#import &quot;ASINetworkQueue.h&quot;
+
 #import &quot;QuickLook.h&quot;
 #import &quot;DBPrefsWindowController.h&quot;
 #import &lt;Sparkle/SUUpdater.h&gt;</diff>
      <filename>Scribd_Uploader_Prefix.pch</filename>
    </modified>
    <modified>
      <diff>@@ -3,9 +3,10 @@
 //  asi-http-request
 //
 //  Created by Ben Copsey on 07/11/2008.
-//  Copyright 2008 All-Seeing Interactive. All rights reserved.
+//  Copyright 2008-2009 All-Seeing Interactive. All rights reserved.
 //
 
+#import &lt;Foundation/Foundation.h&gt;
 #import &quot;ASIHTTPRequest.h&quot;
 
 @interface ASIFormDataRequest : ASIHTTPRequest {</diff>
      <filename>Vendor/ASIHTTPRequest/ASIFormDataRequest.h</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,7 @@
 //  asi-http-request
 //
 //  Created by Ben Copsey on 07/11/2008.
-//  Copyright 2008 All-Seeing Interactive. All rights reserved.
+//  Copyright 2008-2009 All-Seeing Interactive. All rights reserved.
 //
 
 #import &quot;ASIFormDataRequest.h&quot;
@@ -21,6 +21,11 @@
 	return self;
 }
 
++ (id)requestWithURL:(NSURL *)newURL
+{
+	return [[[self alloc] initWithURL:newURL] autorelease];
+}
+
 - (void)dealloc
 {
 	[postData release];
@@ -44,10 +49,7 @@
 	if (!fileData) {
 		fileData = [[NSMutableDictionary alloc] init];
 	}
-	NSMutableDictionary *file = [[[NSMutableDictionary alloc] init] autorelease];
-	[file setObject:[NSData dataWithContentsOfFile:filePath options:NSUncachedRead error:NULL] forKey:@&quot;data&quot;];
-	[file setObject:[filePath lastPathComponent] forKey:@&quot;filename&quot;];
-	[fileData setValue:file forKey:key];
+	[fileData setValue:filePath forKey:key];
 	[self setRequestMethod:@&quot;POST&quot;];
 }
 
@@ -56,10 +58,7 @@
 	if (!fileData) {
 		fileData = [[NSMutableDictionary alloc] init];
 	}
-	NSMutableDictionary *file = [[[NSMutableDictionary alloc] init] autorelease];
-	[file setObject:data forKey:@&quot;data&quot;];
-	[file setObject:@&quot;file&quot; forKey:@&quot;filename&quot;];
-	[fileData setValue:file forKey:key];
+	[fileData setObject:data forKey:key];
 	[self setRequestMethod:@&quot;POST&quot;];	
 }
 
@@ -69,15 +68,17 @@
 		[super buildPostBody];
 		return;
 	}	
-
-	NSMutableData *body = [[[NSMutableData alloc] init] autorelease];
+	if ([fileData count] &gt; 0) {
+		[self setShouldStreamPostDataFromDisk:YES];
+	}
+	 
 	
 	// Set your own boundary string only if really obsessive. We don't bother to check if post data contains the boundary, since it's pretty unlikely that it does.
 	NSString *stringBoundary = @&quot;0xKhTmLbOuNdArY&quot;;
 	
 	[self addRequestHeader:@&quot;Content-Type&quot; value:[NSString stringWithFormat:@&quot;multipart/form-data; boundary=%@&quot;,stringBoundary]];
 	
-	[body appendData:[[NSString stringWithFormat:@&quot;--%@\r\n&quot;,stringBoundary] dataUsingEncoding:NSUTF8StringEncoding]];
+	[self appendPostData:[[NSString stringWithFormat:@&quot;--%@\r\n&quot;,stringBoundary] dataUsingEncoding:NSUTF8StringEncoding]];
 	
 	// Adds post data
 	NSData *endItemBoundary = [[NSString stringWithFormat:@&quot;\r\n--%@\r\n&quot;,stringBoundary] dataUsingEncoding:NSUTF8StringEncoding];
@@ -85,11 +86,11 @@
 	NSString *key;
 	int i=0;
 	while (key = [e nextObject]) {
-		[body appendData:[[NSString stringWithFormat:@&quot;Content-Disposition: form-data; name=\&quot;%@\&quot;\r\n\r\n&quot;,key] dataUsingEncoding:NSUTF8StringEncoding]];
-		[body appendData:[[postData objectForKey:key] dataUsingEncoding:NSUTF8StringEncoding]];
+		[self appendPostData:[[NSString stringWithFormat:@&quot;Content-Disposition: form-data; name=\&quot;%@\&quot;\r\n\r\n&quot;,key] dataUsingEncoding:NSUTF8StringEncoding]];
+		[self appendPostData:[[postData objectForKey:key] dataUsingEncoding:NSUTF8StringEncoding]];
 		i++;
 		if (i != [postData count] || [fileData count] &gt; 0) { //Only add the boundary if this is not the last item in the post body
-			[body appendData:endItemBoundary];
+			[self appendPostData:endItemBoundary];
 		}
 	}
 	
@@ -98,22 +99,27 @@
 	e = [fileData keyEnumerator];
 	i=0;
 	while (key = [e nextObject]) {
-		NSDictionary *fileInfo = [fileData objectForKey:key];
-		[body appendData:[[NSString stringWithFormat:@&quot;Content-Disposition: form-data; name=\&quot;%@\&quot;; filename=\&quot;%@\&quot;\r\n&quot;,key,[fileInfo objectForKey:@&quot;filename&quot;]] dataUsingEncoding:NSUTF8StringEncoding]];
-		[body appendData:contentTypeHeader];
-		[body appendData: [fileInfo objectForKey:@&quot;data&quot;]];
+		NSString *fileName = @&quot;file&quot;;
+		id file =  [fileData objectForKey:key];
+		if ([file isKindOfClass:[NSString class]]) {
+			fileName = (NSString *)file;
+		}
+		[self appendPostData:[[NSString stringWithFormat:@&quot;Content-Disposition: form-data; name=\&quot;%@\&quot;; filename=\&quot;%@\&quot;\r\n&quot;,key,fileName] dataUsingEncoding:NSUTF8StringEncoding]];
+		[self appendPostData:contentTypeHeader];
+		if ([file isKindOfClass:[NSString class]]) {
+			[self appendPostDataFromFile:fileName];
+		} else {
+			[self appendPostData:file];
+		}
 		i++;
 		// Only add the boundary if this is not the last item in the post body
 		if (i != [fileData count]) { 
-			[body appendData:endItemBoundary];
+			[self appendPostData:endItemBoundary];
 		}
 	}
 	
-	[body appendData:[[NSString stringWithFormat:@&quot;\r\n--%@--\r\n&quot;,stringBoundary] dataUsingEncoding:NSUTF8StringEncoding]];
+	[self appendPostData:[[NSString stringWithFormat:@&quot;\r\n--%@--\r\n&quot;,stringBoundary] dataUsingEncoding:NSUTF8StringEncoding]];
 	
-	[self setPostBody:body];
-	
-
 	[super buildPostBody];
 }
 </diff>
      <filename>Vendor/ASIHTTPRequest/ASIFormDataRequest.m</filename>
    </modified>
    <modified>
      <diff>@@ -2,7 +2,7 @@
 //  ASIHTTPRequest.h
 //
 //  Created by Ben Copsey on 04/10/2007.
-//  Copyright 2007-2008 All-Seeing Interactive. All rights reserved.
+//  Copyright 2007-2009 All-Seeing Interactive. All rights reserved.
 //
 //  A guide to the main features is available at:
 //  http://allseeing-i.com/ASIHTTPRequest
@@ -10,13 +10,14 @@
 //  Portions are based on the ImageClient example from Apple:
 //  See: http://developer.apple.com/samplecode/ImageClient/listing37.html
 
-
+#import &lt;Foundation/Foundation.h&gt;
 // Dammit, importing frameworks when you are targetting two platforms is a PITA
 #if TARGET_OS_IPHONE
 	#import &lt;CFNetwork/CFNetwork.h&gt;
 #endif
 #import &lt;stdio.h&gt;
 
+
 typedef enum _ASINetworkErrorType {
     ASIConnectionFailureErrorType = 1,
     ASIRequestTimedOutErrorType = 2,
@@ -25,10 +26,13 @@ typedef enum _ASINetworkErrorType {
     ASIUnableToCreateRequestErrorType = 5,
     ASIInternalErrorWhileBuildingRequestType  = 6,
     ASIInternalErrorWhileApplyingCredentialsType  = 7,
-	ASIFileManagementError = 8
+	ASIFileManagementError = 8,
+	ASITooMuchRedirectionErrorType = 9
 	
 } ASINetworkErrorType;
 
+extern NSString* const NetworkRequestErrorDomain;
+
 @interface ASIHTTPRequest : NSOperation {
 	
 	// The url for this operation, should include GET params in the query string where appropriate
@@ -37,11 +41,37 @@ typedef enum _ASINetworkErrorType {
 	// The delegate, you need to manage setting and talking to your delegate in your subclasses
 	id delegate;
 	
-	// HTTP method to use (GET / POST / PUT / DELETE). Defaults to GET
+	// A queue delegate that should *ALSO* be notified of delegate message (used by ASINetworkQueue)
+	id queue;
+	
+	// HTTP method to use (GET / POST / PUT / DELETE / HEAD). Defaults to GET
 	NSString *requestMethod;
 	
-	// Request body
-	NSData *postBody;
+	// Request body - only used when the whole body is stored in memory (shouldStreamPostDataFromDisk is false)
+	NSMutableData *postBody;
+	
+	// gzipped request body used when shouldCompressRequestBody is YES
+	NSData *compressedPostBody;
+	
+	// When true, post body will be streamed from a file on disk, rather than loaded into memory at once (useful for large uploads)
+	// Automatically set to true in ASIFormDataRequests when using setFile:forKey:
+	BOOL shouldStreamPostDataFromDisk;
+	
+	// Path to file used to store post body (when shouldStreamPostDataFromDisk is true)
+	// You can set this yourself - useful if you want to PUT a file from local disk 
+	NSString *postBodyFilePath;
+	
+	// Path to a temporary file used to store a deflated post body (when shouldCompressPostBody is YES)
+	NSString *compressedPostBodyFilePath;
+	
+	// Set to true when ASIHTTPRequest automatically created a temporary file containing the request body (when true, the file at postBodyFilePath will be deleted at the end of the request)
+	BOOL didCreateTemporaryPostDataFile;
+	
+	// Used when writing to the post body when shouldStreamPostDataFromDisk is true (via appendPostData: or appendPostDataFromFile:)
+	NSOutputStream *postBodyWriteStream;
+	
+	// Used for reading from the post body when sending the request
+	NSInputStream *postBodyReadStream;
 	
 	// Dictionary for custom HTTP request headers
 	NSMutableDictionary *requestHeaders;
@@ -67,6 +97,10 @@ typedef enum _ASINetworkErrorType {
 	// If allowCompressedResponse is true, requests will inform the server they can accept compressed data, and will automatically decompress gzipped responses. Default is true.
 	BOOL allowCompressedResponse;
 	
+	// If shouldCompressRequestBody is true, the request body will be gzipped. Default is false.
+	// You will probably need to enable this feature on your webserver to make this work. Tested with apache only.
+	BOOL shouldCompressRequestBody;
+	
 	// When downloadDestinationPath is set, the result of this request will be downloaded to the file at this location
 	// If downloadDestinationPath is not set, download data will be stored in memory
 	NSString *downloadDestinationPath;
@@ -75,7 +109,7 @@ typedef enum _ASINetworkErrorType {
 	NSString *temporaryFileDownloadPath;
 	
 	// Used for writing data to a file when downloadDestinationPath is set
-	NSOutputStream *outputStream;
+	NSOutputStream *fileDownloadOutputStream;
 	
 	// When the request fails or completes successfully, complete will be true
 	BOOL complete;
@@ -84,9 +118,6 @@ typedef enum _ASINetworkErrorType {
 	// If error code is = ASIConnectionFailureErrorType (1, Connection failure occurred) - inspect [[error userInfo] objectForKey:NSUnderlyingErrorKey] for more information
 	NSError *error;
 	
-	// If an authentication error occurs, we give the delegate a chance to handle it, ignoreError will be set to true
-	BOOL ignoreError;
-	
 	// Username and password used for authentication
 	NSString *username;
 	NSString *password;
@@ -122,14 +153,21 @@ typedef enum _ASINetworkErrorType {
 	// Size of the response
 	unsigned long long contentLength;
 	
+	// Size of the partially downloaded content
+	unsigned long long partialDownloadSize;
+	
 	// Size of the POST payload
 	unsigned long long postLength;	
 	
 	// The total amount of downloaded data
 	unsigned long long totalBytesRead;
 	
+	// The total amount of uploaded data
+	unsigned long long totalBytesSent;
+	
 	// Last amount of data read (used for incrementing progress)
 	unsigned long long lastBytesRead;
+	
 	// Last amount of data sent (used for incrementing progress)
 	unsigned long long lastBytesSent;
 	
@@ -175,12 +213,38 @@ typedef enum _ASINetworkErrorType {
 	// Prevents the body of the post being built more than once (largely for subclasses)
 	BOOL haveBuiltPostBody;
 	
+	// Used internally, may reflect the size of the internal used by CFNetwork
+	// POST / PUT operations with body sizes greater than uploadBufferSize will not timeout unless more than uploadBufferSize bytes have been sent
+	// Likely to be 32KB on iPhone 3.0, 128KB on Mac OS X Leopard and iPhone 2.2.x
 	unsigned long long uploadBufferSize;
 	
+	// Text encoding for responses that do not send a Content-Type with a charset value. Defaults to NSISOLatin1StringEncoding
 	NSStringEncoding defaultResponseEncoding;
+	
+	// The text encoding of the response, will be defaultResponseEncoding if the server didn't specify. Can't be set.
 	NSStringEncoding responseEncoding;
 	
+	// Tells ASIHTTPRequest not to delete partial downloads, and allows it to use an existing file to resume a download. Defaults to NO.
 	BOOL allowResumeForFileDownloads;
+	
+	// Custom user information assosiated with the request
+	NSDictionary *userInfo;
+	
+	// Use HTTP 1.0 rather than 1.1 (defaults to false)
+	BOOL useHTTPVersionOne;
+	
+	// When YES, requests will automatically redirect when they get a HTTP 30x header (defaults to YES)
+	BOOL shouldRedirect;
+	
+	// Used internally to tell the main loop we need to stop and retry with a new url
+	BOOL needsRedirect;
+	
+	// Incremented every time this request redirects. When it reaches 5, we give up
+	int redirectCount;
+	
+	// When NO, requests will not check the secure certificate is valid (use for self-signed cerficates during development, DO NOT USE IN PRODUCTION) Default is YES
+	BOOL validatesSecureCertificate;
+
 }
 
 #pragma mark init / dealloc
@@ -188,6 +252,9 @@ typedef enum _ASINetworkErrorType {
 // Should be an HTTP or HTTPS url, may include username and password if appropriate
 - (id)initWithURL:(NSURL *)newURL;
 
+// Convenience constructor
++ (id)requestWithURL:(NSURL *)newURL;
+
 #pragma mark setup request
 
 // Add a custom header to the request
@@ -195,6 +262,10 @@ typedef enum _ASINetworkErrorType {
 
 - (void)buildPostBody;
 
+// Called to add data to the post body. Will append to postBody when shouldStreamPostDataFromDisk is false, or write to postBodyWriteStream when true
+- (void)appendPostData:(NSData *)data;
+- (void)appendPostDataFromFile:(NSString *)file;
+
 #pragma mark get information about this request
 
 // Returns the contents of the result as an NSString (not appropriate for binary data - used responseData instead)
@@ -217,6 +288,14 @@ typedef enum _ASINetworkErrorType {
 // Cancel loading and clean up
 - (void)cancelLoad;
 
+// Call to delete the temporary file used during a file download (if it exists)
+// No need to call this if the request succeeds - it is removed automatically
+- (void)removeTemporaryDownloadFile;
+
+// Call to remove the file used as the request body
+// No need to call this if the request succeeds and you didn't specify postBodyFilePath manually - it is removed automatically
+- (void)removePostDataFile;
+
 #pragma mark upload/download progress
 
 // Called on main thread to update progress delegates
@@ -240,11 +319,15 @@ typedef enum _ASINetworkErrorType {
 // Called when a request fails, and lets the delegate now via didFailSelector
 - (void)failWithError:(NSError *)theError;
 
-#pragma mark http authentication stuff
+#pragma mark parsing HTTP response headers
 
-// Reads the response headers to find the content length, and returns true if the request needs a username and password (or if those supplied were incorrect)
+// Reads the response headers to find the content length, encoding, cookies for the session 
+// Also initiates request redirection when shouldRedirect is true
+// Returns true if the request needs a username and password (or if those supplied were incorrect)
 - (BOOL)readResponseHeadersReturningAuthenticationFailure;
 
+#pragma mark http authentication stuff
+
 // Apply credentials to this request
 - (BOOL)applyCredentials:(NSMutableDictionary *)newCredentials;
 
@@ -290,10 +373,13 @@ typedef enum _ASINetworkErrorType {
 + (void)setSessionCookies:(NSMutableArray *)newSessionCookies;
 + (NSMutableArray *)sessionCookies;
 
+// Adds a cookie to our list of cookies we've accepted, checking first for an old version of the same cookie and removing that
++ (void)addSessionCookie:(NSHTTPCookie *)newCookie;
+
 // Dump all session data (authentication and cookies)
 + (void)clearSession;
 
-#pragma mark gzip compression
+#pragma mark gzip decompression
 
 // Uncompress gzipped data with zlib
 + (NSData *)uncompressZippedData:(NSData*)compressedData;
@@ -302,12 +388,28 @@ typedef enum _ASINetworkErrorType {
 + (int)uncompressZippedDataFromFile:(NSString *)sourcePath toFile:(NSString *)destinationPath;
 + (int)uncompressZippedDataFromSource:(FILE *)source toDestination:(FILE *)dest;
 
+#pragma mark gzip compression
+
+// Compress data with gzip using zlib
++ (NSData *)compressData:(NSData*)uncompressedData;
+
+// gzip compress data from a file, saving to another file, used for uploading when shouldCompressRequestBody is true
++ (int)compressDataFromFile:(NSString *)sourcePath toFile:(NSString *)destinationPath;
++ (int)compressDataFromSource:(FILE *)source toDestination:(FILE *)dest;
+
+#pragma mark get user agent
+
+// Will be used as a user agent if requests do not specify a custom user agent
+// Is only used when you have specified a Bundle Display Name (CFDisplayBundleName) or Bundle Name (CFBundleName) in your plist
++ (NSString *)defaultUserAgentString;
+
 @property (retain) NSString *username;
 @property (retain) NSString *password;
 @property (retain) NSString *domain;
 
-@property (retain,readonly) NSURL *url;
+@property (retain,setter=setURL:) NSURL *url;
 @property (assign) id delegate;
+@property (assign) id queue;
 @property (assign) id uploadProgressDelegate;
 @property (assign) id downloadProgressDelegate;
 @property (assign) BOOL useKeychainPersistance;
@@ -319,27 +421,35 @@ typedef enum _ASINetworkErrorType {
 @property (retain,readonly) NSString *authenticationRealm;
 @property (retain) NSError *error;
 @property (assign,readonly) BOOL complete;
-@property (retain) NSDictionary *responseHeaders;
+@property (retain,readonly) NSDictionary *responseHeaders;
 @property (retain) NSMutableDictionary *requestHeaders;
 @property (retain) NSMutableArray *requestCookies;
-@property (retain) NSArray *responseCookies;
+@property (retain,readonly) NSArray *responseCookies;
 @property (assign) BOOL useCookiePersistance;
 @property (retain) NSDictionary *requestCredentials;
-@property (assign) int responseStatusCode;
-@property (retain) NSMutableData *rawResponseData;
-@property (retain) NSDate *lastActivityTime;
+@property (assign,readonly) int responseStatusCode;
+@property (retain,readonly) NSMutableData *rawResponseData;
 @property (assign) NSTimeInterval timeOutSeconds;
 @property (retain) NSString *requestMethod;
-@property (retain,setter=setPostBody:) NSData *postBody;
-@property (assign) unsigned long long contentLength;
+@property (retain) NSMutableData *postBody;
+@property (assign,readonly) unsigned long long contentLength;
 @property (assign) unsigned long long postLength;
 @property (assign) BOOL shouldResetProgressIndicators;
 @property (retain) ASIHTTPRequest *mainRequest;
 @property (assign) BOOL showAccurateProgress;
 @property (assign,readonly) unsigned long long totalBytesRead;
-@property (assign) unsigned long long uploadBufferSize;
+@property (assign,readonly) unsigned long long totalBytesSent;
 @property (assign) NSStringEncoding defaultResponseEncoding;
-@property (assign) NSStringEncoding responseEncoding;
+@property (assign,readonly) NSStringEncoding responseEncoding;
 @property (assign) BOOL allowCompressedResponse;
 @property (assign) BOOL allowResumeForFileDownloads;
+@property (retain) NSDictionary *userInfo;
+@property (retain) NSString *postBodyFilePath;
+@property (assign) BOOL shouldStreamPostDataFromDisk;
+@property (assign) BOOL didCreateTemporaryPostDataFile;
+@property (assign) BOOL useHTTPVersionOne;
+@property (assign, readonly) unsigned long long partialDownloadSize;
+@property (assign) BOOL shouldRedirect;
+@property (assign) BOOL validatesSecureCertificate;
+@property (assign) BOOL shouldCompressRequestBody;
 @end</diff>
      <filename>Vendor/ASIHTTPRequest/ASIHTTPRequest.h</filename>
    </modified>
    <modified>
      <diff>@@ -11,13 +11,15 @@
 //  See: http://developer.apple.com/samplecode/ImageClient/listing37.html
 
 #import &quot;ASIHTTPRequest.h&quot;
-#import &quot;NSHTTPCookieAdditions.h&quot;
 #import &lt;zlib.h&gt;
+#ifndef TARGET_OS_IPHONE
+#import &lt;SystemConfiguration/SystemConfiguration.h&gt;
+#endif
 
 // We use our own custom run loop mode as CoreAnimation seems to want to hijack our threads otherwise
 static CFStringRef ASIHTTPRequestRunMode = CFSTR(&quot;ASIHTTPRequest&quot;);
 
-static NSString *NetworkRequestErrorDomain = @&quot;com.Your-Company.Your-Product.NetworkError.&quot;;
+NSString* const NetworkRequestErrorDomain = @&quot;ASIHTTPRequestErrorDomain&quot;;
 
 static const CFOptionFlags kNetworkEvents = kCFStreamEventOpenCompleted | kCFStreamEventHasBytesAvailable | kCFStreamEventEndEncountered | kCFStreamEventErrorOccurred;
 
@@ -25,6 +27,8 @@ static CFHTTPAuthenticationRef sessionAuthentication = NULL;
 static NSMutableDictionary *sessionCredentials = nil;
 static NSMutableArray *sessionCookies = nil;
 
+// The number of times we will allow requests to redirect before we fail with a redirection error
+const int RedirectionLimit = 5;
 
 static void ReadStreamClientCallBack(CFReadStreamRef readStream, CFStreamEventType type, void *clientCallBackInfo) {
     [((ASIHTTPRequest*)clientCallBackInfo) handleNetworkEvent: type];
@@ -37,6 +41,38 @@ static NSError *ASIRequestCancelledError;
 static NSError *ASIRequestTimedOutError;
 static NSError *ASIAuthenticationError;
 static NSError *ASIUnableToCreateRequestError;
+static NSError *ASITooMuchRedirectionError;
+
+
+// Private stuff
+@interface ASIHTTPRequest ()
+	@property (assign) BOOL complete;
+	@property (retain) NSDictionary *responseHeaders;
+	@property (retain) NSArray *responseCookies;
+	@property (assign) int responseStatusCode;
+	@property (retain) NSMutableData *rawResponseData;
+	@property (retain, nonatomic) NSDate *lastActivityTime;
+	@property (assign) unsigned long long contentLength;
+	@property (assign) unsigned long long partialDownloadSize;
+	@property (assign, nonatomic) unsigned long long uploadBufferSize;
+	@property (assign) NSStringEncoding responseEncoding;
+	@property (retain, nonatomic) NSOutputStream *postBodyWriteStream;
+	@property (retain, nonatomic) NSInputStream *postBodyReadStream;
+	@property (assign) unsigned long long totalBytesRead;
+	@property (assign) unsigned long long totalBytesSent;
+	@property (assign, nonatomic) unsigned long long lastBytesRead;
+	@property (assign, nonatomic) unsigned long long lastBytesSent;
+	@property (retain) NSLock *cancelledLock;
+	@property (assign, nonatomic) BOOL haveBuiltPostBody;
+	@property (retain, nonatomic) NSOutputStream *fileDownloadOutputStream;
+	@property (assign, nonatomic) int authenticationRetryCount;
+	@property (assign, nonatomic) BOOL updatedProgress;
+	@property (assign, nonatomic) BOOL needsRedirect;
+	@property (assign, nonatomic) int redirectCount;
+	@property (retain, nonatomic) NSData *compressedPostBody;
+	@property (retain, nonatomic) NSString *compressedPostBodyFilePath;
+	@property (retain) NSConditionLock *authenticationLock;
+@end
 
 @implementation ASIHTTPRequest
 
@@ -52,49 +88,41 @@ static NSError *ASIUnableToCreateRequestError;
 		ASIAuthenticationError = [[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIAuthenticationErrorType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@&quot;Authentication needed&quot;,NSLocalizedDescriptionKey,nil]] retain];
 		ASIRequestCancelledError = [[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIRequestCancelledErrorType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@&quot;The request was cancelled&quot;,NSLocalizedDescriptionKey,nil]] retain];
 		ASIUnableToCreateRequestError = [[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIUnableToCreateRequestErrorType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@&quot;Unable to create request (bad url?)&quot;,NSLocalizedDescriptionKey,nil]] retain];
+		ASITooMuchRedirectionError = [[NSError errorWithDomain:NetworkRequestErrorDomain code:ASITooMuchRedirectionErrorType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@&quot;The request failed because it redirected too many times&quot;,NSLocalizedDescriptionKey,nil]] retain];	
+
 	}
 	[super initialize];
 }
 
+
 - (id)initWithURL:(NSURL *)newURL
 {
 	self = [super init];
 	[self setRequestMethod:@&quot;GET&quot;];
-	lastBytesSent = 0;
-
-	showAccurateProgress = YES;
-	shouldResetProgressIndicators = YES;
-	updatedProgress = NO;
-	[self setMainRequest:nil];
-	[self setPassword:nil];
-	[self setUsername:nil];
-	[self setRequestHeaders:nil];
-	authenticationRetryCount = 0;
-	authenticationMethod = nil;
-	authenticationRealm = nil;
-	outputStream = nil;
-	requestAuthentication = NULL;
-	haveBuiltPostBody = NO;
-	request = NULL;
+
+	[self setShouldRedirect:YES];
+	[self setShowAccurateProgress:YES];
+	[self setShouldResetProgressIndicators:YES];
 	[self setAllowCompressedResponse:YES];
 	[self setDefaultResponseEncoding:NSISOLatin1StringEncoding];
-	[self setUploadBufferSize:0];
-	[self setResponseHeaders:nil];
+	
 	[self setTimeOutSeconds:10];
-	[self setAllowResumeForFileDownloads:NO];
-	[self setUseKeychainPersistance:NO];
 	[self setUseSessionPersistance:YES];
 	[self setUseCookiePersistance:YES];
-	[self setRawResponseData:nil];
+	[self setValidatesSecureCertificate:YES];
 	[self setRequestCookies:[[[NSMutableArray alloc] init] autorelease]];
 	[self setDidFinishSelector:@selector(requestFinished:)];
 	[self setDidFailSelector:@selector(requestFailed:)];
-	[self setDelegate:nil];
-	url = [newURL retain];
-	cancelledLock = [[NSLock alloc] init];
+	[self setURL:newURL];
+	[self setCancelledLock:[[[NSLock alloc] init] autorelease]];
 	return self;
 }
 
++ (id)requestWithURL:(NSURL *)newURL
+{
+	return [[[self alloc] initWithURL:newURL] autorelease];
+}
+
 - (void)dealloc
 {
 	if (requestAuthentication) {
@@ -104,15 +132,17 @@ static NSError *ASIUnableToCreateRequestError;
 		CFRelease(request);
 	}
 	[self cancelLoad];
+	[userInfo release];
 	[mainRequest release];
 	[postBody release];
+	[compressedPostBody release];
 	[requestCredentials release];
 	[error release];
 	[requestHeaders release];
 	[requestCookies release];
 	[downloadDestinationPath release];
 	[temporaryFileDownloadPath release];
-	[outputStream release];
+	[fileDownloadOutputStream release];
 	[username release];
 	[password release];
 	[domain release];
@@ -126,6 +156,10 @@ static NSError *ASIUnableToCreateRequestError;
 	[requestMethod release];
 	[cancelledLock release];
 	[authenticationMethod release];
+	[postBodyFilePath release];
+	[compressedPostBodyFilePath release];
+	[postBodyWriteStream release];
+	[postBodyReadStream release];
 	[super dealloc];
 }
 
@@ -140,43 +174,123 @@ static NSError *ASIUnableToCreateRequestError;
 	[requestHeaders setObject:value forKey:header];
 }
 
--(void)setPostBody:(NSData *)body
+// This function will be called either just before a request starts, or when postLength is needed, whichever comes first
+// postLength must be set by the time this function is complete
+- (void)buildPostBody
 {
-	postBody = [body retain];
-	postLength = [postBody length];
-	[self addRequestHeader:@&quot;Content-Length&quot; value:[NSString stringWithFormat:@&quot;%llu&quot;,postLength]];
-	if (postBody &amp;&amp; postLength &gt; 0 &amp;&amp; ![requestMethod isEqualToString:@&quot;POST&quot;] &amp;&amp; ![requestMethod isEqualToString:@&quot;PUT&quot;]) {
-		[self setRequestMethod:@&quot;POST&quot;];
+	// Are we submitting the request body from a file on disk
+	if ([self postBodyFilePath]) {
+		
+		// If we were writing to the post body via appendPostData or appendPostDataFromFile, close the write stream
+		if ([self postBodyWriteStream]) {
+			[[self postBodyWriteStream] close];
+			[self setPostBodyWriteStream:nil];
+		}
+
+		if ([self shouldCompressRequestBody]) {
+			[self setCompressedPostBodyFilePath:[NSTemporaryDirectory() stringByAppendingPathComponent:[[NSProcessInfo processInfo] globallyUniqueString]]];
+			[ASIHTTPRequest compressDataFromFile:[self postBodyFilePath] toFile:[self compressedPostBodyFilePath]];
+			[self setPostLength:[[[NSFileManager defaultManager] fileAttributesAtPath:[self compressedPostBodyFilePath] traverseLink:NO] fileSize]];
+		} else {
+			[self setPostLength:[[[NSFileManager defaultManager] fileAttributesAtPath:[self postBodyFilePath] traverseLink:NO] fileSize]];
+		}
+		
+	// Otherwise, we have an in-memory request body
+	} else {
+		if ([self shouldCompressRequestBody]) {
+			[self setCompressedPostBody:[ASIHTTPRequest compressData:[self postBody]]];
+			[self setPostLength:[[self compressedPostBody] length]];
+		} else {
+			[self setPostLength:[[self postBody] length]];
+		}
 	}
+		
+	if ([self postLength] &gt; 0) {
+		if (![requestMethod isEqualToString:@&quot;POST&quot;] &amp;&amp; ![requestMethod isEqualToString:@&quot;PUT&quot;]) {
+			[self setRequestMethod:@&quot;POST&quot;];
+		}
+		[self addRequestHeader:@&quot;Content-Length&quot; value:[NSString stringWithFormat:@&quot;%llu&quot;,[self postLength]]];
+	}
+	[self setHaveBuiltPostBody:YES];
 }
 
-// Subclasses should override this method if they need to create POST content for this request
-// This function will be called either just before a request starts, or when postLength is needed, whichever comes first
-// postLength must be set by the time this function is complete - calling setPostBody: will do this for you
-- (void)buildPostBody
+// Sets up storage for the post body
+- (void)setupPostBody
 {
-	haveBuiltPostBody = YES;
+	if ([self shouldStreamPostDataFromDisk]) {
+		if (![self postBodyFilePath]) {
+			[self setPostBodyFilePath:[NSTemporaryDirectory() stringByAppendingPathComponent:[[NSProcessInfo processInfo] globallyUniqueString]]];
+			[self setDidCreateTemporaryPostDataFile:YES];
+		}
+		if (![self postBodyWriteStream]) {
+			[self setPostBodyWriteStream:[[[NSOutputStream alloc] initToFileAtPath:[self postBodyFilePath] append:NO] autorelease]];
+			[[self postBodyWriteStream] open];
+		}
+	} else {
+		if (![self postBody]) {
+			[self setPostBody:[[[NSMutableData alloc] init] autorelease]];
+		}
+	}	
+}
+
+- (void)appendPostData:(NSData *)data
+{
+	[self setupPostBody];
+	if ([data length] == 0) {
+		return;
+	}
+	if ([self shouldStreamPostDataFromDisk]) {
+		[[self postBodyWriteStream] write:[data bytes] maxLength:[data length]];
+	} else {
+		[[self postBody] appendData:data];
+	}
+}
+
+- (void)appendPostDataFromFile:(NSString *)file
+{
+	[self setupPostBody];
+	NSInputStream *stream = [[[NSInputStream alloc] initWithFileAtPath:file] autorelease];
+	[stream open];
+	int bytesRead;
+	while ([stream hasBytesAvailable]) {
+		
+		unsigned char buffer[1024*256];
+		bytesRead = [stream read:buffer maxLength:sizeof(buffer)];
+		if (bytesRead == 0) {
+			break;
+		}
+		if ([self shouldStreamPostDataFromDisk]) {
+			[[self postBodyWriteStream] write:buffer maxLength:bytesRead];
+		} else {
+			[[self postBody] appendData:[NSData dataWithBytes:buffer length:bytesRead]];
+		}
+	}
+	[stream close];
 }
 
 #pragma mark get information about this request
 
 - (BOOL)isFinished 
 {
-	return complete;
+	return [self complete];
 }
 
 
 - (void)cancel
 {
+	// Request may already be complete
+	if ([self complete] || [self isCancelled]) {
+		return;
+	}
 	[self failWithError:ASIRequestCancelledError];
 	[super cancel];
 	[self cancelLoad];
-	complete = YES;
+	[self setComplete:YES];
 
 }
 
 
-// Call this method to get the received data as an NSString. Don't use for Binary data!
+// Call this method to get the received data as an NSString. Don't use for binary data!
 - (NSString *)responseString
 {
 	NSData *data = [self responseData];
@@ -202,6 +316,7 @@ static NSError *ASIUnableToCreateRequestError;
 	}
 }
 
+
 #pragma mark request logic
 
 // Create the request
@@ -211,22 +326,32 @@ static NSError *ASIUnableToCreateRequestError;
 	[pool release];
 	pool = [[NSAutoreleasePool alloc] init];
 	
-	complete = NO;
+	[self setComplete:NO];
 	
-	if (!url) {
+	if (![self url]) {
 		[self failWithError:ASIUnableToCreateRequestError];
 		return;		
 	}
 	
+	if (![self haveBuiltPostBody]) {
+		[self buildPostBody];
+	}
+	
+	// If we're redirecting, we'll already have a CFHTTPMessageRef
+	if (request) {
+		CFRelease(request);
+	}
+	
     // Create a new HTTP request.
-	request = CFHTTPMessageCreateRequest(kCFAllocatorDefault, (CFStringRef)requestMethod, (CFURLRef)url, kCFHTTPVersion1_1);
+	request = CFHTTPMessageCreateRequest(kCFAllocatorDefault, (CFStringRef)[self requestMethod], (CFURLRef)[self url], [self useHTTPVersionOne] ? kCFHTTPVersion1_0 : kCFHTTPVersion1_1);
     if (!request) {
 		[self failWithError:ASIUnableToCreateRequestError];
 		return;
     }
 	
+	
 	// If we've already talked to this server and have valid credentials, let's apply them to the request
-	if (useSessionPersistance &amp;&amp; sessionCredentials &amp;&amp; sessionAuthentication) {
+	if ([self useSessionPersistance] &amp;&amp; sessionCredentials &amp;&amp; sessionAuthentication) {
 		if (!CFHTTPMessageApplyCredentialDictionary(request, sessionAuthentication, (CFMutableDictionaryRef)sessionCredentials, NULL)) {
 			[ASIHTTPRequest setSessionAuthentication:NULL];
 			[ASIHTTPRequest setSessionCredentials:nil];
@@ -234,10 +359,10 @@ static NSError *ASIUnableToCreateRequestError;
 	}
 	
 	// Add cookies from the persistant (mac os global) store
-	if (useCookiePersistance) {
-		NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:url];
+	if ([self useCookiePersistance] ) {
+		NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:[self url]];
 		if (cookies) {
-			[requestCookies addObjectsFromArray:cookies];
+			[[self requestCookies] addObjectsFromArray:cookies];
 		}
 	}
 	
@@ -253,9 +378,9 @@ static NSError *ASIUnableToCreateRequestError;
 		NSString *cookieHeader = nil;
 		for (cookie in cookies) {
 			if (!cookieHeader) {
-				cookieHeader = [NSString stringWithFormat: @&quot;%@=%@&quot;,[cookie name],[cookie encodedValue]];
+				cookieHeader = [NSString stringWithFormat: @&quot;%@=%@&quot;,[cookie name],[cookie value]];
 			} else {
-				cookieHeader = [NSString stringWithFormat: @&quot;%@; %@=%@&quot;,cookieHeader,[cookie name],[cookie encodedValue]];
+				cookieHeader = [NSString stringWithFormat: @&quot;%@; %@=%@&quot;,cookieHeader,[cookie name],[cookie value]];
 			}
 		}
 		if (cookieHeader) {
@@ -263,27 +388,35 @@ static NSError *ASIUnableToCreateRequestError;
 		}
 	}
 	
-	
-	if (!haveBuiltPostBody) {
-		[self buildPostBody];
+	// Build and set the user agent string if the request does not already have a custom user agent specified
+	if (![[self requestHeaders] objectForKey:@&quot;User-Agent&quot;]) {
+		NSString *userAgentString = [ASIHTTPRequest defaultUserAgentString];
+		if (userAgentString) {
+			[self addRequestHeader:@&quot;User-Agent&quot; value:userAgentString];
+		}
 	}
-	
+
 	
 	// Accept a compressed response
 	if ([self allowCompressedResponse]) {
 		[self addRequestHeader:@&quot;Accept-Encoding&quot; value:@&quot;gzip&quot;];
 	}
 	
+	// Configure a compressed request body
+	if ([self shouldCompressRequestBody]) {
+		[self addRequestHeader:@&quot;Content-Encoding&quot; value:@&quot;gzip&quot;];
+	}
+	
 	// Should this request resume an existing download?
 	if ([self allowResumeForFileDownloads] &amp;&amp; [self downloadDestinationPath] &amp;&amp; [self temporaryFileDownloadPath] &amp;&amp; [[NSFileManager defaultManager] fileExistsAtPath:[self temporaryFileDownloadPath]]) {
-		unsigned long long downloadedSoFar = [[[NSFileManager defaultManager] fileAttributesAtPath:[self temporaryFileDownloadPath] traverseLink:NO] fileSize];
-		[self addRequestHeader:@&quot;Range&quot; value:[NSString stringWithFormat:@&quot;bytes=%llu-&quot;,downloadedSoFar]];
+		[self setPartialDownloadSize:[[[NSFileManager defaultManager] fileAttributesAtPath:[self temporaryFileDownloadPath] traverseLink:NO] fileSize]];
+		[self addRequestHeader:@&quot;Range&quot; value:[NSString stringWithFormat:@&quot;bytes=%llu-&quot;,[self partialDownloadSize]]];
 	}
 	
 	// Add custom headers
 	NSDictionary *headers;
 	
-	//Add headers from the main request if this is a HEAD request generated by an ASINetwork Queue
+	//Add headers from the main request if this is a HEAD request generated by an ASINetworkQueue
 	if ([self mainRequest]) {
 		headers = [mainRequest requestHeaders];
 	} else {
@@ -291,13 +424,14 @@ static NSError *ASIUnableToCreateRequestError;
 	}	
 	NSString *header;
 	for (header in headers) {
-		CFHTTPMessageSetHeaderFieldValue(request, (CFStringRef)header, (CFStringRef)[requestHeaders objectForKey:header]);
+		CFHTTPMessageSetHeaderFieldValue(request, (CFStringRef)header, (CFStringRef)[[self requestHeaders] objectForKey:header]);
 	}
-	
-	
-	// If this is a post request and we have data to send, add it to the request
-	if ([self postBody]) {
-		CFHTTPMessageSetBody(request, (CFDataRef)postBody);
+
+	// If this is a post/put request and we store the request body in memory, add it to the request
+	if ([self shouldCompressRequestBody] &amp;&amp; [self compressedPostBody]) {
+		CFHTTPMessageSetBody(request, (CFDataRef)[self compressedPostBody]);
+	} else if ([self postBody]) {
+		CFHTTPMessageSetBody(request, (CFDataRef)[self postBody]);
 	}
 	
 	[self loadRequest];
@@ -306,47 +440,80 @@ static NSError *ASIUnableToCreateRequestError;
 
 - (void)startRequest
 {
-	[cancelledLock lock];
+	[[self cancelledLock] lock];
 	
 	if ([self isCancelled]) {
-		[cancelledLock unlock];
+		[[self cancelledLock] unlock];
 		return;
 	}
 	
-	[authenticationLock release];
-	authenticationLock = [[NSConditionLock alloc] initWithCondition:1];
+	[self setAuthenticationLock:[[[NSConditionLock alloc] initWithCondition:1] autorelease]];
 	
-	complete = NO;
-	totalBytesRead = 0;
-	lastBytesRead = 0;
+	[self setComplete:NO];
+	[self setTotalBytesRead:0];
+	[self setLastBytesRead:0];
 	
 	// If we're retrying a request after an authentication failure, let's remove any progress we made
-	if (lastBytesSent &gt; 0 &amp;&amp; uploadProgressDelegate) {
+	if ([self lastBytesSent] &gt; 0) {
 		[self removeUploadProgressSoFar];
 	}
 	
-	lastBytesSent = 0;
-	if (shouldResetProgressIndicators) {
-		contentLength = 0;
+	[self setLastBytesSent:0];
+	if ([self shouldResetProgressIndicators]) {
+		[self setContentLength:0];
+		[self resetDownloadProgress:0];
 	}
 	[self setResponseHeaders:nil];
 	if (![self downloadDestinationPath]) {
 		[self setRawResponseData:[[[NSMutableData alloc] init] autorelease]];
     }
     // Create the stream for the request.
-    readStream = CFReadStreamCreateForStreamedHTTPRequest(kCFAllocatorDefault, request,readStream);
-    if (!readStream) {
-		[cancelledLock unlock];
+	if ([self shouldStreamPostDataFromDisk] &amp;&amp; [self postBodyFilePath] &amp;&amp; [[NSFileManager defaultManager] fileExistsAtPath:[self postBodyFilePath]]) {
+		
+		// Are we gzipping the request body?
+		if ([self compressedPostBodyFilePath] &amp;&amp; [[NSFileManager defaultManager] fileExistsAtPath:[self compressedPostBodyFilePath]]) {
+			[self setPostBodyReadStream:[[[NSInputStream alloc] initWithFileAtPath:[self compressedPostBodyFilePath]] autorelease]];
+		} else {
+			[self setPostBodyReadStream:[[[NSInputStream alloc] initWithFileAtPath:[self postBodyFilePath]] autorelease]];	
+		}
+		readStream = CFReadStreamCreateForStreamedHTTPRequest(kCFAllocatorDefault, request,(CFReadStreamRef)[self postBodyReadStream]);
+    } else {
+		readStream = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, request);
+	}
+	if (!readStream) {
+		[[self cancelledLock] unlock];
 		[self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIInternalErrorWhileBuildingRequestType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@&quot;Unable to create read stream&quot;,NSLocalizedDescriptionKey,nil]]];
         return;
     }
-    
+
+	// Tell CFNetwork not to validate SSL certificates
+	if (!validatesSecureCertificate) {
+		CFReadStreamSetProperty(readStream, kCFStreamPropertySSLSettings, [NSMutableDictionary dictionaryWithObject:(NSString *)kCFBooleanFalse forKey:(NSString *)kCFStreamSSLValidatesCertificateChain]); 
+	}
+	
+	// Detect proxy settings and apply them
+#if TARGET_OS_IPHONE
+	#if TARGET_IPHONE_SIMULATOR
+		#if __IPHONE_OS_VERSION_MIN_REQUIRED &gt; __IPHONE_2_2
+	NSDictionary *proxySettings = [(NSDictionary *)CFNetworkCopySystemProxySettings() autorelease];
+		#else
+	// Can't detect proxies in 2.2.1 Simulator
+	NSDictionary *proxySettings = [NSMutableDictionary dictionary];	
+		#endif
+	#else
+	NSDictionary *proxySettings = [(NSDictionary *)CFNetworkCopySystemProxySettings() autorelease];
+	#endif
+#else
+	NSDictionary *proxySettings = [(NSDictionary *)SCDynamicStoreCopyProxies(NULL) autorelease];
+#endif
+	CFReadStreamSetProperty(readStream, kCFStreamPropertyHTTPProxy, proxySettings);
+	
     // Set the client
 	CFStreamClientContext ctxt = {0, self, NULL, NULL, NULL};
     if (!CFReadStreamSetClient(readStream, kNetworkEvents, ReadStreamClientCallBack, &amp;ctxt)) {
         CFRelease(readStream);
         readStream = NULL;
-		[cancelledLock unlock];
+		[[self cancelledLock] unlock];
 		[self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIInternalErrorWhileBuildingRequestType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@&quot;Unable to setup read stream&quot;,NSLocalizedDescriptionKey,nil]]];
         return;
     }
@@ -360,14 +527,14 @@ static NSError *ASIUnableToCreateRequestError;
         CFReadStreamUnscheduleFromRunLoop(readStream, CFRunLoopGetCurrent(), ASIHTTPRequestRunMode);
         CFRelease(readStream);
         readStream = NULL;
-		[cancelledLock unlock];
+		[[self cancelledLock] unlock];
 		[self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIInternalErrorWhileBuildingRequestType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@&quot;Unable to start HTTP connection&quot;,NSLocalizedDescriptionKey,nil]]];
         return;
     }
-	[cancelledLock unlock];
+	[[self cancelledLock] unlock];
 	
 	
-	if (uploadProgressDelegate &amp;&amp; shouldResetProgressIndicators) {
+	if (shouldResetProgressIndicators) {
 		double amount = 1;
 		if (showAccurateProgress) {
 			amount = postLength;
@@ -376,14 +543,11 @@ static NSError *ASIUnableToCreateRequestError;
 	}	
 }
 
-// Start the request
+// This is the 'main loop' for the request. Basically, it runs the runloop that our network stuff is attached to, and checks to see if we should cancel or timeout
 - (void)loadRequest
 {
-
-
 	[self startRequest];
 	
-	
 	// Record when the request started, so we can timeout if nothing happens
 	[self setLastActivityTime:[NSDate date]];
 	
@@ -399,24 +563,53 @@ static NSError *ASIUnableToCreateRequestError;
 		// See if we need to timeout
 		if (lastActivityTime &amp;&amp; timeOutSeconds &gt; 0 &amp;&amp; [now timeIntervalSinceDate:lastActivityTime] &gt; timeOutSeconds) {
 			
-			// Prevent timeouts before 128KB has been sent when the size of data to upload is greater than 128KB
+			// Prevent timeouts before 128KB* has been sent when the size of data to upload is greater than 128KB* (*32KB on iPhone 3.0 SDK)
 			// This is to workaround the fact that kCFStreamPropertyHTTPRequestBytesWrittenCount is the amount written to the buffer, not the amount actually sent
 			// This workaround prevents erroneous timeouts in low bandwidth situations (eg iPhone)
-			if (contentLength &lt;= uploadBufferSize || (uploadBufferSize &gt; 0 &amp;&amp; lastBytesSent &gt; uploadBufferSize)) {
+			if (totalBytesSent || postLength &lt;= uploadBufferSize || (uploadBufferSize &gt; 0 &amp;&amp; totalBytesSent &gt; uploadBufferSize)) {
 				[self failWithError:ASIRequestTimedOutError];
 				[self cancelLoad];
-				complete = YES;
+				[self setComplete:YES];
 				break;
 			}
 		}
 		
+		// Do we need to redirect?
+		if ([self needsRedirect]) {
+			[self cancelLoad];
+			[self setNeedsRedirect:NO];
+			[self setRedirectCount:[self redirectCount]+1];
+			if ([self redirectCount] &gt; RedirectionLimit) {
+				// Some naughty / badly coded website is trying to force us into a redirection loop. This is not cool.
+				[self failWithError:ASITooMuchRedirectionError];
+				[self setComplete:YES];
+			} else {
+				// Go all the way back to the beginning and build the request again, so that we can apply any new cookies
+				[self main];
+			}
+			break;
+		}
+		
 		// See if our NSOperationQueue told us to cancel
 		if ([self isCancelled]) {
 			break;
 		}
 		
+		// Find out if we've sent any more data than last time, and reset the timeout if so
+		if (totalBytesSent &gt; lastBytesSent) {
+			[self setLastActivityTime:[NSDate date]];
+			[self setLastBytesSent:totalBytesSent];
+		}
+		
+		// Find out how much data we've uploaded so far
+		[[self cancelledLock] lock];
+		[self setTotalBytesSent:[[(NSNumber *)CFReadStreamCopyProperty(readStream, kCFStreamPropertyHTTPRequestBytesWrittenCount) autorelease] unsignedLongLongValue]];
+		[[self cancelledLock] unlock];
+		
 		[self updateProgressIndicators];
 		
+		
+		
 		// This thread should wait for 1/4 second for the stream to do something. We'll stop early if it does.
 		CFRunLoopRunInMode(ASIHTTPRequestRunMode,0.25,YES);
 	}
@@ -428,7 +621,7 @@ static NSError *ASIUnableToCreateRequestError;
 // Cancel loading and clean up
 - (void)cancelLoad
 {
-	[cancelledLock lock];
+	[[self cancelledLock] lock];
     if (readStream) {
         CFReadStreamClose(readStream);
         CFReadStreamSetClient(readStream, kCFStreamEventNone, NULL, NULL);
@@ -437,12 +630,14 @@ static NSError *ASIUnableToCreateRequestError;
         readStream = NULL;
     }
 	
+	[[self postBodyReadStream] close];
+	
     if (rawResponseData) {
 		[self setRawResponseData:nil];
 	
 	// If we were downloading to a file
 	} else if (temporaryFileDownloadPath) {
-		[outputStream close];
+		[fileDownloadOutputStream close];
 		
 		// If we haven't said we might want to resume, let's remove the temporary file too
 		if (![self allowResumeForFileDownloads]) {
@@ -450,10 +645,47 @@ static NSError *ASIUnableToCreateRequestError;
 		}
 	}
 	
+	// Clean up any temporary file used to store request body for streaming
+	if ([self didCreateTemporaryPostDataFile]) {
+		[self removePostDataFile];
+	}
+	
 	[self setResponseHeaders:nil];
-	[cancelledLock unlock];
+	[[self cancelledLock] unlock];
+}
+
+
+- (void)removeTemporaryDownloadFile
+{
+	if (temporaryFileDownloadPath) {
+		NSError *removeError = nil;
+		[[NSFileManager defaultManager] removeItemAtPath:temporaryFileDownloadPath error:&amp;removeError];
+		if (removeError) {
+			[self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIFileManagementError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@&quot;Failed to delete file at %@ with error: %@&quot;,temporaryFileDownloadPath,removeError],NSLocalizedDescriptionKey,removeError,NSUnderlyingErrorKey,nil]]];
+		}
+		[self setTemporaryFileDownloadPath:nil];
+	}
 }
 
+- (void)removePostDataFile
+{
+	if ([self postBodyFilePath]) {
+		NSError *removeError = nil;
+		[[NSFileManager defaultManager] removeItemAtPath:[self postBodyFilePath] error:&amp;removeError];
+		if (removeError) {
+			[self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIFileManagementError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@&quot;Failed to delete file at %@ with error: %@&quot;,[self postBodyFilePath],removeError],NSLocalizedDescriptionKey,removeError,NSUnderlyingErrorKey,nil]]];
+		}
+		[self setPostBodyFilePath:nil];
+	}
+	if ([self compressedPostBodyFilePath]) {
+		NSError *removeError = nil;
+		[[NSFileManager defaultManager] removeItemAtPath:[self compressedPostBodyFilePath] error:&amp;removeError];
+		if (removeError) {
+			[self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIFileManagementError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@&quot;Failed to delete file at %@ with error: %@&quot;,[self compressedPostBodyFilePath],removeError],NSLocalizedDescriptionKey,removeError,NSUnderlyingErrorKey,nil]]];
+		}
+		[self setCompressedPostBodyFilePath:nil];
+	}
+}
 
 
 #pragma mark upload/download progress
@@ -464,7 +696,7 @@ static NSError *ASIUnableToCreateRequestError;
 	
 	//Only update progress if this isn't a HEAD request used to preset the content-length
 	if (!mainRequest) {
-		if (showAccurateProgress || (complete &amp;&amp; !updatedProgress)) {
+		if ([self showAccurateProgress] || ([self complete] &amp;&amp; ![self updatedProgress])) {
 			[self updateUploadProgress];
 			[self updateDownloadProgress];
 		}
@@ -511,16 +743,9 @@ static NSError *ASIUnableToCreateRequestError;
 - (void)resetUploadProgress:(unsigned long long)value
 {
 	[progressLock lock];
-	//We're using a progress queue or compatible controller to handle progress
-	if ([uploadProgressDelegate respondsToSelector:@selector(incrementUploadSizeBy:)]) {
-		SEL selector = @selector(incrementUploadSizeBy:);
-		NSMethodSignature *signature = [[uploadProgressDelegate class] instanceMethodSignatureForSelector:selector];
-		NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
-		[invocation setTarget:uploadProgressDelegate];
-		[invocation setSelector:selector];
-		[invocation setArgument:&amp;value atIndex:2];
-		[invocation invoke];
-	} else {
+	
+	// Request this request's own upload progress delegate
+	if (uploadProgressDelegate) {
 		[ASIHTTPRequest setProgress:0 forProgressIndicator:uploadProgressDelegate];
 	}
 	[progressLock unlock];
@@ -528,87 +753,88 @@ static NSError *ASIUnableToCreateRequestError;
 
 - (void)updateUploadProgress
 {
-	[cancelledLock lock];
+	[[self cancelledLock] lock];
 	if ([self isCancelled]) {
-		[cancelledLock unlock];
+		[[self cancelledLock] unlock];
 		return;
 	}
-	unsigned long long byteCount = [[(NSNumber *)CFReadStreamCopyProperty(readStream, kCFStreamPropertyHTTPRequestBytesWrittenCount) autorelease] unsignedLongLongValue];
 	
-	// If this is the first time we've written to the buffer, byteCount will be the size of the buffer (currently seems to be 128KB on both Mac and iPhone)
+	// If this is the first time we've written to the buffer, byteCount will be the size of the buffer (currently seems to be 128KB on both Leopard and iPhone 2.2.1, 32KB on iPhone 3.0)
+	// If request body is less than the buffer size, byteCount will be the total size of the request body
 	// We will remove this from any progress display, as kCFStreamPropertyHTTPRequestBytesWrittenCount does not tell us how much data has actually be written
-	if (byteCount &gt; 0 &amp;&amp; uploadBufferSize == 0 &amp;&amp; byteCount != postLength) {
-		[self setUploadBufferSize:byteCount];
+	if (totalBytesSent &gt; 0 &amp;&amp; uploadBufferSize == 0 &amp;&amp; totalBytesSent != postLength) {
+		[self setUploadBufferSize:totalBytesSent];
 		SEL selector = @selector(setUploadBufferSize:);
-		if ([uploadProgressDelegate respondsToSelector:selector]) {
+		if ([queue respondsToSelector:selector]) {
 			NSMethodSignature *signature = nil;
-			signature = [[uploadProgressDelegate class] instanceMethodSignatureForSelector:selector];
+			signature = [[queue class] instanceMethodSignatureForSelector:selector];
 			NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
-			[invocation setTarget:uploadProgressDelegate];
+			[invocation setTarget:queue];
 			[invocation setSelector:selector];
-			[invocation setArgument:&amp;byteCount atIndex:2];
+			[invocation setArgument:&amp;totalBytesSent atIndex:2];
 			[invocation invoke];
 		}
 	}
 	
 
 	
-	[cancelledLock unlock];
-	if (byteCount &gt; lastBytesSent) {
-		[self setLastActivityTime:[NSDate date]];		
+	[[self cancelledLock] unlock];
+
+	if (totalBytesSent == 0) {
+		return;
 	}
 	
-	if (uploadProgressDelegate) {
 		
-		// We're using a progress queue or compatible controller to handle progress
-		if ([uploadProgressDelegate respondsToSelector:@selector(incrementUploadProgressBy:)]) {
-			unsigned long long value = 0;
-			if (showAccurateProgress) {
-				if (byteCount == postLength) {
-					value = byteCount+uploadBufferSize;
-				} else if (lastBytesSent &gt; 0) {
-					value = ((byteCount-uploadBufferSize)-(lastBytesSent-uploadBufferSize));
-				} else {
-					value = 0;
-				}
+	// Update the progress queue, if we have one
+	SEL selector = @selector(incrementUploadProgressBy:);
+	if ([queue respondsToSelector:selector]) {
+		unsigned long long value = 0;
+		if (showAccurateProgress) {
+			if (totalBytesSent == postLength || lastBytesSent &gt; 0) {
+				value = totalBytesSent-lastBytesSent;
 			} else {
-				value = 1;
-				updatedProgress = YES;
+				value = 0;
 			}
-			SEL selector = @selector(incrementUploadProgressBy:);
-			NSMethodSignature *signature = nil;
-			signature = [[uploadProgressDelegate class] instanceMethodSignatureForSelector:selector];
-			NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
-			[invocation setTarget:uploadProgressDelegate];
-			[invocation setSelector:selector];
-			[invocation setArgument:&amp;value atIndex:2];
-			[invocation invoke];
-			
-			// We aren't using a queue, we should just set progress of the indicator
 		} else {
-			[ASIHTTPRequest setProgress:(double)(1.0*(byteCount-uploadBufferSize)/(postLength-uploadBufferSize)) forProgressIndicator:uploadProgressDelegate];
+			value = 1;
+			[self setUpdatedProgress:YES];
 		}
 		
+		NSMethodSignature *signature = nil;
+		signature = [[queue class] instanceMethodSignatureForSelector:selector];
+		NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
+		[invocation setTarget:queue];
+		[invocation setSelector:selector];
+		[invocation setArgument:&amp;value atIndex:2];
+		[invocation invoke];
 	}
-	lastBytesSent = byteCount;
-	
+
+	// Update this request's own upload progress delegate
+	if (uploadProgressDelegate) {
+		[ASIHTTPRequest setProgress:(double)(1.0*(totalBytesSent-uploadBufferSize)/(postLength-uploadBufferSize)) forProgressIndicator:uploadProgressDelegate];
+		
+	}
+
 }
 
 
 - (void)resetDownloadProgress:(unsigned long long)value
 {
 	[progressLock lock];	
-	// We're using a progress queue or compatible controller to handle progress
-	if ([downloadProgressDelegate respondsToSelector:@selector(incrementDownloadSizeBy:)]) {
-		SEL selector = @selector(incrementDownloadSizeBy:);
-		NSMethodSignature *signature = [[downloadProgressDelegate class] instanceMethodSignatureForSelector:selector];
+	
+	// Reset download progress for this request in the queue
+	SEL selector = @selector(incrementDownloadSizeBy:);
+	if ([queue respondsToSelector:selector]) {
+		NSMethodSignature *signature = [[queue class] instanceMethodSignatureForSelector:selector];
 		NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
-		[invocation setTarget:downloadProgressDelegate];
+		[invocation setTarget:queue];
 		[invocation setSelector:selector];
 		[invocation setArgument:&amp;value atIndex:2];
 		[invocation invoke];
-		
-	} else {
+	}
+	
+	// Request this request's own download progress delegate
+	if (downloadProgressDelegate) {
 		[ASIHTTPRequest setProgress:0 forProgressIndicator:downloadProgressDelegate];
 	}
 	[progressLock unlock];
@@ -621,47 +847,38 @@ static NSError *ASIUnableToCreateRequestError;
 	// We won't update download progress until we've examined the headers, since we might need to authenticate
 	if (responseHeaders) {
 		
-		unsigned long long bytesReadSoFar = totalBytesRead;
-		
-		if (bytesReadSoFar &gt; lastBytesRead) {
-			[self setLastActivityTime:[NSDate date]];
-		}
-		
-		if (downloadProgressDelegate) {
+		unsigned long long bytesReadSoFar = totalBytesRead+partialDownloadSize;
+
+		// We're using a progress queue or compatible controller to handle progress
+		SEL selector = @selector(incrementDownloadProgressBy:);
+		if ([queue respondsToSelector:@selector(incrementDownloadProgressBy:)]) {
 			
+			NSAutoreleasePool *thePool = [[NSAutoreleasePool alloc] init];
 			
-			// We're using a progress queue or compatible controller to handle progress
-			if ([downloadProgressDelegate respondsToSelector:@selector(incrementDownloadProgressBy:)]) {
-				
-				NSAutoreleasePool *thePool = [[NSAutoreleasePool alloc] init];
-				
-				unsigned long long value = 0;
-				if (showAccurateProgress) {
-					value = bytesReadSoFar-lastBytesRead;
-				} else {
-					value = 1;
-					updatedProgress = YES;
-				}
-				
-				
-				
-				SEL selector = @selector(incrementDownloadProgressBy:);
-				NSMethodSignature *signature = [[downloadProgressDelegate class] instanceMethodSignatureForSelector:selector];
-				NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
-				[invocation setTarget:downloadProgressDelegate];
-				[invocation setSelector:selector];
-				[invocation setArgument:&amp;value atIndex:2];
-				[invocation invoke];
-				
-				[thePool release];
-				
-				// We aren't using a queue, we should just set progress of the indicator to 0
-			} else if (contentLength &gt; 0)  {
-				[ASIHTTPRequest setProgress:(double)(1.0*bytesReadSoFar/contentLength) forProgressIndicator:downloadProgressDelegate];
+			unsigned long long value = 0;
+			if ([self showAccurateProgress]) {
+				value = bytesReadSoFar-[self lastBytesRead];
+			} else {
+				value = 1;
+				[self setUpdatedProgress:YES];
 			}
+			
+			
+			NSMethodSignature *signature = [[queue class] instanceMethodSignatureForSelector:selector];
+			NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
+			[invocation setTarget:queue];
+			[invocation setSelector:selector];
+			[invocation setArgument:&amp;value atIndex:2];
+			[invocation invoke];
+			
+			[thePool release];
+		}
+			
+		if (downloadProgressDelegate &amp;&amp; contentLength &gt; 0)  {
+			[ASIHTTPRequest setProgress:(double)(1.0*bytesReadSoFar/(contentLength+partialDownloadSize)) forProgressIndicator:downloadProgressDelegate];
 		}
 		
-		lastBytesRead = bytesReadSoFar;
+		[self setLastBytesRead:bytesReadSoFar];
 	}
 	
 }
@@ -670,18 +887,20 @@ static NSError *ASIUnableToCreateRequestError;
 {
 	
 	// We're using a progress queue or compatible controller to handle progress
-	if ([uploadProgressDelegate respondsToSelector:@selector(decrementUploadProgressBy:)]) {
+	SEL selector = @selector(decrementUploadProgressBy:);
+	if ([queue respondsToSelector:selector]) {
 		unsigned long long value = 0-lastBytesSent;
-		SEL selector = @selector(decrementUploadProgressBy:);
-		NSMethodSignature *signature = [[uploadProgressDelegate class] instanceMethodSignatureForSelector:selector];
+		
+		NSMethodSignature *signature = [[queue class] instanceMethodSignatureForSelector:selector];
 		NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
-		[invocation setTarget:uploadProgressDelegate];
+		[invocation setTarget:queue];
 		[invocation setSelector:selector];
 		[invocation setArgument:&amp;value atIndex:2];
 		[invocation invoke];
 		
-		// We aren't using a queue, we should just set progress of the indicator to 0
-	} else {
+	}
+	
+	if (uploadProgressDelegate) {
 		[ASIHTTPRequest setProgress:0 forProgressIndicator:uploadProgressDelegate];
 	}
 }
@@ -714,7 +933,7 @@ static NSError *ASIUnableToCreateRequestError;
 		[invocation setSelector:selector];
 		[invocation setArgument:&amp;progress atIndex:2];
 		
-		// If we're running in the main thread, update the progress straight away. Otherwise, it's not that urgent
+
 		[invocation performSelectorOnMainThread:@selector(invokeWithTarget:) withObject:indicator waitUntilDone:[NSThread isMainThread]];
 		
 	}
@@ -724,44 +943,60 @@ static NSError *ASIUnableToCreateRequestError;
 
 #pragma mark handling request complete / failure
 
-// Subclasses can override this method to process the result in the same thread
-// If not overidden, it will call the didFinishSelector on the delegate, if one has been setup
+// Subclasses might override this method to process the result in the same thread
+// If you do this, don't forget to call [super requestFinished] to let the queue / delegate know we're done
 - (void)requestFinished
 {
-	if (didFinishSelector &amp;&amp; ![self isCancelled] &amp;&amp; [delegate respondsToSelector:didFinishSelector]) {
+	if ([self error] || [self mainRequest]) {
+		return;
+	}
+	// Let the queue know we are done
+	if ([queue respondsToSelector:@selector(requestDidFinish:)]) {
+		[queue performSelectorOnMainThread:@selector(requestDidFinish:) withObject:self waitUntilDone:[NSThread isMainThread]];		
+	}
+	
+	// Let the delegate know we are done
+	if (didFinishSelector &amp;&amp; [delegate respondsToSelector:didFinishSelector]) {
 		[delegate performSelectorOnMainThread:didFinishSelector withObject:self waitUntilDone:[NSThread isMainThread]];		
 	}
 }
 
-
-
-// Subclasses can override this method to perform error handling in the same thread
-// If not overidden, it will call the didFailSelector on the delegate (by default requestFailed:)`
+// Subclasses might override this method to perform error handling in the same thread
+// If you do this, don't forget to call [super failWithError:] to let the queue / delegate know we're done
 - (void)failWithError:(NSError *)theError
 {
-	complete = YES;
-	if (!error) {
+	[self setComplete:YES];
+	
+	if ([self isCancelled] || [self error]) {
+		return;
+	}
+	
+	// If this is a HEAD request created by an ASINetworkQueue or compatible queue delegate, make the main request fail
+	if ([self mainRequest]) {
+		ASIHTTPRequest *mRequest = [self mainRequest];
+		[mRequest setError:theError];
+
+		// Let the queue know something went wrong
+		if ([queue respondsToSelector:@selector(requestDidFail:)]) {
+			[queue performSelectorOnMainThread:@selector(requestDidFail:) withObject:mRequest waitUntilDone:[NSThread isMainThread]];		
+		}
+	
+	} else {
+		[self setError:theError];
 		
-		// If this is a HEAD request created by an ASINetworkQueue, make the main request fail
-		if ([self mainRequest]) {
-			ASIHTTPRequest *mRequest = [self mainRequest];
-			[mRequest setError:theError];
-			if ([mRequest didFailSelector] &amp;&amp; ![self isCancelled] &amp;&amp; [[mRequest delegate] respondsToSelector:[mRequest didFailSelector]]) {
-				[[mRequest delegate] performSelectorOnMainThread:[mRequest didFailSelector] withObject:mRequest waitUntilDone:[NSThread isMainThread]];	
-			}
+		// Let the queue know something went wrong
+		if ([queue respondsToSelector:@selector(requestDidFail:)]) {
+			[queue performSelectorOnMainThread:@selector(requestDidFail:) withObject:self waitUntilDone:[NSThread isMainThread]];		
+		}
 		
-		} else {
-			[self setError:theError];
-			if (didFailSelector &amp;&amp; ![self isCancelled] &amp;&amp; [delegate respondsToSelector:didFailSelector]) {
-				[delegate performSelectorOnMainThread:didFailSelector withObject:self waitUntilDone:[NSThread isMainThread]];	
-			}
+		// Let the delegate know something went wrong
+		if (didFailSelector &amp;&amp; [delegate respondsToSelector:didFailSelector]) {
+			[delegate performSelectorOnMainThread:didFailSelector withObject:self waitUntilDone:[NSThread isMainThread]];	
 		}
-
 	}
 }
 
-
-#pragma mark http authentication
+#pragma mark parsing HTTP response headers
 
 - (BOOL)readResponseHeadersReturningAuthenticationFailure
 {
@@ -775,7 +1010,7 @@ static NSError *ASIUnableToCreateRequestError;
 		[self setResponseStatusCode:CFHTTPMessageGetResponseStatusCode(headers)];
 		
 		// Is the server response a challenge for credentials?
-		isAuthenticationChallenge = (responseStatusCode == 401);
+		isAuthenticationChallenge = ([self responseStatusCode] == 401);
 		
 		// We won't reset the download progress delegate if we got an authentication challenge
 		if (!isAuthenticationChallenge) {
@@ -783,12 +1018,12 @@ static NSError *ASIUnableToCreateRequestError;
 			// See if we got a Content-length header
 			NSString *cLength = [responseHeaders valueForKey:@&quot;Content-Length&quot;];
 			if (cLength) {
-				contentLength = CFStringGetIntValue((CFStringRef)cLength);
-				if (mainRequest) {
-					[mainRequest setContentLength:contentLength];
+				[self setContentLength:CFStringGetIntValue((CFStringRef)cLength)];
+				if ([self mainRequest]) {
+					[[self mainRequest] setContentLength:contentLength];
 				}
-				if (downloadProgressDelegate &amp;&amp; showAccurateProgress &amp;&amp; shouldResetProgressIndicators) {
-					[self resetDownloadProgress:contentLength];
+				if ([self showAccurateProgress] &amp;&amp; [self shouldResetProgressIndicators]) {
+					[self resetDownloadProgress:[self contentLength]+[self partialDownloadSize]];
 				}
 			}
 			
@@ -818,21 +1053,36 @@ static NSError *ASIUnableToCreateRequestError;
 			[self setResponseEncoding:encoding];
 			
 			// Handle cookies
-			NSArray *cookies = [NSHTTPCookie cookiesWithResponseHeaderFields:responseHeaders forURL:url];
-			[self setResponseCookies:cookies];
+			NSArray *newCookies = [NSHTTPCookie cookiesWithResponseHeaderFields:responseHeaders forURL:url];
+			[self setResponseCookies:newCookies];
 			
-			if (useCookiePersistance) {
+			if ([self useCookiePersistance]) {
 				
 				// Store cookies in global persistent store
-				[[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookies:cookies forURL:url mainDocumentURL:nil];
+				[[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookies:newCookies forURL:url mainDocumentURL:nil];
 				
 				// We also keep any cookies in the sessionCookies array, so that we have a reference to them if we need to remove them later
-				if (!sessionCookies) {
-					[ASIHTTPRequest setSessionCookies:[[[NSMutableArray alloc] init] autorelease]];
-					NSHTTPCookie *cookie;
-					for (cookie in cookies) {
-						[[ASIHTTPRequest sessionCookies] addObject:cookie];
+				NSHTTPCookie *cookie;
+				for (cookie in newCookies) {
+					[ASIHTTPRequest addSessionCookie:cookie];
+				}
+			}
+			// Do we need to redirect?
+			if ([self shouldRedirect] &amp;&amp; [responseHeaders valueForKey:@&quot;Location&quot;]) {
+				if ([self responseStatusCode] &gt; 300 &amp;&amp; [self responseStatusCode] &lt; 308 &amp;&amp; [self responseStatusCode] != 304) {
+					if ([self responseStatusCode] == 303) {
+						[self setRequestMethod:@&quot;GET&quot;];
+						[self setPostBody:nil];
+						[self setPostLength:0];
+						[self setRequestHeaders:nil];
 					}
+					[self setURL:[[NSURL URLWithString:[responseHeaders valueForKey:@&quot;Location&quot;] relativeToURL:[self url]] absoluteURL]];
+					[self setNeedsRedirect:YES];
+					
+					// Clear the request cookies
+					// This means manually added cookies will not be added to the redirect request - only those stored in the global persistent store
+					// But, this is probably the safest option - we might be redirecting to a different domain
+					[self setRequestCookies:[NSMutableArray array]];
 				}
 			}
 			
@@ -843,6 +1093,7 @@ static NSError *ASIUnableToCreateRequestError;
 	return isAuthenticationChallenge;
 }
 
+#pragma mark http authentication
 
 - (void)saveCredentialsToKeychain:(NSMutableDictionary *)newCredentials
 {
@@ -857,8 +1108,8 @@ static NSError *ASIUnableToCreateRequestError;
 
 - (BOOL)applyCredentials:(NSMutableDictionary *)newCredentials
 {
-	authenticationRetryCount++;
-
+	[self setAuthenticationRetryCount:[self authenticationRetryCount]+1];
+	
 	if (newCredentials &amp;&amp; requestAuthentication &amp;&amp; request) {
 		// Apply whatever credentials we've built up to the old request
 		if (CFHTTPMessageApplyCredentialDictionary(request, requestAuthentication, (CFMutableDictionaryRef)newCredentials, NULL)) {
@@ -976,10 +1227,17 @@ static NSError *ASIUnableToCreateRequestError;
 			
 			[self setRequestCredentials:nil];
 			
-			ignoreError = YES;	
 			[self setLastActivityTime:nil];
-			if ([delegate respondsToSelector:@selector(authorizationNeededForRequest:)]) {
-				[delegate performSelectorOnMainThread:@selector(authorizationNeededForRequest:) withObject:self waitUntilDone:[NSThread isMainThread]];
+			
+			// If we have a delegate, we'll see if it can handle authorizationNeededForRequest.
+			// Otherwise, we'll try the queue (if this request is part of one) and it will pass the message on to its own delegate
+			id authorizationDelegate = [self delegate];
+			if (!authorizationDelegate) {
+				authorizationDelegate = [self queue];
+			}
+			
+			if ([authorizationDelegate respondsToSelector:@selector(authorizationNeededForRequest:)]) {
+				[authorizationDelegate performSelectorOnMainThread:@selector(authorizationNeededForRequest:) withObject:self waitUntilDone:[NSThread isMainThread]];
 				[authenticationLock lockWhenCondition:2];
 				[authenticationLock unlock];
 				
@@ -995,7 +1253,7 @@ static NSError *ASIUnableToCreateRequestError;
 	[self cancelLoad];
 	
 	if (requestCredentials) {
-		NSLog(@&quot;%hi&quot;,authenticationRetryCount);
+
 		if (((authenticationMethod != (NSString *)kCFHTTPAuthenticationSchemeNTLM) || authenticationRetryCount &lt; 2) &amp;&amp; [self applyCredentials:requestCredentials]) {
 			[self startRequest];
 			
@@ -1007,7 +1265,7 @@ static NSError *ASIUnableToCreateRequestError;
 			[self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIInternalErrorWhileApplyingCredentialsType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@&quot;Failed to apply credentials to request&quot;,NSLocalizedDescriptionKey,nil]]];
 		}
 		
-		// Are a user name &amp; password needed?
+	// Are a user name &amp; password needed?
 	}  else if (CFHTTPAuthenticationRequiresUserNameAndPassword(requestAuthentication)) {
 		
 		NSMutableDictionary *newCredentials = [self findCredentials];
@@ -1024,9 +1282,15 @@ static NSError *ASIUnableToCreateRequestError;
 		}
 		
 		// We've got no credentials, let's ask the delegate to sort this out
-		ignoreError = YES;	
-		if ([delegate respondsToSelector:@selector(authorizationNeededForRequest:)]) {
-			[delegate performSelectorOnMainThread:@selector(authorizationNeededForRequest:) withObject:self waitUntilDone:[NSThread isMainThread]];
+		// If we have a delegate, we'll see if it can handle authorizationNeededForRequest.
+		// Otherwise, we'll try the queue (if this request is part of one) and it will pass the message on to its own delegate
+		id authorizationDelegate = [self delegate];
+		if (!authorizationDelegate) {
+			authorizationDelegate = [self queue];
+		}
+		
+		if ([authorizationDelegate respondsToSelector:@selector(authorizationNeededForRequest:)]) {
+			[authorizationDelegate performSelectorOnMainThread:@selector(authorizationNeededForRequest:) withObject:self waitUntilDone:[NSThread isMainThread]];
 			[authenticationLock lockWhenCondition:2];
 			[authenticationLock unlock];
 			[self attemptToApplyCredentialsAndResume];
@@ -1068,12 +1332,15 @@ static NSError *ASIUnableToCreateRequestError;
 - (void)handleBytesAvailable
 {
 	
-	if (!responseHeaders) {
+	if (![self responseHeaders]) {
 		if ([self readResponseHeadersReturningAuthenticationFailure]) {
 			[self attemptToApplyCredentialsAndResume];
 			return;
 		}
 	}
+	if ([self needsRedirect]) {
+		return;
+	}
 	int bufferSize = 2048;
 	if (contentLength &gt; 262144) {
 		bufferSize = 65536;
@@ -1089,14 +1356,15 @@ static NSError *ASIUnableToCreateRequestError;
     if (bytesRead &lt; 0) {
         [self handleStreamError];
 		
-		// If zero bytes were read, wait for the EOF to come.
+	// If zero bytes were read, wait for the EOF to come.
     } else if (bytesRead) {
 		
-		totalBytesRead += bytesRead;
+		[self setTotalBytesRead:[self totalBytesRead]+bytesRead];
+		[self setLastActivityTime:[NSDate date]];
 		
 		// Are we downloading to a file?
-		if (downloadDestinationPath) {
-			if (!outputStream) {
+		if ([self downloadDestinationPath]) {
+			if (![self fileDownloadOutputStream]) {
 				BOOL append = NO;
 				if (![self temporaryFileDownloadPath]) {
 					[self setTemporaryFileDownloadPath:[NSTemporaryDirectory() stringByAppendingPathComponent:[[NSProcessInfo processInfo] globallyUniqueString]]];
@@ -1104,12 +1372,12 @@ static NSError *ASIUnableToCreateRequestError;
 					append = YES;
 				}
 				
-				outputStream = [[NSOutputStream alloc] initToFileAtPath:temporaryFileDownloadPath append:append];
-				[outputStream open];
+				[self setFileDownloadOutputStream:[[[NSOutputStream alloc] initToFileAtPath:temporaryFileDownloadPath append:append] autorelease]];
+				[fileDownloadOutputStream open];
 			}
-			[outputStream write:buffer maxLength:bytesRead];
+			[fileDownloadOutputStream write:buffer maxLength:bytesRead];
 			
-			//Otherwise, let's add the data to our in-memory store
+		//Otherwise, let's add the data to our in-memory store
 		} else {
 			[rawResponseData appendBytes:buffer length:bytesRead];
 		}
@@ -1118,17 +1386,22 @@ static NSError *ASIUnableToCreateRequestError;
 
 - (void)handleStreamComplete
 {
-	//Try to read the headers (if this is a HEAD request handleBytesAvailable available may not be called)
-	if (!responseHeaders) {
+	//Try to read the headers (if this is a HEAD request handleBytesAvailable may not be called)
+	if (![self responseHeaders]) {
 		if ([self readResponseHeadersReturningAuthenticationFailure]) {
 			[self attemptToApplyCredentialsAndResume];
 			return;
 		}
 	}
+	if ([self needsRedirect]) {
+		return;
+	}
 	[progressLock lock];	
-	complete = YES;
+	
+	[self setComplete:YES];
 	[self updateProgressIndicators];
 	
+	[[self cancelledLock] lock];
     if (readStream) {
         CFReadStreamClose(readStream);
         CFReadStreamSetClient(readStream, kCFStreamEventNone, NULL, NULL);
@@ -1137,11 +1410,18 @@ static NSError *ASIUnableToCreateRequestError;
         readStream = NULL;
     }
 	
+	[[self postBodyReadStream] close];
+	
 	NSError *fileError = nil;
 	
+	// Delete up the request body temporary file, if it exists
+	if (didCreateTemporaryPostDataFile) {
+		[self removePostDataFile];
+	}
+	
 	// Close the output stream as we're done writing to the file
 	if (temporaryFileDownloadPath) {
-		[outputStream close];
+		[fileDownloadOutputStream close];
 		
 		// Decompress the file (if necessary) directly to the destination path
 		if ([self isResponseCompressed]) {
@@ -1150,12 +1430,7 @@ static NSError *ASIUnableToCreateRequestError;
 				fileError = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASIFileManagementError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@&quot;Decompression of %@ failed with code %hi&quot;,temporaryFileDownloadPath,decompressionStatus],NSLocalizedDescriptionKey,nil]];
 			}
 				
-			//Remove the temporary file
-			NSError *removeError = nil;
-			[[NSFileManager defaultManager] removeItemAtPath:temporaryFileDownloadPath error:&amp;removeError];
-			if (removeError) {
-				fileError = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASIFileManagementError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@&quot;Failed to delete file at %@ with error: %@&quot;,temporaryFileDownloadPath,removeError],NSLocalizedDescriptionKey,removeError,NSUnderlyingErrorKey,nil]];
-			}			
+			[self removeTemporaryDownloadFile];
 		} else {
 					
 			//Remove any file at the destination path
@@ -1176,7 +1451,9 @@ static NSError *ASIUnableToCreateRequestError;
 			}
 		}
 	}
+	[[self cancelledLock] unlock];
 	[progressLock unlock];
+	
 	if (fileError) {
 		[self failWithError:fileError];
 	} else {
@@ -1190,11 +1467,23 @@ static NSError *ASIUnableToCreateRequestError;
 	NSError *underlyingError = [(NSError *)CFReadStreamCopyError(readStream) autorelease];
 	
 	[self cancelLoad];
-	complete = YES;
+	[self setComplete:YES];
 	
-	if (!error) { // We may already have handled this error
+	if (![self error]) { // We may already have handled this error
+		
 		
-		[self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIConnectionFailureErrorType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@&quot;A connection failure occurred&quot;,NSLocalizedDescriptionKey,underlyingError,NSUnderlyingErrorKey,nil]]];
+		NSString *reason = @&quot;A connection failure occurred&quot;;
+		
+		// We'll use a custom error message for SSL errors, but you should always check underlying error if you want more details
+		// For some reason SecureTransport.h doesn't seem to be available on iphone, so error codes hard-coded
+		// Also, iPhone seems to handle errors differently from Mac OS X - a self-signed certificate returns a different error code on each platform, so we'll just provide a general error
+		if ([[underlyingError domain] isEqualToString:NSOSStatusErrorDomain]) {
+			if ([underlyingError code] &lt;= -9800 &amp;&amp; [underlyingError code] &gt;= -9818) {
+				reason = [NSString stringWithFormat:@&quot;%@: SSL problem (possibily a bad/expired/self-signed certificate)&quot;,reason];
+			}
+		}
+		
+		[self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIConnectionFailureErrorType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:reason,NSLocalizedDescriptionKey,underlyingError,NSUnderlyingErrorKey,nil]]];
 	}
     [super cancel];
 }
@@ -1263,19 +1552,37 @@ static NSError *ASIUnableToCreateRequestError;
 
 + (NSMutableArray *)sessionCookies
 {
+	if (!sessionCookies) {
+		[ASIHTTPRequest setSessionCookies:[[[NSMutableArray alloc] init] autorelease]];
+	}
 	return sessionCookies;
 }
 
 + (void)setSessionCookies:(NSMutableArray *)newSessionCookies
 {
 	// Remove existing cookies from the persistent store
-	for (NSHTTPCookie *cookie in [ASIHTTPRequest sessionCookies]) {
+	for (NSHTTPCookie *cookie in sessionCookies) {
 		[[NSHTTPCookieStorage sharedHTTPCookieStorage] deleteCookie:cookie];
 	}
 	[sessionCookies release];
 	sessionCookies = [newSessionCookies retain];
 }
 
++ (void)addSessionCookie:(NSHTTPCookie *)newCookie
+{
+	NSHTTPCookie *cookie;
+	int i;
+	int max = [[ASIHTTPRequest sessionCookies] count];
+	for (i=0; i&lt;max; i++) {
+		cookie = [[ASIHTTPRequest sessionCookies] objectAtIndex:i];
+		if ([[cookie domain] isEqualToString:[newCookie domain]] &amp;&amp; [[cookie path] isEqualToString:[newCookie path]] &amp;&amp; [[cookie name] isEqualToString:[newCookie name]]) {
+			[[ASIHTTPRequest sessionCookies] removeObjectAtIndex:i];
+			break;
+		}
+	}
+	[[ASIHTTPRequest sessionCookies] addObject:newCookie];
+}
+
 // Dump all session data (authentication and cookies)
 + (void)clearSession
 {
@@ -1284,8 +1591,7 @@ static NSError *ASIUnableToCreateRequestError;
 	[ASIHTTPRequest setSessionCookies:nil];
 }
 
-
-#pragma mark gzip data handling
+#pragma mark gzip decompression
 
 //
 // Contributed by Shaun Harrison of Enormego, see: http://developers.enormego.com/view/asihttprequest_gzip
@@ -1338,24 +1644,29 @@ static NSError *ASIUnableToCreateRequestError;
 	}
 }
 
-
+// NOTE: To debug this method, turn off Data Formatters in Xcode or you'll crash on closeFile
 + (int)uncompressZippedDataFromFile:(NSString *)sourcePath toFile:(NSString *)destinationPath
 {
-	// Get a FILE struct for the source file
-	FILE *source = fdopen([[NSFileHandle fileHandleForReadingAtPath:sourcePath] fileDescriptor], &quot;r&quot;);
-	
 	// Create an empty file at the destination path
 	[[NSFileManager defaultManager] createFileAtPath:destinationPath contents:[NSData data] attributes:nil];
 	
+	// Get a FILE struct for the source file
+	NSFileHandle *inputFileHandle = [NSFileHandle fileHandleForReadingAtPath:sourcePath];
+	FILE *source = fdopen([inputFileHandle fileDescriptor], &quot;r&quot;);
+	
 	// Get a FILE struct for the destination path
-	FILE *dest = fdopen([[NSFileHandle fileHandleForWritingAtPath:destinationPath] fileDescriptor], &quot;w&quot;);
+	NSFileHandle *outputFileHandle = [NSFileHandle fileHandleForWritingAtPath:destinationPath];
+	FILE *dest = fdopen([outputFileHandle fileDescriptor], &quot;w&quot;);
+	
 	
 	// Uncompress data in source and save in destination
 	int status = [ASIHTTPRequest uncompressZippedDataFromSource:source toDestination:dest];
 	
 	// Close the files
-	fclose(source);
 	fclose(dest);
+	fclose(source);
+	[inputFileHandle closeFile];
+	[outputFileHandle closeFile];	
 	return status;
 }
 
@@ -1364,6 +1675,7 @@ static NSError *ASIUnableToCreateRequestError;
 //	http://www.zlib.net/zpipe.c
 //
 #define CHUNK 16384
+
 + (int)uncompressZippedDataFromSource:(FILE *)source toDestination:(FILE *)dest
 {
     int ret;
@@ -1421,13 +1733,188 @@ static NSError *ASIUnableToCreateRequestError;
     (void)inflateEnd(&amp;strm);
     return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
 }
+
+
+#pragma mark gzip compression
+
+// Based on this from Robbie Hanson: http://deusty.blogspot.com/2007/07/gzip-compressiondecompression.html
+
++ (NSData *)compressData:(NSData*)uncompressedData
+{
+	if ([uncompressedData length] == 0) return uncompressedData;
+	
+	z_stream strm;
+	
+	strm.zalloc = Z_NULL;
+	strm.zfree = Z_NULL;
+	strm.opaque = Z_NULL;
+	strm.total_out = 0;
+	strm.next_in=(Bytef *)[uncompressedData bytes];
+	strm.avail_in = [uncompressedData length];
+	
+	// Compresssion Levels:
+	//   Z_NO_COMPRESSION
+	//   Z_BEST_SPEED
+	//   Z_BEST_COMPRESSION
+	//   Z_DEFAULT_COMPRESSION
+	
+	if (deflateInit2(&amp;strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, (15+16), 8, Z_DEFAULT_STRATEGY) != Z_OK) return nil;
+	
+	NSMutableData *compressed = [NSMutableData dataWithLength:16384];  // 16K chunks for expansion
+	
+	do {
+		
+		if (strm.total_out &gt;= [compressed length])
+			[compressed increaseLengthBy: 16384];
+		
+		strm.next_out = [compressed mutableBytes] + strm.total_out;
+		strm.avail_out = [compressed length] - strm.total_out;
+		
+		deflate(&amp;strm, Z_FINISH);  
+		
+	} while (strm.avail_out == 0);
+	
+	deflateEnd(&amp;strm);
+	
+	[compressed setLength: strm.total_out];
+	return [NSData dataWithData:compressed];
+}
+
+// NOTE: To debug this method, turn off Data Formatters in Xcode or you'll crash on closeFile
++ (int)compressDataFromFile:(NSString *)sourcePath toFile:(NSString *)destinationPath
+{
+	// Create an empty file at the destination path
+	[[NSFileManager defaultManager] createFileAtPath:destinationPath contents:[NSData data] attributes:nil];
+	
+	// Get a FILE struct for the source file
+	NSFileHandle *inputFileHandle = [NSFileHandle fileHandleForReadingAtPath:sourcePath];
+	FILE *source = fdopen([inputFileHandle fileDescriptor], &quot;r&quot;);
+
+	// Get a FILE struct for the destination path
+	NSFileHandle *outputFileHandle = [NSFileHandle fileHandleForWritingAtPath:destinationPath];
+	FILE *dest = fdopen([outputFileHandle fileDescriptor], &quot;w&quot;);
+
+	// compress data in source and save in destination
+	int status = [ASIHTTPRequest compressDataFromSource:source toDestination:dest];
+
+	// Close the files
+	fclose(dest);
+	fclose(source);
+	
+	// We have to close both of these explictly because CFReadStreamCreateForStreamedHTTPRequest() seems to go bonkers otherwise
+	[inputFileHandle closeFile];
+	[outputFileHandle closeFile];
+
+	return status;
+}
+
+//
+// Also from the zlib sample code  at http://www.zlib.net/zpipe.c
+// 
++ (int)compressDataFromSource:(FILE *)source toDestination:(FILE *)dest
+{
+    int ret, flush;
+    unsigned have;
+    z_stream strm;
+    unsigned char in[CHUNK];
+    unsigned char out[CHUNK];
+	
+    /* allocate deflate state */
+    strm.zalloc = Z_NULL;
+    strm.zfree = Z_NULL;
+    strm.opaque = Z_NULL;
+    ret = deflateInit2(&amp;strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, (15+16), 8, Z_DEFAULT_STRATEGY);
+    if (ret != Z_OK)
+        return ret;
+	
+    /* compress until end of file */
+    do {
+        strm.avail_in = fread(in, 1, CHUNK, source);
+        if (ferror(source)) {
+            (void)deflateEnd(&amp;strm);
+            return Z_ERRNO;
+        }
+        flush = feof(source) ? Z_FINISH : Z_NO_FLUSH;
+        strm.next_in = in;
+		
+        /* run deflate() on input until output buffer not full, finish
+		 compression if all of source has been read in */
+        do {
+            strm.avail_out = CHUNK;
+            strm.next_out = out;
+            ret = deflate(&amp;strm, flush);    /* no bad return value */
+            assert(ret != Z_STREAM_ERROR);  /* state not clobbered */
+            have = CHUNK - strm.avail_out;
+            if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
+                (void)deflateEnd(&amp;strm);
+                return Z_ERRNO;
+            }
+        } while (strm.avail_out == 0);
+        assert(strm.avail_in == 0);     /* all input will be used */
+		
+        /* done when last data in file processed */
+    } while (flush != Z_FINISH);
+    assert(ret == Z_STREAM_END);        /* stream will be complete */
+	
+    /* clean up and return */
+    (void)deflateEnd(&amp;strm);
+    return Z_OK;
+}
+
+#pragma mark get user agent
+
++ (NSString *)defaultUserAgentString
+{
+	NSBundle *bundle = [NSBundle mainBundle];
 	
+	// Attempt to find a name for this application
+	NSString *appName = [bundle objectForInfoDictionaryKey:@&quot;CFBundleDisplayName&quot;];
+	if (!appName) {
+		appName = [bundle objectForInfoDictionaryKey:@&quot;CFBundleName&quot;];	
+	}
+	// If we couldn't find one, we'll give up (and ASIHTTPRequest will use the standard CFNetwork user agent)
+	if (!appName) {
+		return nil;
+	}
+	NSString *appVersion = [bundle objectForInfoDictionaryKey:@&quot;CFBundleVersion&quot;];
+	NSString *deviceName;;
+	NSString *OSName;
+	NSString *OSVersion;
+	
+	NSString *locale = [[NSLocale currentLocale] localeIdentifier];
+	
+#if TARGET_OS_IPHONE
+	UIDevice *device = [UIDevice currentDevice];
+	deviceName = [device model];
+	OSName = [device systemName];
+	OSVersion = [device systemVersion];
+	
+#else
+	deviceName = @&quot;Macintosh&quot;;
+	OSName = @&quot;Mac OS X&quot;;
+	
+	// From http://www.cocoadev.com/index.pl?DeterminingOSVersion
+	// We won't bother to check for systems prior to 10.4, since ASIHTTPRequest only works on 10.5+
+    OSErr err;
+    SInt32 versionMajor, versionMinor, versionBugFix;
+	if ((err = Gestalt(gestaltSystemVersionMajor, &amp;versionMajor)) != noErr) return nil;
+	if ((err = Gestalt(gestaltSystemVersionMinor, &amp;versionMinor)) != noErr) return nil;
+	if ((err = Gestalt(gestaltSystemVersionBugFix, &amp;versionBugFix)) != noErr) return nil;
+	OSVersion = [NSString stringWithFormat:@&quot;%u.%u.%u&quot;, versionMajor, versionMinor, versionBugFix];
+	
+#endif
+	// Takes the form &quot;My Application 1.0 (Macintosh; Mac OS X 10.5.7; en_GB)&quot;
+	return [NSString stringWithFormat:@&quot;%@ %@ (%@; %@ %@; %@)&quot;, appName, appVersion, deviceName, OSName, OSVersion, locale];
+}
+
+
 
 @synthesize username;
 @synthesize password;
 @synthesize domain;
 @synthesize url;
 @synthesize delegate;
+@synthesize queue;
 @synthesize uploadProgressDelegate;
 @synthesize downloadProgressDelegate;
 @synthesize useKeychainPersistance;
@@ -1451,15 +1938,39 @@ static NSError *ASIUnableToCreateRequestError;
 @synthesize timeOutSeconds;
 @synthesize requestMethod;
 @synthesize postBody;
+@synthesize compressedPostBody;
 @synthesize contentLength;
+@synthesize partialDownloadSize;
 @synthesize postLength;
 @synthesize shouldResetProgressIndicators;
 @synthesize mainRequest;
 @synthesize totalBytesRead;
+@synthesize totalBytesSent;
 @synthesize showAccurateProgress;
 @synthesize uploadBufferSize;
 @synthesize defaultResponseEncoding;
 @synthesize responseEncoding;
 @synthesize allowCompressedResponse;
 @synthesize allowResumeForFileDownloads;
+@synthesize userInfo;
+@synthesize postBodyFilePath;
+@synthesize compressedPostBodyFilePath;
+@synthesize postBodyWriteStream;
+@synthesize postBodyReadStream;
+@synthesize shouldStreamPostDataFromDisk;
+@synthesize didCreateTemporaryPostDataFile;
+@synthesize useHTTPVersionOne;
+@synthesize lastBytesRead;
+@synthesize lastBytesSent;
+@synthesize cancelledLock;
+@synthesize haveBuiltPostBody;
+@synthesize fileDownloadOutputStream;
+@synthesize authenticationRetryCount;
+@synthesize updatedProgress;
+@synthesize shouldRedirect;
+@synthesize validatesSecureCertificate;
+@synthesize needsRedirect;
+@synthesize redirectCount;
+@synthesize shouldCompressRequestBody;
+@synthesize authenticationLock;
 @end</diff>
      <filename>Vendor/ASIHTTPRequest/ASIHTTPRequest.m</filename>
    </modified>
    <modified>
      <diff>@@ -3,13 +3,14 @@
 //  asi-http-request
 //
 //  Created by Ben Copsey on 07/11/2008.
-//  Copyright 2008 All-Seeing Interactive. All rights reserved.
+//  Copyright 2008-2009 All-Seeing Interactive. All rights reserved.
 //
 
+#import &lt;Foundation/Foundation.h&gt;
 
 @interface ASINetworkQueue : NSOperationQueue {
 	
-	// Delegate will get didFail + didFinish messages (if set), as well as authorizationNeededForRequest messages
+	// Delegate will get didFail + didFinish messages (if set)
 	id delegate;
 
 	// Will be called when a request completes with the request as the argument
@@ -56,6 +57,9 @@
 	
 }
 
+// Convenience constructor
++ (id)queue;
+
 // Used internally to manage HEAD requests when showAccurateProgress is YES, do not use!
 - (void)addHEADOperation:(NSOperation *)operation;
 
@@ -83,6 +87,14 @@
 // This method will start the queue
 - (void)go;
 
+// Used on iPhone platform to show / hide the network activity indicator (in the status bar)
+// On mac, you could subclass to do something else
+- (void)updateNetworkActivityIndicator;
+
+// Returns YES if the queue is in progress
+- (BOOL)isNetworkActive;
+
+
 @property (assign,setter=setUploadProgressDelegate:) id uploadProgressDelegate;
 @property (assign,setter=setDownloadProgressDelegate:) id downloadProgressDelegate;
 
@@ -92,4 +104,5 @@
 @property (assign) BOOL shouldCancelAllRequestsOnFailure;
 @property (assign) id delegate;
 @property (assign) BOOL showAccurateProgress;
+@property (assign, readonly) int requestsCount;
 @end</diff>
      <filename>Vendor/ASIHTTPRequest/ASINetworkQueue.h</filename>
    </modified>
    <modified>
      <diff>@@ -3,56 +3,74 @@
 //  asi-http-request
 //
 //  Created by Ben Copsey on 07/11/2008.
-//  Copyright 2008 All-Seeing Interactive. All rights reserved.
+//  Copyright 2008-2009 All-Seeing Interactive. All rights reserved.
 //
 
 #import &quot;ASINetworkQueue.h&quot;
 #import &quot;ASIHTTPRequest.h&quot;
 
+// Private stuff
+@interface ASINetworkQueue ()
+	@property (assign) int requestsCount;
+	@property (assign) unsigned long long uploadProgressBytes;
+	@property (assign) unsigned long long uploadProgressTotalBytes;
+	@property (assign) unsigned long long downloadProgressBytes;
+	@property (assign) unsigned long long downloadProgressTotalBytes;
+@end
 
 @implementation ASINetworkQueue
 
 - (id)init
 {
 	self = [super init];
-	
-	delegate = NULL;
-	requestDidFinishSelector = NULL;
-	requestDidFailSelector = NULL;
-	queueDidFinishSelector = NULL;
-	shouldCancelAllRequestsOnFailure = YES;
-	
-	uploadProgressDelegate = nil;
-	uploadProgressBytes = 0;
-	uploadProgressTotalBytes = 0;
-	
-	downloadProgressDelegate = nil;
-	downloadProgressBytes = 0;
-	downloadProgressTotalBytes = 0;
-	
-	requestsCount = 0;
-	
-	showAccurateProgress = NO;
-	
+	[self setShouldCancelAllRequestsOnFailure:YES];
 	[self setMaxConcurrentOperationCount:4];
 	[self setSuspended:YES];
 	
 	return self;
 }
 
++ (id)queue
+{
+	return [[[self alloc] init] autorelease];
+}
+
 - (void)dealloc
 {
+	//We need to clear the delegate on any requests that haven't got around to cleaning up yet, as otherwise they'll try to let us know if something goes wrong, and we'll be long gone by then
+	for (ASIHTTPRequest *request in [self operations]) {
+		[request setDelegate:nil];
+	}
 	[super dealloc];
 }
 
+- (BOOL)isNetworkActive
+{
+	return ([self requestsCount] &gt; 0 &amp;&amp; ![self isSuspended]);
+}
+
+- (void)updateNetworkActivityIndicator
+{
+#if TARGET_OS_IPHONE
+	[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:[self isNetworkActive]];
+#endif
+}
+
+- (void)setSuspended:(BOOL)suspend
+{
+	[super setSuspended:suspend];
+	[self updateNetworkActivityIndicator];
+}
+
+
 - (void)go
 {
-	if (!showAccurateProgress) {
-		if (downloadProgressDelegate) {
-			[self incrementDownloadSizeBy:requestsCount];
+	if (![self showAccurateProgress]) {
+		if ([self downloadProgressDelegate]) {
+			[self incrementDownloadSizeBy:[self requestsCount]];
 		}
-		if (uploadProgressDelegate) {
-			[self incrementUploadSizeBy:requestsCount];
+		if ([self uploadProgressDelegate]) {
+			[self incrementUploadSizeBy:[self requestsCount]];
 		}		
 	}
 	[self setSuspended:NO];
@@ -60,12 +78,13 @@
 
 - (void)cancelAllOperations
 {
-	requestsCount = 0;
-	uploadProgressBytes = 0;
-	uploadProgressTotalBytes = 0;
-	downloadProgressBytes = 0;
-	downloadProgressTotalBytes = 0;
+	[self setRequestsCount:0];
+	[self setUploadProgressBytes:0];
+	[self setUploadProgressTotalBytes:0];
+	[self setDownloadProgressBytes:0];
+	[self setDownloadProgressTotalBytes:0];
 	[super cancelAllOperations];
+	[self updateNetworkActivityIndicator];
 }
 
 - (void)setUploadProgressDelegate:(id)newDelegate
@@ -74,13 +93,13 @@
 	
 	// If the uploadProgressDelegate is an NSProgressIndicator, we set it's MaxValue to 1.0 so we can treat it similarly to UIProgressViews
 	SEL selector = @selector(setMaxValue:);
-	if ([uploadProgressDelegate respondsToSelector:selector]) {
+	if ([[self uploadProgressDelegate] respondsToSelector:selector]) {
 		double max = 1.0;
-		NSMethodSignature *signature = [[uploadProgressDelegate class] instanceMethodSignatureForSelector:selector];
+		NSMethodSignature *signature = [[[self uploadProgressDelegate] class] instanceMethodSignatureForSelector:selector];
 		NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
 		[invocation setSelector:selector];
 		[invocation setArgument:&amp;max atIndex:2];
-		[invocation invokeWithTarget:uploadProgressDelegate];
+		[invocation invokeWithTarget:[self uploadProgressDelegate]];
 	}	
 }
 
@@ -91,13 +110,13 @@
 	
 	// If the downloadProgressDelegate is an NSProgressIndicator, we set it's MaxValue to 1.0 so we can treat it similarly to UIProgressViews
 	SEL selector = @selector(setMaxValue:);
-	if ([downloadProgressDelegate respondsToSelector:selector]) {
+	if ([[self downloadProgressDelegate] respondsToSelector:selector]) {
 		double max = 1.0;
-		NSMethodSignature *signature = [[downloadProgressDelegate class] instanceMethodSignatureForSelector:selector];
+		NSMethodSignature *signature = [[[self downloadProgressDelegate] class] instanceMethodSignatureForSelector:selector];
 		NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
 		[invocation setSelector:@selector(setMaxValue:)];
 		[invocation setArgument:&amp;max atIndex:2];
-		[invocation invokeWithTarget:downloadProgressDelegate];
+		[invocation invokeWithTarget:[self downloadProgressDelegate]];
 	}	
 }
 
@@ -109,17 +128,9 @@
 		[request setRequestMethod:@&quot;HEAD&quot;];
 		[request setQueuePriority:10];
 		[request setShowAccurateProgress:YES];
-		if (uploadProgressDelegate) {
-			[request setUploadProgressDelegate:self];
-		} else {
-			[request setUploadProgressDelegate:NULL];
-		}
-		if (downloadProgressDelegate) {
-			[request setDownloadProgressDelegate:self];
-		} else {
-			[request setDownloadProgressDelegate:NULL];	
-		}
-		[request setDelegate:self];
+		[request setQueue:self];
+		
+		// Important - we are calling NSOperation's add method - we don't want to add this as a normal request!
 		[super addOperation:request];
 	}
 }
@@ -127,80 +138,69 @@
 // Only add ASIHTTPRequests to this queue!!
 - (void)addOperation:(NSOperation *)operation
 {
-	if ([operation isKindOfClass:[ASIHTTPRequest class]]) {
-		
-		requestsCount++;
+	if (![operation isKindOfClass:[ASIHTTPRequest class]]) {
+		[NSException raise:@&quot;AttemptToAddInvalidRequest&quot; format:@&quot;Attempted to add an object that was not an ASIHTTPRequest to an ASINetworkQueue&quot;];
+	}
 		
-		ASIHTTPRequest *request = (ASIHTTPRequest *)operation;
+	[self setRequestsCount:[self requestsCount]+1];
+	
+	ASIHTTPRequest *request = (ASIHTTPRequest *)operation;
+	
+	if ([self showAccurateProgress]) {
 		
-		if (showAccurateProgress) {
+		// If this is a GET request and we want accurate progress, perform a HEAD request first to get the content-length
+		if ([[request requestMethod] isEqualToString:@&quot;GET&quot;]) {
+			ASIHTTPRequest *HEADRequest = [[[ASIHTTPRequest alloc] initWithURL:[request url]] autorelease];
+			[HEADRequest setMainRequest:request];
+			[self addHEADOperation:HEADRequest];
 			
-			// If this is a GET request and we want accurate progress, perform a HEAD request first to get the content-length
-			if ([[request requestMethod] isEqualToString:@&quot;GET&quot;]) {
-				ASIHTTPRequest *HEADRequest = [[[ASIHTTPRequest alloc] initWithURL:[request url]] autorelease];
-				[HEADRequest setMainRequest:request];
-				
-				//If we're downloading to a file, and we already have a partial download to start from
-				if ([request allowResumeForFileDownloads] &amp;&amp; [request downloadDestinationPath] &amp;&amp; [request temporaryFileDownloadPath] &amp;&amp; [[NSFileManager defaultManager] fileExistsAtPath:[request temporaryFileDownloadPath]]) {
-					unsigned long long downloadedSoFar = [[[NSFileManager defaultManager] fileAttributesAtPath:[request temporaryFileDownloadPath] traverseLink:NO] fileSize];
-					[HEADRequest addRequestHeader:@&quot;Range&quot; value:[NSString stringWithFormat:@&quot;bytes=%llu-&quot;,downloadedSoFar]];
-				}
-				
-				[self addHEADOperation:HEADRequest];
-				
-				//Tell the request not to reset the progress indicator when it gets a content-length, as we will get the length from the HEAD request
-				[request setShouldResetProgressIndicators:NO];
-				[request addDependency:HEADRequest];
+			//Tell the request not to reset the progress indicator when it gets a content-length, as we will get the length from the HEAD request
+			[request setShouldResetProgressIndicators:NO];
 			
-			// If we want to track uploading for this request accurately, we need to add the size of the post content to the total
-			} else if (uploadProgressDelegate) {
-				[request buildPostBody];
-				uploadProgressTotalBytes += [request postLength];
-			}
-		}
-		[request setShowAccurateProgress:showAccurateProgress];
+			[request addDependency:HEADRequest];
 		
-		if (uploadProgressDelegate) {
-			
-			// For uploads requests, we always work out the total upload size before the queue starts, so we tell the request not to reset the progress indicator when starting each request
-			[request setShouldResetProgressIndicators:NO];
-			[request setUploadProgressDelegate:self];
-		} else {
-			[request setUploadProgressDelegate:NULL];
-		}
-		if (downloadProgressDelegate) {
-			[request setDownloadProgressDelegate:self];
-		} else {
-			[request setDownloadProgressDelegate:NULL];	
+		// If we want to track uploading for this request accurately, we need to add the size of the post content to the total
+		} else if (uploadProgressDelegate) {
+			[request buildPostBody];
+			[self setUploadProgressTotalBytes:[self uploadProgressTotalBytes]+[request postLength]];
 		}
-		[request setDelegate:self];
-		[request setDidFailSelector:@selector(requestDidFail:)];
-		[request setDidFinishSelector:@selector(requestDidFinish:)];
-		[super addOperation:request];
 	}
+	[request setShowAccurateProgress:[self showAccurateProgress]];
+
 	
+	[request setQueue:self];
+	[super addOperation:request];
+	[self updateNetworkActivityIndicator];
+
 }
 
 - (void)requestDidFail:(ASIHTTPRequest *)request
 {
-	requestsCount--;
-	if (requestDidFailSelector) {
-		[delegate performSelector:requestDidFailSelector withObject:request];
+	[self setRequestsCount:[self requestsCount]-1];
+	[self updateNetworkActivityIndicator];
+	if ([self requestDidFailSelector]) {
+		[[self delegate] performSelector:[self requestDidFailSelector] withObject:request];
 	}
-	if (shouldCancelAllRequestsOnFailure &amp;&amp; requestsCount &gt; 0) {
+	if ([self shouldCancelAllRequestsOnFailure] &amp;&amp; [self requestsCount] &gt; 0) {
 		[self cancelAllOperations];
 	}
+	if ([self requestsCount] == 0) {
+		if ([self queueDidFinishSelector]) {
+			[[self delegate] performSelector:[self queueDidFinishSelector] withObject:self];
+		}
+	}
 }
 
 - (void)requestDidFinish:(ASIHTTPRequest *)request
 {
-	requestsCount--;
-	if (requestDidFinishSelector) {
-		[delegate performSelector:requestDidFinishSelector withObject:request];
+	[self setRequestsCount:[self requestsCount]-1];
+	[self updateNetworkActivityIndicator];
+	if ([self requestDidFinishSelector]) {
+		[[self delegate] performSelector:[self requestDidFinishSelector] withObject:request];
 	}
-	if (requestsCount == 0) {
-		if (queueDidFinishSelector) {
-			[delegate performSelector:queueDidFinishSelector withObject:self];
+	if ([self requestsCount] == 0) {
+		if ([self queueDidFinishSelector]) {
+			[[self delegate] performSelector:[self queueDidFinishSelector] withObject:self];
 		}
 	}
 }
@@ -208,70 +208,70 @@
 
 - (void)setUploadBufferSize:(unsigned long long)bytes
 {
-	if (!uploadProgressDelegate) {
+	if (![self uploadProgressDelegate]) {
 		return;
 	}
-	uploadProgressTotalBytes -= bytes;
+	[self setUploadProgressTotalBytes:[self uploadProgressTotalBytes] - bytes];
 	[self incrementUploadProgressBy:0];
 }
 
 - (void)incrementUploadSizeBy:(unsigned long long)bytes
 {
-	if (!uploadProgressDelegate) {
+	if (![self uploadProgressDelegate]) {
 		return;
 	}
-	uploadProgressTotalBytes += bytes;
+	[self setUploadProgressTotalBytes:[self uploadProgressTotalBytes] + bytes];
 	[self incrementUploadProgressBy:0];
 }
 
 - (void)decrementUploadProgressBy:(unsigned long long)bytes
 {
-	if (!uploadProgressDelegate || uploadProgressTotalBytes == 0) {
+	if (![self uploadProgressDelegate] || [self uploadProgressTotalBytes] == 0) {
 		return;
 	}
-	uploadProgressBytes -= bytes;
+	[self setUploadProgressBytes:[self uploadProgressBytes] - bytes];
 	
-	double progress = (uploadProgressBytes*1.0)/(uploadProgressTotalBytes*1.0);
-	[ASIHTTPRequest setProgress:progress forProgressIndicator:uploadProgressDelegate];
+	double progress = ([self uploadProgressBytes]*1.0)/([self uploadProgressTotalBytes]*1.0);
+	[ASIHTTPRequest setProgress:progress forProgressIndicator:[self uploadProgressDelegate]];
 }
 
 
 - (void)incrementUploadProgressBy:(unsigned long long)bytes
 {
-	if (!uploadProgressDelegate || uploadProgressTotalBytes == 0) {
+	if (![self uploadProgressDelegate] || [self uploadProgressTotalBytes] == 0) {
 		return;
 	}
-	uploadProgressBytes += bytes;
+	[self setUploadProgressBytes:[self uploadProgressBytes] + bytes];
 	
-	double progress = (uploadProgressBytes*1.0)/(uploadProgressTotalBytes*1.0);
-	[ASIHTTPRequest setProgress:progress forProgressIndicator:uploadProgressDelegate];
+	double progress = ([self uploadProgressBytes]*1.0)/([self uploadProgressTotalBytes]*1.0);
+	[ASIHTTPRequest setProgress:progress forProgressIndicator:[self uploadProgressDelegate]];
 
 }
 
 - (void)incrementDownloadSizeBy:(unsigned long long)bytes
 {
-	if (!downloadProgressDelegate) {
+	if (![self downloadProgressDelegate]) {
 		return;
 	}
-	downloadProgressTotalBytes += bytes;
+	[self setDownloadProgressTotalBytes:[self downloadProgressTotalBytes] + bytes];
 	[self incrementDownloadProgressBy:0];
 }
 
 - (void)incrementDownloadProgressBy:(unsigned long long)bytes
 {
-	if (!downloadProgressDelegate || downloadProgressTotalBytes == 0) {
+	if (![self downloadProgressDelegate] || [self downloadProgressTotalBytes] == 0) {
 		return;
 	}
-	downloadProgressBytes += bytes;
-	double progress = (downloadProgressBytes*1.0)/(downloadProgressTotalBytes*1.0);
-	[ASIHTTPRequest setProgress:progress forProgressIndicator:downloadProgressDelegate];
+	[self setDownloadProgressBytes:[self downloadProgressBytes] + bytes];
+	double progress = ([self downloadProgressBytes]*1.0)/([self downloadProgressTotalBytes]*1.0);
+	[ASIHTTPRequest setProgress:progress forProgressIndicator:[self downloadProgressDelegate]];
 }
 
 // Since this queue takes over as the delegate for all requests it contains, it should forward authorisation requests to its own delegate
 - (void)authorizationNeededForRequest:(ASIHTTPRequest *)request
 {
-	if ([delegate respondsToSelector:@selector(authorizationNeededForRequest:)]) {
-		[delegate performSelector:@selector(authorizationNeededForRequest:) withObject:request];
+	if ([[self delegate] respondsToSelector:@selector(authorizationNeededForRequest:)]) {
+		[[self delegate] performSelector:@selector(authorizationNeededForRequest:) withObject:request];
 	}
 }
 
@@ -279,7 +279,7 @@
 - (BOOL)respondsToSelector:(SEL)selector
 {
 	if (selector == @selector(authorizationNeededForRequest:)) {
-		if ([delegate respondsToSelector:@selector(authorizationNeededForRequest:)]) {
+		if ([[self delegate] respondsToSelector:@selector(authorizationNeededForRequest:)]) {
 			return YES;
 		}
 		return NO;
@@ -288,7 +288,12 @@
 }
 
 
-
+@synthesize requestsCount;
+@synthesize uploadProgressBytes;
+@synthesize uploadProgressTotalBytes;
+@synthesize downloadProgressBytes;
+@synthesize downloadProgressTotalBytes;
+@synthesize shouldCancelAllRequestsOnFailure;
 @synthesize uploadProgressDelegate;
 @synthesize downloadProgressDelegate;
 @synthesize requestDidFinishSelector;</diff>
      <filename>Vendor/ASIHTTPRequest/ASINetworkQueue.m</filename>
    </modified>
  </modified>
  <removed type="array">
    <removed>
      <filename>Vendor/ASIHTTPRequest/NSHTTPCookieAdditions.h</filename>
    </removed>
    <removed>
      <filename>Vendor/ASIHTTPRequest/NSHTTPCookieAdditions.m</filename>
    </removed>
  </removed>
  <parents type="array">
    <parent>
      <id>1aa888e29e7df737f44dd30e45c6964db4bdc993</id>
    </parent>
  </parents>
  <author>
    <name>Tim Morgan</name>
    <email>git@timothymorgan.info</email>
  </author>
  <url>http://github.com/RISCfuture/scribd-uploader/commit/85f6b2c6e4824a76f1f9767fda91455796bbe25e</url>
  <id>85f6b2c6e4824a76f1f9767fda91455796bbe25e</id>
  <committed-date>2009-07-30T22:45:03-07:00</committed-date>
  <authored-date>2009-07-24T18:02:55-07:00</authored-date>
  <message>Latest ASIHTTPRequest</message>
  <tree>ff45cba4eb880dbec1e11cef775d1417ab3928ae</tree>
  <committer>
    <name>Tim Morgan</name>
    <email>git@timothymorgan.info</email>
  </committer>
</commit>
