Ver Fonte

Merge branch 'master' into swift-2.0

# Conflicts:
#	Source/Request.swift
#	Tests/CacheTests.swift
Christian Noon há 10 anos atrás
pai
commit
fd71afb3a0

+ 23 - 8
.travis.yml

@@ -4,16 +4,31 @@ branches:
   except:
   except:
     - swift-2.0
     - swift-2.0
 env:
 env:
-  - LC_CTYPE=en_US.UTF-8 LANG=en_US.UTF-8
+  global:
+  - LC_CTYPE=en_US.UTF-8
+  - LANG=en_US.UTF-8
+  matrix:
+    - DESTINATION="OS=8.1,name=iPhone 5S" SCHEME="Alamofire iOS" SDK=iphonesimulator8.3 BUILD_EXAMPLE="YES" POD_LINT="NO"
+    - DESTINATION="OS=8.2,name=iPhone 6" SCHEME="Alamofire iOS" SDK=iphonesimulator8.3 BUILD_EXAMPLE="YES" POD_LINT="NO"
+    - DESTINATION="OS=8.3,name=iPhone 6 Plus" SCHEME="Alamofire iOS" SDK=iphonesimulator8.3 BUILD_EXAMPLE="YES" POD_LINT="NO"
+    - DESTINATION="arch=x86_64" SCHEME="Alamofire OSX" SDK=macosx10.10 BUILD_EXAMPLE="NO" POD_LINT="YES"
 before_install:
 before_install:
   - gem install cocoapods --no-rdoc --no-ri --no-document --quiet
   - gem install cocoapods --no-rdoc --no-ri --no-document --quiet
   - gem install xcpretty --no-rdoc --no-ri --no-document --quiet
   - gem install xcpretty --no-rdoc --no-ri --no-document --quiet
 script:
 script:
   - set -o pipefail
   - set -o pipefail
-  - xcodebuild -project Alamofire.xcodeproj -scheme "Alamofire iOS" -sdk iphonesimulator
-    -destination "platform=iOS Simulator,name=iPhone 6" ONLY_ACTIVE_ARCH=NO test | xcpretty -c
-  - xcodebuild -project Alamofire.xcodeproj -scheme "Alamofire OSX" -sdk macosx10.10
-    -destination "platform=OS X,arch=x86_64" ONLY_ACTIVE_ARCH=NO test | xcpretty -c
-  - xcodebuild -project "iOS Example.xcodeproj" -scheme "iOS Example" -sdk iphonesimulator
-    -destination "platform=iOS Simulator,name=iPhone 6" ONLY_ACTIVE_ARCH=YES build | xcpretty -c
-  - pod lib lint --quick
+  - xcodebuild -project Alamofire.xcodeproj -scheme "$SCHEME" -sdk "$SDK" -destination "$DESTINATION" 
+    -configuration Debug ONLY_ACTIVE_ARCH=NO test | xcpretty -c
+  - xcodebuild -project Alamofire.xcodeproj -scheme "$SCHEME" -sdk "$SDK" -destination "$DESTINATION" 
+    -configuration Release ONLY_ACTIVE_ARCH=NO test | xcpretty -c
+  - if [ $BUILD_EXAMPLE == "YES" ]; then 
+      xcodebuild -project "iOS Example.xcodeproj" -scheme "iOS Example" -sdk "$SDK" -destination "$DESTINATION" 
+      -configuration Debug ONLY_ACTIVE_ARCH=NO build | xcpretty -c; 
+    fi
+  - if [ $BUILD_EXAMPLE == "YES" ]; then 
+      xcodebuild -project "iOS Example.xcodeproj" -scheme "iOS Example" -sdk "$SDK" -destination "$DESTINATION" 
+      -configuration Release ONLY_ACTIVE_ARCH=NO build | xcpretty -c; 
+    fi
+  - if [ $POD_LINT == "YES" ]; then 
+      pod lib lint --quick; 
+    fi

+ 1 - 1
Alamofire.podspec

@@ -1,6 +1,6 @@
 Pod::Spec.new do |s|
 Pod::Spec.new do |s|
   s.name = 'Alamofire'
   s.name = 'Alamofire'
-  s.version = '1.2.2'
+  s.version = '1.2.3'
   s.license = 'MIT'
   s.license = 'MIT'
   s.summary = 'Elegant HTTP Networking in Swift'
   s.summary = 'Elegant HTTP Networking in Swift'
   s.homepage = 'https://github.com/Alamofire/Alamofire'
   s.homepage = 'https://github.com/Alamofire/Alamofire'

+ 10 - 4
Alamofire.xcodeproj/project.pbxproj

@@ -11,6 +11,8 @@
 		4C256A541B096C770065714F /* BaseTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C256A501B096C2C0065714F /* BaseTestCase.swift */; };
 		4C256A541B096C770065714F /* BaseTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C256A501B096C2C0065714F /* BaseTestCase.swift */; };
 		4C341BBA1B1A865A00C1B34D /* CacheTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C341BB91B1A865A00C1B34D /* CacheTests.swift */; };
 		4C341BBA1B1A865A00C1B34D /* CacheTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C341BB91B1A865A00C1B34D /* CacheTests.swift */; };
 		4C341BBB1B1A865A00C1B34D /* CacheTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C341BB91B1A865A00C1B34D /* CacheTests.swift */; };
 		4C341BBB1B1A865A00C1B34D /* CacheTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C341BB91B1A865A00C1B34D /* CacheTests.swift */; };
