Merge pull request #1203 from johnno1962e/swift-4.0-branch

diff --git a/Foundation/URLSession/URLSessionTask.swift b/Foundation/URLSession/URLSessionTask.swift
index 1115ef5..7dcc66e 100644
--- a/Foundation/URLSession/URLSessionTask.swift
+++ b/Foundation/URLSession/URLSessionTask.swift
@@ -29,8 +29,8 @@
     internal var suspendCount = 1
     internal var session: URLSessionProtocol! //change to nil when task completes
     internal let body: _Body
-    fileprivate var _protocol: URLProtocol! = nil
-    
+    fileprivate var _protocol: URLProtocol? = nil
+
     /// All operations must run on this queue.
     internal let workQueue: DispatchQueue 
     /// Using dispatch semaphore to make public attributes thread safe.
@@ -200,8 +200,8 @@
             self.workQueue.async {
                 let urlError = URLError(_nsError: NSError(domain: NSURLErrorDomain, code: NSURLErrorCancelled, userInfo: nil))
                 self.error = urlError
-                self._protocol.stopLoading()
-                self._protocol.client?.urlProtocol(self._protocol, didFailWithError: urlError)
+                self._protocol?.stopLoading()
+                self._protocol?.client?.urlProtocol(self._protocol!, didFailWithError: urlError)
             }
         }
     }
@@ -263,7 +263,7 @@
             
             if self.suspendCount == 1 {
                 self.workQueue.async {
-                    self._protocol.stopLoading()
+                    self._protocol?.stopLoading()
                 }
             }
         }
@@ -278,7 +278,21 @@
             self.updateTaskState()
             if self.suspendCount == 0 {
                 self.workQueue.async {
-                    self._protocol.startLoading()
+                    if let _protocol = self._protocol {
+                        _protocol.startLoading()
+                    }
+                    else if self.error == nil {
+                        var userInfo: [String: Any] = [NSLocalizedDescriptionKey: "unsupported URL"]
+                        if let url = self.originalRequest?.url {
+                            userInfo[NSURLErrorFailingURLErrorKey] = url
+                            userInfo[NSURLErrorFailingURLStringErrorKey] = url.absoluteString
+                        }
+                        let urlError = URLError(_nsError: NSError(domain: NSURLErrorDomain,
+                                                                  code: NSURLErrorUnsupportedURL,
+                                                                  userInfo: userInfo))
+                        self.error = urlError
+                        _ProtocolClient().urlProtocol(task: self, didFailWithError: urlError)
+                    }
                 }
             }
         }
@@ -573,6 +587,7 @@
                 session.taskRegistry.remove(task)
             }
         }
+        task._protocol = nil
     }
 
     func urlProtocol(_ protocol: URLProtocol, didCancel challenge: URLAuthenticationChallenge) {
@@ -600,6 +615,10 @@
 
     func urlProtocol(_ protocol: URLProtocol, didFailWithError error: Error) {
         guard let task = `protocol`.task else { fatalError() }
+        urlProtocol(task: task, didFailWithError: error)
+    }
+
+    func urlProtocol(task: URLSessionTask, didFailWithError error: Error) {
         guard let session = task.session as? URLSession else { fatalError() }
         switch session.behaviour(for: task) {
         case .taskDelegate(let delegate):
@@ -624,6 +643,7 @@
                 session.taskRegistry.remove(task)
             }
         }
+        task._protocol = nil
     }
 
     func urlProtocol(_ protocol: URLProtocol, cachedResponseIsValid cachedResponse: CachedURLResponse) {
diff --git a/Foundation/URLSession/http/HTTPURLProtocol.swift b/Foundation/URLSession/http/HTTPURLProtocol.swift
index 307a64f..78aff84 100644
--- a/Foundation/URLSession/http/HTTPURLProtocol.swift
+++ b/Foundation/URLSession/http/HTTPURLProtocol.swift
@@ -13,13 +13,14 @@
 internal class _HTTPURLProtocol: URLProtocol {
 
     fileprivate var easyHandle: _EasyHandle!
-    fileprivate var tempFileURL: URL
+    fileprivate lazy var tempFileURL: URL = {
+        let fileName = NSTemporaryDirectory() + NSUUID().uuidString + ".tmp"
+        _ = FileManager.default.createFile(atPath: fileName, contents: nil)
+        return URL(fileURLWithPath: fileName)
+    }()
 
     public required init(task: URLSessionTask, cachedResponse: CachedURLResponse?, client: URLProtocolClient?) {
         self.internalState = _InternalState.initial
-        let fileName = NSTemporaryDirectory() + NSUUID().uuidString + ".tmp"
-        _ = FileManager.default.createFile(atPath: fileName, contents: nil)
-        self.tempFileURL = URL(fileURLWithPath: fileName)
         super.init(request: task.originalRequest!, cachedResponse: cachedResponse, client: client)
         self.task = task
         self.easyHandle = _EasyHandle(delegate: self)
@@ -27,9 +28,6 @@
 
     public required init(request: URLRequest, cachedResponse: CachedURLResponse?, client: URLProtocolClient?) {
         self.internalState = _InternalState.initial
-        let fileName = NSTemporaryDirectory() + NSUUID().uuidString + ".tmp"
-        _ = FileManager.default.createFile(atPath: fileName, contents: nil)
-        self.tempFileURL = URL(fileURLWithPath: fileName)
         super.init(request: request, cachedResponse: cachedResponse, client: client)
         self.easyHandle = _EasyHandle(delegate: self)
     }