diff --git a/Foundation/NSURLSession/NSURLSessionTask.swift b/Foundation/NSURLSession/NSURLSessionTask.swift index 25f0afda4f..e44fb9da9f 100644 --- a/Foundation/NSURLSession/NSURLSessionTask.swift +++ b/Foundation/NSURLSession/NSURLSessionTask.swift @@ -554,7 +554,16 @@ fileprivate extension URLSessionTask { // HTTP Options: easyHandle.set(followLocation: false) - easyHandle.set(customHeaders: curlHeaders(for: request)) + + let customHeaders: [String] + let headersForRequest = curlHeaders(for: request) + if ((request.httpMethod == "POST") && (request.value(forHTTPHeaderField: "Content-Type") == nil)) { + customHeaders = headersForRequest + ["Content-Type:application/x-www-form-urlencoded"] + } else { + customHeaders = headersForRequest + } + + easyHandle.set(customHeaders: customHeaders) //TODO: The CURLOPT_PIPEDWAIT option is unavailable on Ubuntu 14.04 (libcurl 7.36) //TODO: Introduce something like an #if, if we want to set them here @@ -575,8 +584,6 @@ fileprivate extension URLSessionTask { easyHandle.set(requestMethod: request.httpMethod ?? "GET") if request.httpMethod == "HEAD" { easyHandle.set(noBody: true) - } else if ((request.httpMethod == "POST") && (request.value(forHTTPHeaderField: "Content-Type") == nil)) { - easyHandle.set(customHeaders: ["Content-Type:application/x-www-form-urlencoded"]) } } } diff --git a/TestFoundation/HTTPServer.swift b/TestFoundation/HTTPServer.swift index 3ba04ea882..4070399045 100644 --- a/TestFoundation/HTTPServer.swift +++ b/TestFoundation/HTTPServer.swift @@ -191,6 +191,14 @@ struct _HTTPRequest { body = lines.last! } + public func getCommaSeparatedHeaders() -> String { + var allHeaders = "" + for header in headers { + allHeaders += header + "," + } + return allHeaders + } + } struct _HTTPResponse { @@ -240,18 +248,24 @@ public class TestURLSessionServer { } func process(request: _HTTPRequest) -> _HTTPResponse { - if request.method == .GET { - return getResponse(uri: request.uri) + if request.method == .GET || request.method == .POST { + return getResponse(request: request) } else { fatalError("Unsupported method!") } } - func getResponse(uri: String) -> _HTTPResponse { + func getResponse(request: _HTTPRequest) -> _HTTPResponse { + let uri = request.uri if uri == "/country.txt" { let text = capitals[String(uri.characters.dropFirst())]! return _HTTPResponse(response: .OK, headers: "Content-Length: \(text.characters.count)", body: text) } + + if uri == "/requestHeaders" { + let text = request.getCommaSeparatedHeaders() + return _HTTPResponse(response: .OK, headers: "Content-Length: \(text.characters.count)", body: text) + } return _HTTPResponse(response: .OK, body: capitals[String(uri.characters.dropFirst())]!) } diff --git a/TestFoundation/TestNSURLSession.swift b/TestFoundation/TestNSURLSession.swift index 0731bc0f8a..022c601577 100644 --- a/TestFoundation/TestNSURLSession.swift +++ b/TestFoundation/TestNSURLSession.swift @@ -34,6 +34,7 @@ class TestURLSession : XCTestCase { ("test_taskCopy", test_taskCopy), ("test_cancelTask", test_cancelTask), ("test_taskTimeout", test_taskTimeout), + ("test_verifyRequestHeaders", test_verifyRequestHeaders), ] } @@ -66,14 +67,14 @@ class TestURLSession : XCTestCase { serverReady.wait() let urlString = "http://127.0.0.1:\(serverPort)/Nepal" let url = URL(string: urlString)! - let d = DataTask(with: expectation(description: "data task")) + let d = DataTask(with: expectation(description: "data task")) d.run(with: url) waitForExpectations(timeout: 12) if !d.error { XCTAssertEqual(d.capital, "Kathmandu", "test_dataTaskWithURLRequest returned an unexpected result") } } - + func test_dataTaskWithURLCompletionHandler() { let serverReady = ServerSemaphore() globalDispatchQueue.async { @@ -81,7 +82,7 @@ class TestURLSession : XCTestCase { try self.runServer(with: serverReady) } catch { XCTAssertTrue(true) - return + return } } serverReady.wait() @@ -100,7 +101,7 @@ class TestURLSession : XCTestCase { } let httpResponse = response as! HTTPURLResponse? - XCTAssertEqual(200, httpResponse!.statusCode, "HTTP response code is not 200") + XCTAssertEqual(200, httpResponse!.statusCode, "HTTP response code is not 200") expectedResult = String(data: data!, encoding: String.Encoding.utf8)! XCTAssertEqual("Washington, D.C.", expectedResult, "Did not receive expected value") expect.fulfill() @@ -122,7 +123,7 @@ class TestURLSession : XCTestCase { serverReady.wait() let urlString = "http://127.0.0.1:\(serverPort)/Peru" let urlRequest = URLRequest(url: URL(string: urlString)!) - let d = DataTask(with: expectation(description: "data task")) + let d = DataTask(with: expectation(description: "data task")) d.run(with: urlRequest) waitForExpectations(timeout: 12) if !d.error { @@ -176,7 +177,7 @@ class TestURLSession : XCTestCase { } serverReady.wait() let urlString = "http://127.0.0.1:\(serverPort)/country.txt" - let url = URL(string: urlString)! + let url = URL(string: urlString)! let d = DownloadTask(with: expectation(description: "download task with delegate")) d.run(with: url) waitForExpectations(timeout: 12) @@ -251,7 +252,7 @@ class TestURLSession : XCTestCase { task.resume() waitForExpectations(timeout: 12) } - + func test_finishTasksAndInvalidate() { let invalidateExpectation = expectation(description: "URLSession wasn't invalidated") let delegate = SessionDelegate(invalidateExpectation: invalidateExpectation) @@ -266,7 +267,7 @@ class TestURLSession : XCTestCase { session.finishTasksAndInvalidate() waitForExpectations(timeout: 12) } - + func test_taskError() { let url = URL(string: "http://127.0.0.1:\(serverPort)/Nepal")! let session = URLSession(configuration: URLSessionConfiguration.default, @@ -281,22 +282,22 @@ class TestURLSession : XCTestCase { } //should result in Bad URL error task.resume() - + waitForExpectations(timeout: 5) { error in XCTAssertNil(error) - + XCTAssertNotNil(task.error) XCTAssertEqual((task.error as? URLError)?.code, .badURL) } } - + func test_taskCopy() { let url = URL(string: "http://127.0.0.1:\(serverPort)/Nepal")! let session = URLSession(configuration: URLSessionConfiguration.default, delegate: nil, delegateQueue: nil) let task = session.dataTask(with: url) - + XCTAssert(task.isEqual(task.copy())) } @@ -318,7 +319,36 @@ class TestURLSession : XCTestCase { d.cancel() waitForExpectations(timeout: 12) } - + + func test_verifyRequestHeaders() { + let serverReady = ServerSemaphore() + globalDispatchQueue.async { + do { + try self.runServer(with: serverReady) + } catch { + XCTAssertTrue(true) + return + } + } + serverReady.wait() + let config = URLSessionConfiguration.default + config.timeoutIntervalForRequest = 5 + let session = URLSession(configuration: config, delegate: nil, delegateQueue: nil) + var expect = expectation(description: "download task with handler") + var req = URLRequest(url: URL(string: "http://127.0.0.1:\(serverPort)/requestHeaders")!) + let headers = ["header1": "value1"] + req.httpMethod = "POST" + req.allHTTPHeaderFields = headers + var task = session.dataTask(with: req) { (data, _, error) -> Void in + defer { expect.fulfill() } + let headers = String(data: data!, encoding: String.Encoding.utf8)! + XCTAssertNotNil(headers.range(of: "header1: value1")) + } + task.resume() + + waitForExpectations(timeout: 30) + } + func test_taskTimeout() { let serverReady = ServerSemaphore() globalDispatchQueue.async { @@ -340,7 +370,7 @@ class TestURLSession : XCTestCase { XCTAssertNil(error) } task.resume() - + waitForExpectations(timeout: 30) } } @@ -365,7 +395,7 @@ class DataTask : NSObject { public var error = false init(with expectation: XCTestExpectation) { - dataTaskExpectation = expectation + dataTaskExpectation = expectation } func run(with request: URLRequest) { @@ -375,7 +405,7 @@ class DataTask : NSObject { task = session.dataTask(with: request) task.resume() } - + func run(with url: URL) { let config = URLSessionConfiguration.default config.timeoutIntervalForRequest = 8 @@ -405,7 +435,7 @@ extension DataTask : URLSessionTaskDelegate { } self.error = true } -} +} class DownloadTask : NSObject { var totalBytesWritten: Int64 = 0 @@ -435,12 +465,12 @@ class DownloadTask : NSObject { } extension DownloadTask : URLSessionDownloadDelegate { - + public func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) -> Void { self.totalBytesWritten = totalBytesWritten } - + public func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) { do { let attr = try FileManager.default.attributesOfItem(atPath: location.path)