Merge remote-tracking branch 'origin/master' into swift-4.0-branch
diff --git a/Foundation/CharacterSet.swift b/Foundation/CharacterSet.swift
index 79948ec..84fa74c 100644
--- a/Foundation/CharacterSet.swift
+++ b/Foundation/CharacterSet.swift
@@ -94,6 +94,12 @@
     override func isSuperset(of other: CharacterSet) -> Bool {
         return _mapUnmanaged { $0.isSuperset(of: other) }
     }
+
+    override var _cfObject: CFType {
+        // We cannot inherit super's unsafeBitCast(self, to: CFType.self) here, because layout of _SwiftNSCharacterSet
+        // is not compatible with CFCharacterSet. We need to bitcast the underlying NSCharacterSet instead.
+        return _mapUnmanaged { unsafeBitCast($0, to: CFType.self) }
+    }
 }
 
 /**
@@ -469,7 +475,7 @@
     
     /// Returns true if the two `CharacterSet`s are equal.
     public static func ==(lhs : CharacterSet, rhs: CharacterSet) -> Bool {
-        return lhs._wrapped.isEqual(rhs._bridgeToObjectiveC()) // TODO: mlehew - as  NSCharacterSet
+        return lhs._mapUnmanaged { $0.isEqual(rhs) }
     }
 }
 
@@ -503,3 +509,20 @@
     }
     
 }
+
+extension CharacterSet : Codable {
+    private enum CodingKeys : Int, CodingKey {
+        case bitmap
+    }
+    
+    public init(from decoder: Decoder) throws {
+        let container = try decoder.container(keyedBy: CodingKeys.self)
+        let bitmap = try container.decode(Data.self, forKey: .bitmap)
+        self.init(bitmapRepresentation: bitmap)
+    }
+    
+    public func encode(to encoder: Encoder) throws {
+        var container = encoder.container(keyedBy: CodingKeys.self)
+        try container.encode(self.bitmapRepresentation, forKey: .bitmap)
+    }
+}
diff --git a/Foundation/FileHandle.swift b/Foundation/FileHandle.swift
index 645dc5d..28bf722 100644
--- a/Foundation/FileHandle.swift
+++ b/Foundation/FileHandle.swift
@@ -76,7 +76,7 @@
                 fatalError("Unable to fetch current file offset")
             }
             if off_t(statbuf.st_size) > offset {
-                var remaining = size_t(statbuf.st_size - offset)
+                var remaining = size_t(off_t(statbuf.st_size) - offset)
                 remaining = min(remaining, size_t(length))
                 
                 dynamicBuffer = malloc(remaining)
diff --git a/Foundation/NSURLSession/http/HTTPURLProtocol.swift b/Foundation/NSURLSession/http/HTTPURLProtocol.swift
index 0186bf2..b105b15 100644
--- a/Foundation/NSURLSession/http/HTTPURLProtocol.swift
+++ b/Foundation/NSURLSession/http/HTTPURLProtocol.swift
@@ -14,6 +14,8 @@
 
     fileprivate var easyHandle: _EasyHandle!
     fileprivate var totalDownloaded = 0
+    fileprivate var totalUploaded: Int64 = 0
+    fileprivate var requestBodyLength: Int64 = 0
     fileprivate var tempFileURL: URL
 
     public required init(task: URLSessionTask, cachedResponse: CachedURLResponse?, client: URLProtocolClient?) {
@@ -127,6 +129,7 @@
                 set(requestBodyLength: .noBody)
             case (_, .some(let length)):
                 set(requestBodyLength: .length(length))
+                requestBodyLength = Int64(length)
             case (_, .none):
                 set(requestBodyLength: .unknown)
             }
@@ -495,6 +498,16 @@
         }
     }
 
+    fileprivate func notifyDelegate(aboutUploadedData count: Int64) {
+        let session = self.task?.session as! URLSession
+        guard case .taskDelegate(let delegate) = session.behaviour(for: self.task!), self.task is URLSessionUploadTask else { return }
+        totalUploaded += count
+        session.delegateQueue.addOperation {
+            delegate.urlSession(session, task: self.task!, didSendBodyData: count,
+                totalBytesSent: self.totalUploaded, totalBytesExpectedToSend: self.requestBodyLength)
+        }
+    }
+
     func fill(writeBuffer buffer: UnsafeMutableBufferPointer<Int8>) -> _EasyHandle._WriteBufferResult {
         guard case .transferInProgress(let ts) = internalState else { fatalError("Requested to fill write buffer, but transfer isn't in progress.") }
         guard let source = ts.requestBodySource else { fatalError("Requested to fill write buffer, but transfer state has no body source.") }
@@ -503,6 +516,7 @@
             copyDispatchData(data, infoBuffer: buffer)
             let count = data.count
             assert(count > 0)
+            notifyDelegate(aboutUploadedData: Int64(count))
             return .bytes(count)
         case .done:
             return .bytes(0)
diff --git a/TestFoundation/HTTPServer.swift b/TestFoundation/HTTPServer.swift
index 6485523..b129f74 100644
--- a/TestFoundation/HTTPServer.swift
+++ b/TestFoundation/HTTPServer.swift
@@ -330,7 +330,7 @@
     }
 
     func process(request: _HTTPRequest) -> _HTTPResponse {
-        if request.method == .GET || request.method == .POST {
+        if request.method == .GET || request.method == .POST || request.method == .PUT {
             return getResponse(request: request)
         } else {
             fatalError("Unsupported method!")
@@ -339,14 +339,20 @@
 
     func getResponse(request: _HTTPRequest) -> _HTTPResponse {
         let uri = request.uri
+
+        if uri == "/upload" {
+            let text = "Upload completed!"
+            return _HTTPResponse(response: .OK, headers: "Content-Length: \(text.data(using: .utf8)!.count)", body: text)
+        }
+
         if uri == "/country.txt" {
             let text = capitals[String(uri.characters.dropFirst())]!
-            return _HTTPResponse(response: .OK, headers: "Content-Length: \(text.characters.count)", body: text)
+            return _HTTPResponse(response: .OK, headers: "Content-Length: \(text.data(using: .utf8)!.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, headers: "Content-Length: \(text.data(using: .utf8)!.count)", body: text)
         }
 
 	if uri == "/UnitedStates" {
diff --git a/TestFoundation/TestCodable.swift b/TestFoundation/TestCodable.swift
index 9369f67..ba7f7f8 100644
--- a/TestFoundation/TestCodable.swift
+++ b/TestFoundation/TestCodable.swift
@@ -268,6 +268,32 @@
             expectRoundTripEqualityThroughJSON(for: rect)
         }
     }
+    
+    // MARK: - CharacterSet
+    lazy var characterSetValues: [CharacterSet] = [
+        CharacterSet.controlCharacters,
+        CharacterSet.whitespaces,
+        CharacterSet.whitespacesAndNewlines,
+        CharacterSet.decimalDigits,
+        CharacterSet.letters,
+        CharacterSet.lowercaseLetters,
+        CharacterSet.uppercaseLetters,
+        CharacterSet.nonBaseCharacters,
+        CharacterSet.alphanumerics,
+        CharacterSet.decomposables,
+        CharacterSet.illegalCharacters,
+        CharacterSet.punctuationCharacters,
+        CharacterSet.capitalizedLetters,
+        CharacterSet.symbols,
+        CharacterSet.newlines,
+        CharacterSet(charactersIn: "abcd")
+    ]
+    
+    func test_CharacterSet_JSON() {
+        for characterSet in characterSetValues {
+            expectRoundTripEqualityThroughJSON(for: characterSet)
+        }
+    }
 
 }
 
@@ -286,6 +312,7 @@
             ("test_CGPoint_JSON", test_CGPoint_JSON),
             ("test_CGSize_JSON", test_CGSize_JSON),
             ("test_CGRect_JSON", test_CGRect_JSON),
+            ("test_CharacterSet_JSON", test_CharacterSet_JSON),
         ]
     }
 }
diff --git a/TestFoundation/TestNSCharacterSet.swift b/TestFoundation/TestNSCharacterSet.swift
index 51378ae..c56da0d 100644
--- a/TestFoundation/TestNSCharacterSet.swift
+++ b/TestFoundation/TestNSCharacterSet.swift
@@ -1,4 +1,4 @@
-  // This source file is part of the Swift.org open source project
+// This source file is part of the Swift.org open source project
 //
 // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
 // Licensed under Apache License v2.0 with Runtime Library Exception
@@ -7,8 +7,6 @@
 // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
 //
 
-
-
 #if DEPLOYMENT_RUNTIME_OBJC || os(Linux)
 import Foundation
 import XCTest
@@ -17,7 +15,47 @@
 import SwiftXCTest
 #endif
 
+private struct Box: Equatable {
+    private let ns: NSCharacterSet
+    private let swift: CharacterSet
+    
+    private init(ns: NSCharacterSet, swift: CharacterSet) {
+        self.ns = ns
+        self.swift = swift
+    }
+    
+    init(charactersIn string: String) {
+        self.ns = NSCharacterSet(charactersIn: string)
+        self.swift = CharacterSet(charactersIn: string)
+    }
+    
+    static var alphanumerics: Box {
+        return Box(ns: NSCharacterSet.alphanumerics._bridgeToObjectiveC(),
+                   swift: CharacterSet.alphanumerics)
+    }
+    
+    static var decimalDigits: Box {
+        return Box(ns: NSCharacterSet.decimalDigits._bridgeToObjectiveC(),
+                   swift: CharacterSet.decimalDigits)
+    }
 
+    // MARK: Equatable
+
+    static func ==(lhs: Box, rhs: Box) -> Bool {
+        return lhs.ns == rhs.ns
+            && lhs.swift == rhs.swift
+            && lhs.ns._bridgeToSwift() == rhs.ns._bridgeToSwift()
+            && lhs.swift._bridgeToObjectiveC() == rhs.swift._bridgeToObjectiveC()
+            && lhs.ns.isEqual(rhs.ns)
+            && lhs.ns.isEqual(rhs.swift)
+            && lhs.ns.isEqual(rhs.ns._bridgeToSwift())
+            && lhs.ns.isEqual(rhs.swift._bridgeToObjectiveC())
+            && lhs.swift._bridgeToObjectiveC().isEqual(rhs.ns)
+            && lhs.swift._bridgeToObjectiveC().isEqual(rhs.swift)
+            && lhs.swift._bridgeToObjectiveC().isEqual(rhs.ns._bridgeToSwift())
+            && lhs.swift._bridgeToObjectiveC().isEqual(rhs.swift._bridgeToObjectiveC())
+    }
+}
 
 class TestNSCharacterSet : XCTestCase {
     
@@ -283,28 +321,36 @@
         let expected = CharacterSet(charactersIn: "abc")
         XCTAssertEqual(expected, symmetricDifference)
     }
-
+    
     func test_Equatable() {
-        XCTAssertEqual(NSCharacterSet(charactersIn: ""), NSCharacterSet(charactersIn: ""))
-        XCTAssertEqual(NSCharacterSet(charactersIn: "a"), NSCharacterSet(charactersIn: "a"))
-        XCTAssertEqual(NSCharacterSet(charactersIn: "ab"), NSCharacterSet(charactersIn: "ab"))
-
-        XCTAssertNotEqual(NSCharacterSet(charactersIn: "abc"), NSCharacterSet(charactersIn: "123"))
-        XCTAssertNotEqual(NSCharacterSet(charactersIn: "123"), NSCharacterSet(charactersIn: "abc"))
-
-        XCTAssertNotEqual(NSCharacterSet(charactersIn: ""), nil)
-
+        let equalPairs = [
+            ("", ""),
+            ("a", "a"),
+            ("abcde", "abcde"),
+            ("12345", "12345")
+        ]
+        
         /*
          Tests disabled due to CoreFoundation bug?
          These NSCharacterSet pairs are (wrongly?) evaluated to be equal. Same behaviour can be observed on macOS 10.12.
          Interestingly, on iOS 11 Simulator, they are evaluted to be _not_ equal,
          while on iOS 10.3.1 Simulator, they are evaluted to be equal.
          */
