Skip to content

Ensure curl headers are not overwritten but merged in special case. #915

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions Foundation/NSURLSession/NSURLSessionTask.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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"])
}
}
}
Expand Down
20 changes: 17 additions & 3 deletions TestFoundation/HTTPServer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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())]!)
}

Expand Down
110 changes: 93 additions & 17 deletions TestFoundation/TestNSURLSession.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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),
]
}

Expand Down Expand Up @@ -64,22 +67,22 @@ 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 {
do {
try self.runServer(with: serverReady)
} catch {
XCTAssertTrue(true)
return
return
}
}
serverReady.wait()
Expand All @@ -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()
Expand All @@ -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 {
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand All @@ -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,
Expand All @@ -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 {
Expand All @@ -317,7 +393,7 @@ class DataTask : NSObject {
public var error = false

init(with expectation: XCTestExpectation) {
dataTaskExpectation = expectation
dataTaskExpectation = expectation
}

func run(with request: URLRequest) {
Expand All @@ -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
Expand All @@ -351,7 +427,7 @@ extension DataTask : URLSessionTaskDelegate {
dataTaskExpectation.fulfill()
self.error = true
}
}
}

class DownloadTask : NSObject {
var totalBytesWritten: Int64 = 0
Expand Down Expand Up @@ -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)
Expand Down