+		4CCFA79A1B2BE71600B6F460 /* URLProtocolTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CCFA7991B2BE71600B6F460 /* URLProtocolTests.swift */; };
+		4CCFA79B1B2BE71600B6F460 /* URLProtocolTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CCFA7991B2BE71600B6F460 /* URLProtocolTests.swift */; };
 		4CDE2C371AF8932A00BABAE5 /* Manager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CDE2C361AF8932A00BABAE5 /* Manager.swift */; };
 		4CDE2C371AF8932A00BABAE5 /* Manager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CDE2C361AF8932A00BABAE5 /* Manager.swift */; };
 		4CDE2C381AF8932A00BABAE5 /* Manager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CDE2C361AF8932A00BABAE5 /* Manager.swift */; };
 		4CDE2C381AF8932A00BABAE5 /* Manager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CDE2C361AF8932A00BABAE5 /* Manager.swift */; };
 		4CDE2C3A1AF899EC00BABAE5 /* Request.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CDE2C391AF899EC00BABAE5 /* Request.swift */; };
 		4CDE2C3A1AF899EC00BABAE5 /* Request.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CDE2C391AF899EC00BABAE5 /* Request.swift */; };
@@ -70,6 +72,7 @@
 /* Begin PBXFileReference section */
 /* Begin PBXFileReference section */
 		4C256A501B096C2C0065714F /* BaseTestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseTestCase.swift; sourceTree = "<group>"; };
 		4C256A501B096C2C0065714F /* BaseTestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseTestCase.swift; sourceTree = "<group>"; };
 		4C341BB91B1A865A00C1B34D /* CacheTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CacheTests.swift; sourceTree = "<group>"; };
 		4C341BB91B1A865A00C1B34D /* CacheTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CacheTests.swift; sourceTree = "<group>"; };
+		4CCFA7991B2BE71600B6F460 /* URLProtocolTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLProtocolTests.swift; sourceTree = "<group>"; };
 		4CDE2C361AF8932A00BABAE5 /* Manager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Manager.swift; sourceTree = "<group>"; };
 		4CDE2C361AF8932A00BABAE5 /* Manager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Manager.swift; sourceTree = "<group>"; };
 		4CDE2C391AF899EC00BABAE5 /* Request.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Request.swift; sourceTree = "<group>"; };
 		4CDE2C391AF899EC00BABAE5 /* Request.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Request.swift; sourceTree = "<group>"; };
 		4CDE2C3C1AF89D4900BABAE5 /* Download.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Download.swift; sourceTree = "<group>"; };
 		4CDE2C3C1AF89D4900BABAE5 /* Download.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Download.swift; sourceTree = "<group>"; };
@@ -148,6 +151,7 @@
 				F8111E5B19A9674D0040E7D1 /* DownloadTests.swift */,
 				F8111E5B19A9674D0040E7D1 /* DownloadTests.swift */,
 				F86AEFE51AE6A282007D9C76 /* TLSEvaluationTests.swift */,
 				F86AEFE51AE6A282007D9C76 /* TLSEvaluationTests.swift */,
 				F8111E5F19A9674D0040E7D1 /* UploadTests.swift */,
 				F8111E5F19A9674D0040E7D1 /* UploadTests.swift */,
+				4CCFA7991B2BE71600B6F460 /* URLProtocolTests.swift */,
 				F8AE910119D28DCC0078C7B2 /* ValidationTests.swift */,
 				F8AE910119D28DCC0078C7B2 /* ValidationTests.swift */,
 			);
 			);
 			name = Features;
 			name = Features;
