From 7f7f2bc01a272a3f5ebb1036d4d68a76706410d8 Mon Sep 17 00:00:00 2001 From: Swizzlr Date: Thu, 9 Mar 2017 18:25:15 +0000 Subject: [PATCH 1/2] Ensure curl headers are not overwritten but merged in special case. --- Foundation/NSURLSession/NSURLSessionTask.swift | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Foundation/NSURLSession/NSURLSessionTask.swift b/Foundation/NSURLSession/NSURLSessionTask.swift index ad7b6b24b1..a50fc20436 100644 --- a/Foundation/NSURLSession/NSURLSessionTask.swift +++ b/Foundation/NSURLSession/NSURLSessionTask.swift @@ -548,7 +548,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) //Options unavailable on Ubuntu 14.04 (libcurl 7.36) //TODO: Introduce something like an #if @@ -564,8 +573,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"]) } } } From 1f745ce0877fee9be94b0490f609865afd9caac3 Mon Sep 17 00:00:00 2001 From: Pushkar Kulkarni Date: Fri, 10 Mar 2017 19:48:05 +0530 Subject: [PATCH 2/2] test for 915 --- TestFoundation/HTTPServer.swift | 20 ++++- TestFoundation/TestNSURLSession.swift | 110 ++++++++++++++++++++++---- 2 files changed, 110 insertions(+), 20 deletions(-) diff --git a/TestFoundation/HTTPServer.swift b/TestFoundation/HTTPServer.swift index 5b032a247c..7874d39b4e 100644 --- a/TestFoundation/HTTPServer.swift +++ b/TestFoundation/HTTPServer.swift @@ -152,6 +152,14 @@ struct _HTTPRequest { body = lines.last! } + public func getCommaSeparatedHeaders() -> String { + var allHeaders = "" + for header in headers { + allHeaders += header + "," + } + return allHeaders + } + } struct _HTTPResponse { @@ -195,18 +203,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 d86e749515..fcb5ac1a08 100644 --- a/TestFoundation/TestNSURLSession.swift +++ b/TestFoundation/TestNSURLSession.swift @@ -32,6 +32,9 @@ class TestURLSession : XCTestCase { ("test_finishTaskAndInvalidate", test_finishTasksAndInvalidate), ("test_taskError", test_taskError), ("test_taskCopy", test_taskCopy), + ("test_cancelTask", test_cancelTask), + ("test_taskTimeout", test_taskTimeout), + ("test_verifyRequestHeaders", test_verifyRequestHeaders), ] } @@ -64,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 { @@ -79,7 +82,7 @@ class TestURLSession : XCTestCase { try self.runServer(with: serverReady) } catch { XCTAssertTrue(true) - return + return } } serverReady.wait() @@ -98,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() @@ -120,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 { @@ -174,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) @@ -249,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) @@ -264,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, @@ -279,24 +282,97 @@ 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())) } + + func test_cancelTask() { + let serverReady = ServerSemaphore() + globalDispatchQueue.async { + do { + try self.runServer(with: serverReady) + } catch { + XCTAssertTrue(true) + return + } + } + serverReady.wait() + let url = URL(string: "http://127.0.0.1:\(serverPort)/Peru")! + let d = DataTask(with: expectation(description: "Task to be canceled")) + d.cancelExpectation = expectation(description: "URLSessionTask wasn't canceled") + d.run(with: url) + 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 { + do { + try self.runServer(with: serverReady, startDelay: 3, sendDelay: 3, bodyChunks: 3) + } 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") + let req = URLRequest(url: URL(string: "http://127.0.0.1:\(serverPort)/Peru")!) + var task = session.dataTask(with: req) { (data, _, error) -> Void in + defer { expect.fulfill() } + XCTAssertNil(error) + } + task.resume() + + waitForExpectations(timeout: 30) + } } class SessionDelegate: NSObject, URLSessionDelegate { @@ -317,7 +393,7 @@ class DataTask : NSObject { public var error = false init(with expectation: XCTestExpectation) { - dataTaskExpectation = expectation + dataTaskExpectation = expectation } func run(with request: URLRequest) { @@ -327,7 +403,7 @@ class DataTask : NSObject { task = session.dataTask(with: request) task.resume() } - + func run(with url: URL) { let config = URLSessionConfiguration.default config.timeoutIntervalForRequest = 8 @@ -351,7 +427,7 @@ extension DataTask : URLSessionTaskDelegate { dataTaskExpectation.fulfill() self.error = true } -} +} class DownloadTask : NSObject { var totalBytesWritten: Int64 = 0 @@ -381,12 +457,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)