-//        XCTAssertNotEqual(NSCharacterSet(charactersIn: "ab"), NSCharacterSet(charactersIn: "abc"))
-//        XCTAssertNotEqual(NSCharacterSet(charactersIn: "abc"), NSCharacterSet(charactersIn: "ab"))
-//        XCTAssertNotEqual(NSCharacterSet(charactersIn: "abc"), NSCharacterSet(charactersIn: ""))
-//        XCTAssertNotEqual(NSCharacterSet(charactersIn: ""), NSCharacterSet(charactersIn: "abc"))
+        let notEqualPairs = [
+            ("abc", "123"),
+//            ("ab", "abc"),
+//            ("abc", "")
+        ]
+        
+        for pair in equalPairs {
+            XCTAssertEqual(Box(charactersIn: pair.0), Box(charactersIn: pair.1))
+        }
+        XCTAssertEqual(Box.alphanumerics, Box.alphanumerics)
+        
+        for pair in notEqualPairs {
+            XCTAssertNotEqual(Box(charactersIn: pair.0), Box(charactersIn: pair.1))
+        }
+        XCTAssertNotEqual(Box.alphanumerics, Box.decimalDigits)
     }
 
 }
-
diff --git a/TestFoundation/TestNSURLSession.swift b/TestFoundation/TestNSURLSession.swift
index 02eb94d..cf44ab6 100644
--- a/TestFoundation/TestNSURLSession.swift
+++ b/TestFoundation/TestNSURLSession.swift
@@ -42,6 +42,7 @@
             ("test_missingContentLengthButStillABody", test_missingContentLengthButStillABody),
             ("test_illegalHTTPServerResponses", test_illegalHTTPServerResponses),
             ("test_dataTaskWithSharedDelegate", test_dataTaskWithSharedDelegate),
