Skip to content

Instantly share code, notes, and snippets.

@shaps80
Last active April 16, 2019 16:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shaps80/0770efefc8824e1aef954dc4043aa450 to your computer and use it in GitHub Desktop.
Save shaps80/0770efefc8824e1aef954dc4043aa450 to your computer and use it in GitHub Desktop.
Expands a URL by doing a HEAD request against its URL and returning the redirected URL, or the original if the URL wasn't shortened. You can call `expand(url:)` multiple times and the queue guarantees that only 1 request will be triggered at a time, in calling order.
import Foundation
final class URLExpander: NSObject, URLSessionTaskDelegate {
private lazy var session: URLSession = {
let config = URLSessionConfiguration.default
return URLSession(configuration: config, delegate: self, delegateQueue: queue)
}()
private let queue: OperationQueue
private var handlers: [URL: (Result<URL, Error>) -> Void] = [:]
override init() {
queue = OperationQueue()
queue.maxConcurrentOperationCount = 1
}
func expand(url: URL, completion: @escaping (Result<URL, Error>) -> Void) {
handlers[url] = completion
var request = URLRequest(url: url)
request.httpMethod = "HEAD"
request.cachePolicy = .returnCacheDataElseLoad
request.allowsCellularAccess = true
session.dataTask(with: request).resume()
}
func urlSession(_ session: URLSession, task: URLSessionTask, willPerformHTTPRedirection response: HTTPURLResponse, newRequest request: URLRequest, completionHandler: @escaping (URLRequest?) -> Void) {
defer {
completionHandler(nil)
}
guard let shortened = task.currentRequest?.url,
let handler = handlers[shortened],
let expanded = request.url else {
return
}
handler(.success(expanded))
handlers[shortened] = nil
}
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
guard let shortened = task.currentRequest?.url,
let handler = handlers[shortened] else {
return
}
if let error = error {
handler(.failure(error))
} else {
// the url wasn't shortened, we can just return it
handler(.success(shortened))
}
handlers[shortened] = nil
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment