[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.


> 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)")
    } 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)")

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