@@ -438,6 +442,7 @@
 			buildActionMask = 2147483647;
 			buildActionMask = 2147483647;
 			files = (
 			files = (
 				4C341BBA1B1A865A00C1B34D /* CacheTests.swift in Sources */,
 				4C341BBA1B1A865A00C1B34D /* CacheTests.swift in Sources */,
+				4CCFA79A1B2BE71600B6F460 /* URLProtocolTests.swift in Sources */,
 				F86AEFE71AE6A312007D9C76 /* TLSEvaluationTests.swift in Sources */,
 				F86AEFE71AE6A312007D9C76 /* TLSEvaluationTests.swift in Sources */,
 				F8858DDD19A96B4300F55F93 /* RequestTests.swift in Sources */,
 				F8858DDD19A96B4300F55F93 /* RequestTests.swift in Sources */,
 				4C256A531B096C770065714F /* BaseTestCase.swift in Sources */,
 				4C256A531B096C770065714F /* BaseTestCase.swift in Sources */,
@@ -456,6 +461,7 @@
 			buildActionMask = 2147483647;
 			buildActionMask = 2147483647;
 			files = (
 			files = (
 				4C341BBB1B1A865A00C1B34D /* CacheTests.swift in Sources */,
 				4C341BBB1B1A865A00C1B34D /* CacheTests.swift in Sources */,
+				4CCFA79B1B2BE71600B6F460 /* URLProtocolTests.swift in Sources */,
 				F829C6BE1A7A950600A2CD59 /* ParameterEncodingTests.swift in Sources */,
 				F829C6BE1A7A950600A2CD59 /* ParameterEncodingTests.swift in Sources */,
 				F829C6BF1A7A950600A2CD59 /* RequestTests.swift in Sources */,
 				F829C6BF1A7A950600A2CD59 /* RequestTests.swift in Sources */,
 				4C256A541B096C770065714F /* BaseTestCase.swift in Sources */,
 				4C256A541B096C770065714F /* BaseTestCase.swift in Sources */,
@@ -500,7 +506,7 @@
 					"DEBUG=1",
 					"DEBUG=1",
 					"$(inherited)",
 					"$(inherited)",
 				);
 				);
-				INFOPLIST_FILE = "$(SRCROOT)/Source/Info.plist";
+				INFOPLIST_FILE = Source/Info.plist;
 				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
 				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
 				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
 				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
@@ -524,7 +530,7 @@
 				DYLIB_CURRENT_VERSION = 1;
 				DYLIB_CURRENT_VERSION = 1;
 				DYLIB_INSTALL_NAME_BASE = "@rpath";
 				DYLIB_INSTALL_NAME_BASE = "@rpath";
 				FRAMEWORK_VERSION = A;
 				FRAMEWORK_VERSION = A;
-				INFOPLIST_FILE = "$(SRCROOT)/Source/Info.plist";
+				INFOPLIST_FILE = Source/Info.plist;
 				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
 				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
 				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
 				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
@@ -634,7 +640,7 @@
 				DYLIB_COMPATIBILITY_VERSION = 1;
 				DYLIB_COMPATIBILITY_VERSION = 1;
 				DYLIB_CURRENT_VERSION = 1;
 				DYLIB_CURRENT_VERSION = 1;
 				DYLIB_INSTALL_NAME_BASE = "@rpath";
 				DYLIB_INSTALL_NAME_BASE = "@rpath";
-				INFOPLIST_FILE = "$(SRCROOT)/Source/Info.plist";
+				INFOPLIST_FILE = Source/Info.plist;
 				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
 				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
 				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
 				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
@@ -656,7 +662,7 @@
 				DYLIB_COMPATIBILITY_VERSION = 1;
 				DYLIB_COMPATIBILITY_VERSION = 1;
 				DYLIB_CURRENT_VERSION = 1;
 				DYLIB_CURRENT_VERSION = 1;
 				DYLIB_INSTALL_NAME_BASE = "@rpath";
 				DYLIB_INSTALL_NAME_BASE = "@rpath";
-				INFOPLIST_FILE = "$(SRCROOT)/Source/Info.plist";
+				INFOPLIST_FILE = Source/Info.plist;
 				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
 				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
 				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
 				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";

+ 66 - 2
CHANGELOG.md

@@ -2,14 +2,78 @@
 All notable changes to this project will be documented in this file.
 All notable changes to this project will be documented in this file.
 `Alamofire` adheres to [Semantic Versioning](http://semver.org/).
 `Alamofire` adheres to [Semantic Versioning](http://semver.org/).
 
 
-- `1.2.x` Releases - [1.2.0](#120) | [1.2.1](#121) | [1.2.2](#122)
+- `1.2.x` Releases - [1.2.0](#120) | [1.2.1](#121) | [1.2.2](#122) | [1.2.3](#123)
 - `1.1.x` Releases - [1.1.0](#110) | [1.1.1](#111) | [1.1.2](#112) | [1.1.3](#113) | [1.1.4](#114) | [1.1.5](#115)
 - `1.1.x` Releases - [1.1.0](#110) | [1.1.1](#111) | [1.1.2](#112) | [1.1.3](#113) | [1.1.4](#114) | [1.1.5](#115)
 - `1.0.x` Releases - [1.0.0](#100) | [1.0.1](#101)
 - `1.0.x` Releases - [1.0.0](#100) | [1.0.1](#101)
 
 
 ---
 ---
 
 
+## [1.2.3](https://github.com/Alamofire/Alamofire/releases/tag/1.2.3)
+Released on 2015-06-12. All issues associated with this milestone can be found using this 
+[filter](https://github.com/Alamofire/Alamofire/issues?utf8=✓&q=milestone%3A1.2.3).
+
+#### Added
+- Tests for data task progress closure and NSProgress updates.
+  - Added by [Christian Noon](https://github.com/cnoon) in Pull Request
+  [#494](https://github.com/Alamofire/Alamofire/pull/494).
+- More robust tests around download and upload progress.
+  - Added by [Christian Noon](https://github.com/cnoon) in Pull Request
+  [#494](https://github.com/Alamofire/Alamofire/pull/494).
+- More robust redirect tests around default behavior and task override closures.
+  - Added by [Christian Noon](https://github.com/cnoon) in Pull Request
+  [#507](https://github.com/Alamofire/Alamofire/pull/507).
+- The "[" and "]" to the legal escape characters and added more documentation.
+  - Added by [Christian Noon](https://github.com/cnoon) in Pull Request
+  [#504](https://github.com/Alamofire/Alamofire/pull/504).
+- Percent escaping tests around reserved / unreserved / illegal characters.
+  - Added by [Christian Noon](https://github.com/cnoon) in Pull Request
+  [#504](https://github.com/Alamofire/Alamofire/pull/504).
+- Tests for various Cache-Control headers with different request cache policies.
+  - Added by [Christian Noon](https://github.com/cnoon) in Pull Request
+  [#505](https://github.com/Alamofire/Alamofire/pull/505).
+- Link to Carthage in the README.
+  - Added by [Josh Brown](https://github.com/joshuatbrown) in Pull Request
+  [#520](https://github.com/Alamofire/Alamofire/pull/520).
+
+#### Updated
+- iOS 7 instructions to cover multiple Swift files in the README.
+  - Updated by [Sébastien Michoy](https://github.com/SebastienMichoy) in regards
+  to Issue [#479](https://github.com/Alamofire/Alamofire/pull/479).
+- All tests to follow the Given / When / Then structure.
+  - Updated by [Christian Noon](https://github.com/cnoon) in Pull Request
+  [#489](https://github.com/Alamofire/Alamofire/pull/489).
+- All tests to be crash safe.
+  - Updated by [Christian Noon](https://github.com/cnoon) in Pull Request
+  [#489](https://github.com/Alamofire/Alamofire/pull/489).
+- The OS X tests so that they are all passing again.
+  - Updated by [Christian Noon](https://github.com/cnoon) in Pull Request
+  [#489](https://github.com/Alamofire/Alamofire/pull/489).
+- Re-enabled Travis-CI tests for both iOS and Mac OS X.
+  - Updated by [Christian Noon](https://github.com/cnoon) in Pull Request
+  [#506](https://github.com/Alamofire/Alamofire/pull/506).
+- Travis-CI test suite to run all tests in both debug and release.
+  - Updated by [Christian Noon](https://github.com/cnoon) in Pull Request
+  [#506](https://github.com/Alamofire/Alamofire/pull/506).
+- Travis-CI test suite to run all tests on iOS 8.1, 8.2 and 8.3 as well as Mac OS X 10.10.
+  - Updated by [Christian Noon](https://github.com/cnoon) in Pull Request
+  [#506](https://github.com/Alamofire/Alamofire/pull/506).
+- Travis-CI test suite to run `pod lib lint` against the latest version of CocoaPods.
+  - Updated by [Christian Noon](https://github.com/cnoon) in Pull Request
+  [#506](https://github.com/Alamofire/Alamofire/pull/506).
+
+#### Fixed
+- Random deinitialization test failure by handling task state race condition.
+  - Fixed by [Christian Noon](https://github.com/cnoon).
+- Typo in the API Parameter Abstraction in the README.
+  - Fixed by [Josh Brown](https://github.com/joshuatbrown) in Pull Request
+  [#500](https://github.com/Alamofire/Alamofire/pull/500).
+- Cookies are now only applied in the DebugPrintable API when appropriate.
+  - Fixed by [Alex Plescan](https://github.com/alexpls) in Pull Request
+  [#516](https://github.com/Alamofire/Alamofire/pull/516).
+
 ## [1.2.2](https://github.com/Alamofire/Alamofire/releases/tag/1.2.2)
 ## [1.2.2](https://github.com/Alamofire/Alamofire/releases/tag/1.2.2)
-Released on 2015-05-13. All issues associated with this milestone can be found using this [filter](https://github.com/Alamofire/Alamofire/issues?utf8=✓&q=milestone%3A1.2.2).
+Released on 2015-05-13. All issues associated with this milestone can be found using this 
+[filter](https://github.com/Alamofire/Alamofire/issues?utf8=✓&q=milestone%3A1.2.2).
 
 
 #### Added
 #### Added
 - Contributing Guidelines document to the project.
 - Contributing Guidelines document to the project.

+ 1 - 1
Source/Info.plist

@@ -15,7 +15,7 @@
 	<key>CFBundlePackageType</key>
 	<key>CFBundlePackageType</key>
 	<string>FMWK</string>
 	<string>FMWK</string>
 	<key>CFBundleShortVersionString</key>
 	<key>CFBundleShortVersionString</key>
-	<string>1.2.2</string>
+	<string>1.2.3</string>
 	<key>CFBundleSignature</key>
 	<key>CFBundleSignature</key>
 	<string>????</string>
 	<string>????</string>
 	<key>CFBundleVersion</key>
 	<key>CFBundleVersion</key>

+ 39 - 12
Source/Request.swift

@@ -116,6 +116,23 @@ public class Request {
         return self
         return self
     }
     }
 
 
+    /**
+        Sets a closure to be called periodically during the lifecycle of the request as data is read from the server.
+
+        This closure returns the bytes most recently received from the server, not including data from previous calls. If this closure is set, data will only be available within this closure, and will not be saved elsewhere. It is also important to note that the `response` closure will be called with nil `responseData`.
+
+        :param: closure The code to be executed periodically during the lifecycle of the request.
+
+        :returns: The request.
+    */
+    public func stream(closure: (NSData -> Void)? = nil) -> Self {
+        if let dataDelegate = delegate as? DataTaskDelegate {
+            dataDelegate.dataStream = closure
+        }
+
+        return self
+    }
+
     // MARK: - Response
     // MARK: - Response
 
 
     /**
     /**
@@ -300,15 +317,19 @@ public class Request {
     class DataTaskDelegate: TaskDelegate, NSURLSessionDataDelegate {
     class DataTaskDelegate: TaskDelegate, NSURLSessionDataDelegate {
         var dataTask: NSURLSessionDataTask? { return task as? NSURLSessionDataTask }
         var dataTask: NSURLSessionDataTask? { return task as? NSURLSessionDataTask }
 
 
+        private var totalBytesReceived: Int64 = 0
         private var mutableData: NSMutableData
         private var mutableData: NSMutableData
         override var data: NSData? {
         override var data: NSData? {
-            return mutableData
+            if dataStream != nil {
+                return nil
+            } else {
+                return mutableData
+            }
         }
         }
 
 
         private var expectedContentLength: Int64?
         private var expectedContentLength: Int64?
-
-
-        var dataProgress: ((bytesReceived: Int64, totalBytesReceived: Int64, totalBytesExpectedToReceive: Int64) -> Void)?
+        private var dataProgress: ((bytesReceived: Int64, totalBytesReceived: Int64, totalBytesExpectedToReceive: Int64) -> Void)?
+        private var dataStream: ((data: NSData) -> Void)?
 
 
         override init(task: NSURLSessionTask) {
         override init(task: NSURLSessionTask) {
             self.mutableData = NSMutableData()
             self.mutableData = NSMutableData()
@@ -346,9 +367,13 @@ public class Request {
             if dataTaskDidReceiveData != nil {
             if dataTaskDidReceiveData != nil {
                 dataTaskDidReceiveData!(session, dataTask, data)
                 dataTaskDidReceiveData!(session, dataTask, data)
             } else {
             } else {
-                mutableData.appendData(data)
+                if let dataStream = dataStream {
+                    dataStream(data: data)
+                } else {
+                    mutableData.appendData(data)
+                }
 
 
-                let totalBytesReceived = Int64(mutableData.length)
+                totalBytesReceived += data.length
                 let totalBytesExpectedToReceive = dataTask.response?.expectedContentLength ?? NSURLSessionTransferSizeUnknown
                 let totalBytesExpectedToReceive = dataTask.response?.expectedContentLength ?? NSURLSessionTransferSizeUnknown
 
 
                 progress.totalUnitCount = totalBytesExpectedToReceive
                 progress.totalUnitCount = totalBytesExpectedToReceive
@@ -427,12 +452,14 @@ extension Request: CustomDebugStringConvertible {
         // Temporarily disabled on OS X due to build failure for CocoaPods
         // Temporarily disabled on OS X due to build failure for CocoaPods
         // See https://github.com/CocoaPods/swift/issues/24
         // See https://github.com/CocoaPods/swift/issues/24
         #if !os(OSX)
         #if !os(OSX)
-            if let cookieStorage = session.configuration.HTTPCookieStorage,
-                cookies = cookieStorage.cookiesForURL(URL!)
-                where !cookies.isEmpty
-            {
-                let string = cookies.reduce(""){ $0 + "\($1.name)=\($1.value ?? String());" }
-                components.append("-b \"\(string.substringToIndex(string.endIndex.predecessor()))\"")
+            if session.configuration.HTTPShouldSetCookies {
+                if let cookieStorage = session.configuration.HTTPCookieStorage,
+                    cookies = cookieStorage.cookiesForURL(URL!)
+                    where !cookies.isEmpty
+                {
+                    let string = cookies.reduce(""){ $0 + "\($1.name)=\($1.value ?? String());" }
+                    components.append("-b \"\(string.substringToIndex(string.endIndex.predecessor()))\"")
+                }
             }
             }
         #endif
         #endif
 
 

+ 43 - 15
Tests/CacheTests.swift

@@ -231,6 +231,22 @@ class CacheTestCase: BaseTestCase {
         }
         }
     }
     }
 
 
+    // MARK: - Cache Helper Methods
+
+    private func isCachedResponseForNoStoreHeaderExpected() -> Bool {
+        var storedInCache = false
+
+        #if os(iOS)
+            let operatingSystemVersion = NSOperatingSystemVersion(majorVersion: 8, minorVersion: 3, patchVersion: 0)
+
+            if !NSProcessInfo().isOperatingSystemAtLeastVersion(operatingSystemVersion) {
+                storedInCache = true
+            }
+        #endif
+
+        return storedInCache
+    }
+
     // MARK: - Tests
     // MARK: - Tests
 
 
     func testURLCacheContainsCachedResponsesForAllRequests() {
     func testURLCacheContainsCachedResponsesForAllRequests() {
@@ -256,7 +272,12 @@ class CacheTestCase: BaseTestCase {
         XCTAssertNotNil(maxAgeNonExpiredResponse, "\(CacheControl.MaxAgeNonExpired) response should not be nil")
         XCTAssertNotNil(maxAgeNonExpiredResponse, "\(CacheControl.MaxAgeNonExpired) response should not be nil")
         XCTAssertNotNil(maxAgeExpiredResponse, "\(CacheControl.MaxAgeExpired) response should not be nil")
         XCTAssertNotNil(maxAgeExpiredResponse, "\(CacheControl.MaxAgeExpired) response should not be nil")
         XCTAssertNotNil(noCacheResponse, "\(CacheControl.NoCache) response should not be nil")
         XCTAssertNotNil(noCacheResponse, "\(CacheControl.NoCache) response should not be nil")
-        XCTAssertNil(noStoreResponse, "\(CacheControl.NoStore) response should be nil")
+
+        if isCachedResponseForNoStoreHeaderExpected() {
+            XCTAssertNotNil(noStoreResponse, "\(CacheControl.NoStore) response should not be nil")
+        } else {
+            XCTAssertNil(noStoreResponse, "\(CacheControl.NoStore) response should be nil")
+        }
     }
     }
 
 
     func testDefaultCachePolicy() {
     func testDefaultCachePolicy() {
@@ -289,7 +310,12 @@ class CacheTestCase: BaseTestCase {
         executeTest(cachePolicy: cachePolicy, cacheControl: CacheControl.MaxAgeNonExpired, shouldReturnCachedResponse: true)
         executeTest(cachePolicy: cachePolicy, cacheControl: CacheControl.MaxAgeNonExpired, shouldReturnCachedResponse: true)
         executeTest(cachePolicy: cachePolicy, cacheControl: CacheControl.MaxAgeExpired, shouldReturnCachedResponse: true)
         executeTest(cachePolicy: cachePolicy, cacheControl: CacheControl.MaxAgeExpired, shouldReturnCachedResponse: true)
         executeTest(cachePolicy: cachePolicy, cacheControl: CacheControl.NoCache, shouldReturnCachedResponse: true)
         executeTest(cachePolicy: cachePolicy, cacheControl: CacheControl.NoCache, shouldReturnCachedResponse: true)
-        executeTest(cachePolicy: cachePolicy, cacheControl: CacheControl.NoStore, shouldReturnCachedResponse: false)
+
+        if isCachedResponseForNoStoreHeaderExpected() {
+            executeTest(cachePolicy: cachePolicy, cacheControl: CacheControl.NoStore, shouldReturnCachedResponse: true)
+        } else {
+            executeTest(cachePolicy: cachePolicy, cacheControl: CacheControl.NoStore, shouldReturnCachedResponse: false)
+        }
     }
     }
 
 
     func testUseLocalCacheDataAndDontLoadFromNetworkPolicy() {
     func testUseLocalCacheDataAndDontLoadFromNetworkPolicy() {
@@ -301,21 +327,23 @@ class CacheTestCase: BaseTestCase {
         executeTest(cachePolicy: cachePolicy, cacheControl: CacheControl.MaxAgeExpired, shouldReturnCachedResponse: true)
         executeTest(cachePolicy: cachePolicy, cacheControl: CacheControl.MaxAgeExpired, shouldReturnCachedResponse: true)
         executeTest(cachePolicy: cachePolicy, cacheControl: CacheControl.NoCache, shouldReturnCachedResponse: true)
         executeTest(cachePolicy: cachePolicy, cacheControl: CacheControl.NoCache, shouldReturnCachedResponse: true)
 
 
-        // Execute Test - CacheControl.NoStore
+        if isCachedResponseForNoStoreHeaderExpected() {
+            executeTest(cachePolicy: cachePolicy, cacheControl: CacheControl.NoStore, shouldReturnCachedResponse: true)
+        } else {
+            // Given
+            let expectation = expectationWithDescription("GET request to httpbin")
+            var response: NSHTTPURLResponse?
+
+            // When
+            startRequest(cacheControl: CacheControl.NoStore, cachePolicy: cachePolicy) { _, responseResponse in
+                response = responseResponse
+                expectation.fulfill()
+            }
 
 
-        // Given
-        let expectation = expectationWithDescription("GET request to httpbin")
-        var response: NSHTTPURLResponse?
+            waitForExpectationsWithTimeout(self.defaultTimeout, handler: nil)
 
 
-        // When
-        startRequest(cacheControl: CacheControl.NoStore, cachePolicy: cachePolicy) { _, responseResponse in
-            response = responseResponse
-            expectation.fulfill()
+            // Then
+            XCTAssertNil(response, "response should be nil")
         }
         }
-
-        waitForExpectationsWithTimeout(self.defaultTimeout, handler: nil)
-
-        // Then
-        XCTAssertNil(response, "response should be nil")
     }
     }
 }
 }

+ 104 - 0
Tests/RequestTests.swift

@@ -153,6 +153,77 @@ class RequestResponseTestCase: BaseTestCase {
             XCTFail("last item in bytesValues and progressValues should not be nil")
             XCTFail("last item in bytesValues and progressValues should not be nil")
         }
         }
     }
     }
+
+    func testRequestResponseWithStream() {
+        // Given
+        let randomBytes = 4 * 1024 * 1024
+        let URLString = "http://httpbin.org/bytes/\(randomBytes)"
+
+        let expectation = expectationWithDescription("Bytes download progress should be reported: \(URLString)")
+
+        var byteValues: [(bytes: Int64, totalBytes: Int64, totalBytesExpected: Int64)] = []
+        var progressValues: [(completedUnitCount: Int64, totalUnitCount: Int64)] = []
+        var accumulatedData = [NSData]()
+
+        var responseRequest: NSURLRequest?
+        var responseResponse: NSHTTPURLResponse?
+        var responseData: AnyObject?
+        var responseError: NSError?
+
+        // When
+        let request = Alamofire.request(.GET, URLString: URLString)
+        request.progress { bytesRead, totalBytesRead, totalBytesExpectedToRead in
+            let bytes = (bytes: bytesRead, totalBytes: totalBytesRead, totalBytesExpected: totalBytesExpectedToRead)
+            byteValues.append(bytes)
+
+            let progress = (completedUnitCount: request.progress.completedUnitCount, totalUnitCount: request.progress.totalUnitCount)
+            progressValues.append(progress)
+        }
+        request.stream { accumulatedData.append($0) }
+        request.response { request, response, data, error in
+            responseRequest = request
+            responseResponse = response
+            responseData = data
+            responseError = error
+
+            expectation.fulfill()
+        }
+
+        waitForExpectationsWithTimeout(self.defaultTimeout, handler: nil)
+
+        // Then
+        XCTAssertNotNil(responseRequest, "response request should not be nil")
+        XCTAssertNotNil(responseResponse, "response response should not be nil")
+        XCTAssertNil(responseData, "response data should be nil")
+        XCTAssertNil(responseError, "response error should be nil")
+        XCTAssertGreaterThanOrEqual(accumulatedData.count, 1, "accumulated data should have one or more parts")
+
+        XCTAssertEqual(byteValues.count, progressValues.count, "byteValues count should equal progressValues count")
+
+        if byteValues.count == progressValues.count {
+            for index in 0..<byteValues.count {
+                let byteValue = byteValues[index]
+                let progressValue = progressValues[index]
+
+                XCTAssertGreaterThan(byteValue.bytes, 0, "reported bytes should always be greater than 0")
+                XCTAssertEqual(byteValue.totalBytes, progressValue.completedUnitCount, "total bytes should be equal to completed unit count")
+                XCTAssertEqual(byteValue.totalBytesExpected, progressValue.totalUnitCount, "total bytes expected should be equal to total unit count")
+            }
+        }
+
+        if let lastByteValue = byteValues.last,
+            lastProgressValue = progressValues.last
+        {
+            let byteValueFractionalCompletion = Double(lastByteValue.totalBytes) / Double(lastByteValue.totalBytesExpected)
+            let progressValueFractionalCompletion = Double(lastProgressValue.0) / Double(lastProgressValue.1)
+
+            XCTAssertEqual(byteValueFractionalCompletion, 1.0, "byte value fractional completion should equal 1.0")
+            XCTAssertEqual(progressValueFractionalCompletion, 1.0, "progress value fractional completion should equal 1.0")
+            XCTAssertEqual(accumulatedData.reduce(0) { $0 + $1.length }, lastByteValue.totalBytes, "accumulated data length should match byte count")
+        } else {
+            XCTFail("last item in bytesValues and progressValues should not be nil")
+        }
+    }
 }
 }
 
 
 // MARK: -
 // MARK: -
@@ -196,6 +267,16 @@ class RequestDebugDescriptionTestCase: BaseTestCase {
         return manager
         return manager
     }()
     }()
 
 
+    let managerDisallowingCookies: Alamofire.Manager = {
+        let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
+        configuration.HTTPShouldSetCookies = false
+
+        let manager = Alamofire.Manager(configuration: configuration)
+        manager.startRequestsImmediately = false
+
+        return manager
+    }()
+
     // MARK: Tests
     // MARK: Tests
 
 
     func testGETRequestDebugDescription() {
     func testGETRequestDebugDescription() {
@@ -269,6 +350,29 @@ class RequestDebugDescriptionTestCase: BaseTestCase {
         #endif
         #endif
     }
     }
 
 
+    func testPOSTRequestWithCookiesDisabledDebugDescription() {
+        // Given
+        let URLString = "http://httpbin.org/post"
+
+        let properties = [
+            NSHTTPCookieDomain: "httpbin.org",
+            NSHTTPCookiePath: "/post",
+            NSHTTPCookieName: "foo",
+            NSHTTPCookieValue: "bar",
+        ]
+
+        let cookie = NSHTTPCookie(properties: properties)!
+        managerDisallowingCookies.session.configuration.HTTPCookieStorage?.setCookie(cookie)
+
+        // When
+        let request = managerDisallowingCookies.request(.POST, URLString)
+        let components = cURLCommandComponents(request)
+
+        // Then
+        let cookieComponents = components.filter { $0 == "-b" }
+        XCTAssertTrue(cookieComponents.isEmpty, "command should not contain -b flag")
+    }
+
     // MARK: Test Helper Methods
     // MARK: Test Helper Methods
 
 
     private func cURLCommandComponents(request: Request) -> [String] {
     private func cURLCommandComponents(request: Request) -> [String] {

+ 168 - 0
Tests/URLProtocolTests.swift

@@ -0,0 +1,168 @@
+// URLProtocolTests.swift
+//
+// Copyright (c) 2014–2015 Alamofire Software Foundation (http://alamofire.org/)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Alamofire
+import Foundation
+import XCTest
+
+class ProxyURLProtocol: NSURLProtocol {
+
+    // MARK: Properties
+
+    struct PropertyKeys {
+        static let HandledByForwarderURLProtocol = "HandledByProxyURLProtocol"
+    }
+
+    lazy var session: NSURLSession = {
+        let configuration: NSURLSessionConfiguration = {
+            let configuration = NSURLSessionConfiguration.ephemeralSessionConfiguration()
+            configuration.HTTPAdditionalHeaders = Alamofire.Manager.defaultHTTPHeaders
+
+            return configuration
+        }()
+
+        let session = NSURLSession(configuration: configuration, delegate: self, delegateQueue: nil)
+
+        return session
+    }()
+
+    var activeTask: NSURLSessionTask?
+
+    // MARK: Class Request Methods
+
+    override class func canInitWithRequest(request: NSURLRequest) -> Bool {
+        if NSURLProtocol.propertyForKey(PropertyKeys.HandledByForwarderURLProtocol, inRequest: request) != nil {
+            return false
+        }
+
+        return true
+    }
+
+    override class func canonicalRequestForRequest(request: NSURLRequest) -> NSURLRequest {
+        return request
+    }
+
+    override class func requestIsCacheEquivalent(a: NSURLRequest, toRequest b: NSURLRequest) -> Bool {
+        return false
+    }
+
+    // MARK: Loading Methods
+
+    override func startLoading() {
+        let mutableRequest = self.request.mutableCopy() as! NSMutableURLRequest
+        NSURLProtocol.setProperty(true, forKey: PropertyKeys.HandledByForwarderURLProtocol, inRequest: mutableRequest)
+
+        self.activeTask = self.session.dataTaskWithRequest(mutableRequest)
+        self.activeTask?.resume()
+    }
+
+    override func stopLoading() {
+        self.activeTask?.cancel()
+    }
+}
+
+// MARK: -
+
+extension ProxyURLProtocol: NSURLSessionDelegate {
+
+    // MARK: NSURLSessionDelegate
+
+    func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) {
+        self.client?.URLProtocol(self, didLoadData: data)
+    }
+
+    func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
+        if let response = task.response {
+            self.client?.URLProtocol(self, didReceiveResponse: response, cacheStoragePolicy: .NotAllowed)
+        }
+
+        self.client?.URLProtocolDidFinishLoading(self)
+    }
+}
+
+// MARK: -
+
+class URLProtocolTestCase: BaseTestCase {
+
+    // MARK: Setup and Teardown Methods
+
+    override func setUp() {
+        super.setUp()
+
+        let protocolClasses: [AnyClass] = [ProxyURLProtocol.self]
+        Alamofire.Manager.sharedInstance.session.configuration.protocolClasses = protocolClasses
+        Alamofire.Manager.sharedInstance.session.configuration.HTTPAdditionalHeaders = ["Session-Configuration-Header": "foo"]
+    }
+
+    override func tearDown() {
+        super.tearDown()
+
+        Alamofire.Manager.sharedInstance.session.configuration.protocolClasses = []
+    }
+
+    // MARK: Tests
+
+    func testThatURLProtocolReceivesRequestHeadersAndNotSessionConfigurationHeaders() {
+        // Given
+        let URLString = "http://httpbin.org/response-headers"
+        let URL = NSURL(string: URLString)!
+        let parameters = ["URLRequest-Header": "foobar"]
+
+        let mutableURLRequest = NSMutableURLRequest(URL: URL)
+        mutableURLRequest.HTTPMethod = Method.GET.rawValue
+
+        let URLRequest = ParameterEncoding.URL.encode(mutableURLRequest, parameters: parameters).0
+
+        let expectation = expectationWithDescription("GET request should succeed")
+
+        var request: NSURLRequest?
+        var response: NSHTTPURLResponse?
+        var string: AnyObject?
+        var error: NSError?
+
+        // When
+        Alamofire.request(URLRequest)
+            .response { responseRequest, responseResponse, responseString, responseError in
+                request = responseRequest
+                response = responseResponse
+                string = responseString
+                error = responseError
+
+                expectation.fulfill()
+        }
+
+        waitForExpectationsWithTimeout(self.defaultTimeout, handler: nil)
+
+        // Then
+        XCTAssertNotNil(request, "request should not be nil")
+        XCTAssertNotNil(response, "response should not be nil")
+        XCTAssertNotNil(string, "string should not be nil")
+        XCTAssertNil(error, "error should be nil")
+
+        if let headers = response?.allHeaderFields as? [String: String] {
+            XCTAssertEqual(headers["URLRequest-Header"] ?? "", "foobar", "URLRequest-Header should be foobar")
+            XCTAssertNil(headers["Session-Configuration-Header"], "Session-Configuration-Header should be nil")
+        } else {
+            XCTFail("headers should not be nil")
+        }
+    }
+}