[swift-users] [Swift3][Linux][URLSession]: Core dump when trying to make simple HTTP request
Quinn "The Eskimo!"
eskimo1 at apple.com
Fri Oct 28 03:08:17 CDT 2016
On 27 Oct 2016, at 13:01, Steven Harms via swift-users <swift-users at swift.org> wrote:
> At this point I'm going to have to confess that I need some help clarifying my model.
Quite. There two real issues here:
* You don’t need to create a queue just to start a request. It’s fine to start the request from any context. Thus, your `queue.async(…)` call is not needed.
* URLSession will run requests asynchronously, thus you need to prevent your process from terminating until the relevant requests are done. In a real program the framework you’re using typically does this for you. In a test project like this you have two options:
- dispatchMain() — That is, just add a line containing `dispatchMain()` to the bottom of your ‘main’ code.
- synthetic synchronous — Traditionally this is done using dispatch semaphores; I won’t show it here because a) you’ll find lots of example of it, and b) it’s not recommended, for obscure reasons related to QoS propagation.
> 1. How did point "y" get fired twice? Or how did it happen not at all?
I ran your code verbatim (except that I added a `dispatchMain()` at the end) on my Mac running 10.11.6, built with Xcode 8, and I didn’t see the second copy of `y`.
> 2. How did my callback for dataTask *never* fire? Even if the connection task *failed* the handler ought have fired, no?
Because the process terminated before the request finished.
> 3. I didn't want to bring this whole queue business into the picture, but it appears that without it the program exits before the handler has a chance to fire.
Correct.
> 4. Changing to a queue.sync from queue.async consistently produces the output I expect, but does not fire my completionHandler still.
Right, because that’s about how the request /starts/, not about how the request’s completion handler runs.
> 5. Is there a canonical reference for doing this simplest of tasks?
Here’s a minimal example of a command line tool that fetches a URL.
---------------------------------------------------------------------------
import Foundation
URLSession.shared.dataTask(with: URL(string: "http://www.example.com")!) { (data, response, error) in
if let error = error {
print("error: \(error)")
exit(1)
} else {
let response = response as! HTTPURLResponse
let data = data!
print("status: \(response.statusCode)")
for (key, value) in response.allHeaderFields {
print("header: \(key) = \(value)")
}
print("body: \(data as NSData)")
exit(0)
}
}.resume()
dispatchMain()
---------------------------------------------------------------------------
When I run this (same environment as above) I get this:
status: 200
header: Date = Fri, 28 Oct 2016 08:02:04 GMT
header: Content-Length = 606
header: Etag = "359670651"
header: x-ec-custom-error = 1
header: Last-Modified = Fri, 09 Aug 2013 23:54:35 GMT
header: Accept-Ranges = bytes
header: Vary = Accept-Encoding
header: X-Cache = HIT
header: Content-Type = text/html
header: Expires = Fri, 04 Nov 2016 08:02:04 GMT
header: Server = ECS (ewr/15BD)
header: Content-Encoding = gzip
header: Cache-Control = max-age=604800
body: <3c21646f 63747970 65206874 6d6c3e0a 3c68746d …>
The only weird thing in the code above is that `key` is of type `AnyHashable` rather than `String`. That’s because the type of `allHeaderFields` is wrong <rdar://problem/27805863>.
Alas, I’m not set up to run this on Linux )-:
Share and Enjoy
--
Quinn "The Eskimo!" <http://www.apple.com/developer/>
Apple Developer Relations, Developer Technical Support, Core OS/Hardware
More information about the swift-users
mailing list