Last active
April 16, 2019 16:18
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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