+            ("test_simpleUploadWithDelegate", test_simpleUploadWithDelegate),
         ]
     }
     
@@ -443,6 +444,21 @@
         dataTask.resume()
         waitForExpectations(timeout: 20)
     }
+
+    func test_simpleUploadWithDelegate() {
+        let delegate = HTTPUploadDelegate()
+        let session = URLSession(configuration: .default, delegate: delegate, delegateQueue: nil)
+        let urlString = "http://127.0.0.1:\(TestURLSession.serverPort)/upload"
+        var request = URLRequest(url: URL(string: urlString)!)
+        request.httpMethod = "PUT"
+
+        delegate.uploadCompletedExpectation = expectation(description: "PUT \(urlString): Upload data")
+
+        let fileData = Data(count: 16*1024)
+        let task = session.uploadTask(with: request, from: fileData)
+        task.resume()
+        waitForExpectations(timeout: 20)
+    }
 }
 
 class SharedDelegate: NSObject {
@@ -649,3 +665,21 @@
         completionHandler(request)
     }
 }
+
+class HTTPUploadDelegate: NSObject {
+    var uploadCompletedExpectation: XCTestExpectation!
+    var totalBytesSent: Int64 = 0
+}
+
+extension HTTPUploadDelegate: URLSessionTaskDelegate {
+    func urlSession(_ session: URLSession, task: URLSessionTask, didSendBodyData bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64) {
+        self.totalBytesSent = totalBytesSent
+    }
+}
+
+extension HTTPUploadDelegate: URLSessionDataDelegate {
+    func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
+        XCTAssertEqual(self.totalBytesSent, 16*1024)
+        uploadCompletedExpectation.fulfill()
+    }
+}