3

I am trying to construct a function in Swift that sends a http HEAD request to a specified url, and measures the response time from the server. I am not concerned with parsing the response, only that I get a 200 from the server. I can do this in python with the requests module:

import requests
def get_latency():
    r = requests.head("http://example.com")
    return r.elapsed.total_seconds()

I assume I will need to use NSURL for this, and I've been able to get this far, but can't figure out the best way to actually send the request...

let url = NSURL (string: "http://example.com")
let request = NSURLRequest(URL: url!)
let started = NSDate()
  <<<Send http HEAD request, verify response>>>  <- need help here
let interval = NSDate().timeIntervalSinceDate(started)
John Sasser
  • 31
  • 1
  • 3
  • I've made this answer today: http://stackoverflow.com/a/35720670/2227743 Is it what you need? – Eric Aya Mar 01 '16 at 17:29
  • well, i tried it in a playground but it doesnt seem to do anything.. when i call the class nothing happens – John Sasser Mar 01 '16 at 17:38
  • For using asynchronous code in a Playground you need to `import XCPlayground` and to declare `XCPlaygroundPage.currentPage.needsIndefiniteExecution = true`. :) – Eric Aya Mar 01 '16 at 17:39
  • ok that works! any idea where I need to start/stop my timers? – John Sasser Mar 01 '16 at 17:50
  • ugh, this is so confusing. the class func and the isOK stuff is really throwing me off. all i need to do is pass a list of URL's, construct and send the head request, validate 200, and measure and return that response time. do you have any idea how I would accomplish that? – John Sasser Mar 01 '16 at 18:22
  • really looking for help with the Swift code... – John Sasser Mar 01 '16 at 18:28
  • i dont care about blocking / UI issues. i am trying to build a very simple function, where i pass a URL, and it does a HEAD request, validates 200 OK, and measures that response time. this is running on swift, but not iOS. Can anyone help??? – John Sasser Mar 01 '16 at 18:30

1 Answers1

4

I wrote this version based on the comments above. I decided to design it as an extension of the URL class. I have tested this code with Swift 4.

extension URL {

    /** Request the http status of the URL resource by sending a "HEAD" request over the network. A nil response means an error occurred. */
    public func requestHTTPStatus(completion: @escaping (_ status: Int?) -> Void) {
        // Adapted from https://stackoverflow.com/a/35720670/7488171
        var request = URLRequest(url: self)
        request.httpMethod = "HEAD"
        let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
            if let httpResponse = response as? HTTPURLResponse, error == nil {
                completion(httpResponse.statusCode)
            } else {
                completion(nil)
            }
        }
        task.resume()
    }

    /** Measure the response time in seconds of an http "HEAD" request to the URL resource. A nil response means an error occurred. */
    public func responseTime(completion: @escaping (TimeInterval?) -> Void) {
        let startTime = DispatchTime.now().uptimeNanoseconds
        requestHTTPStatus { (status) in
            if status != nil {
                let elapsedNanoseconds = DispatchTime.now().uptimeNanoseconds - startTime
                completion(TimeInterval(elapsedNanoseconds)/1e9)
            }
            else {
                completion(nil)
            }
        }
    }
}

Usage:

let testURL = URL(string: "https://www.example.com")
testURL?.responseTime { (time) in
    if let responseTime = time {
        print("Response time: \(responseTime)")
    }
}
Robin Stewart
  • 3,147
  • 20
  • 29