Segment proxied content downloads.

pull/1/head
Matthew Chen 6 years ago
parent db15ff9a26
commit 23980152fc

@ -5,9 +5,11 @@
import Foundation import Foundation
import SignalServiceKit import SignalServiceKit
@objc class GiphyDownloader: ProxiedContentDownloader { @objc
public class GiphyDownloader: ProxiedContentDownloader {
// MARK: - Properties // MARK: - Properties
@objc
public static let giphyDownloader = GiphyDownloader(downloadFolderName: "GIFs") public static let giphyDownloader = GiphyDownloader(downloadFolderName: "GIFs")
} }

@ -345,7 +345,7 @@ public class OWSLinkPreview: MTLModel {
return false return false
} }
return whitelistedDomain(forUrl: url, return whitelistedDomain(forUrl: url,
domainWhitelist: OWSLinkPreview.linkDomainWhitelist + OWSLinkPreview.mediaDomainWhitelist) != nil domainWhitelist: OWSLinkPreview.linkDomainWhitelist + OWSLinkPreview.mediaDomainWhitelist) != nil
} }
private class func whitelistedDomain(forUrl url: URL, domainWhitelist: [String]) -> String? { private class func whitelistedDomain(forUrl url: URL, domainWhitelist: [String]) -> String? {
@ -462,7 +462,7 @@ public class OWSLinkPreview: MTLModel {
completion(cachedInfo) completion(cachedInfo)
return return
} }
downloadContents(ofUrl: previewUrl, completion: { (data) in downloadLink(url: previewUrl, completion: { (data) in
DispatchQueue.global().async { DispatchQueue.global().async {
guard let data = data else { guard let data = data else {
completion(nil) completion(nil)
@ -488,9 +488,9 @@ public class OWSLinkPreview: MTLModel {
} }
} }
private class func downloadContents(ofUrl url: String, private class func downloadLink(url: String,
completion: @escaping (Data?) -> Void, completion: @escaping (Data?) -> Void,
remainingRetries: UInt = 3) { remainingRetries: UInt = 3) {
Logger.verbose("url: \(url)") Logger.verbose("url: \(url)")
@ -536,9 +536,46 @@ public class OWSLinkPreview: MTLModel {
completion(nil) completion(nil)
return return
} }
OWSLinkPreview.downloadContents(ofUrl: url, completion: completion, remainingRetries: remainingRetries - 1) OWSLinkPreview.downloadLink(url: url, completion: completion, remainingRetries: remainingRetries - 1)
}) })
}
private class func downloadImage(url urlString: String,
completion: @escaping (Data?) -> Void) {
Logger.verbose("url: \(urlString)")
guard let url = URL(string: urlString) else {
Logger.error("Could not parse URL.")
return completion(nil)
}
guard let assetDescription = ProxiedContentAssetDescription(url: url as NSURL) else {
Logger.error("Could not create asset description.")
return completion(nil)
}
DispatchQueue.main.async {
_ = ProxiedContentDownloader.defaultDownloader.requestAsset(assetDescription: assetDescription,
priority: .high,
success: { (_, asset) in
DispatchQueue.global().async {
do {
let data = try Data(contentsOf: URL(fileURLWithPath: asset.filePath))
completion(data)
} catch {
owsFailDebug("Could not load asset data: \(type(of: asset.filePath)).")
completion(nil)
}
}
}, failure: { (_) in
DispatchQueue.global().async {
Logger.verbose("Error downloading asset")
completion(nil)
}
})
}
} }
private class func isRetryable(error: Error) -> Bool { private class func isRetryable(error: Error) -> Bool {
@ -599,38 +636,38 @@ public class OWSLinkPreview: MTLModel {
let kValidMimeTypes = [ let kValidMimeTypes = [
OWSMimeTypeImagePng, OWSMimeTypeImagePng,
OWSMimeTypeImageJpeg OWSMimeTypeImageJpeg
] ]
guard kValidMimeTypes.contains(imageMimeType) else { guard kValidMimeTypes.contains(imageMimeType) else {
Logger.error("Image URL has invalid content type: \(imageMimeType).") Logger.error("Image URL has invalid content type: \(imageMimeType).")
return completion(OWSLinkPreviewDraft(urlString: linkUrlString, title: title)) return completion(OWSLinkPreviewDraft(urlString: linkUrlString, title: title))
} }
downloadContents(ofUrl: imageUrlString, downloadImage(url: imageUrlString,
completion: { (imageData) in completion: { (imageData) in
guard let imageData = imageData else { guard let imageData = imageData else {
Logger.error("Could not download image.") Logger.error("Could not download image.")
return completion(OWSLinkPreviewDraft(urlString: linkUrlString, title: title)) return completion(OWSLinkPreviewDraft(urlString: linkUrlString, title: title))
} }
let imageFilePath = OWSFileSystem.temporaryFilePath(withFileExtension: imageFileExtension) let imageFilePath = OWSFileSystem.temporaryFilePath(withFileExtension: imageFileExtension)
do { do {
try imageData.write(to: NSURL.fileURL(withPath: imageFilePath), options: .atomicWrite) try imageData.write(to: NSURL.fileURL(withPath: imageFilePath), options: .atomicWrite)
} catch let error as NSError { } catch let error as NSError {
owsFailDebug("file write failed: \(imageFilePath), \(error)") owsFailDebug("file write failed: \(imageFilePath), \(error)")
return completion(OWSLinkPreviewDraft(urlString: linkUrlString, title: title))
}
// NOTE: imageSize(forFilePath:...) will call ows_isValidImage(...).
let imageSize = NSData.imageSize(forFilePath: imageFilePath, mimeType: imageMimeType)
let kMaxImageSize: CGFloat = 2048
guard imageSize.width > 0,
imageSize.height > 0,
imageSize.width < kMaxImageSize,
imageSize.height < kMaxImageSize else {
Logger.error("Image has invalid size: \(imageSize).")
return completion(OWSLinkPreviewDraft(urlString: linkUrlString, title: title)) return completion(OWSLinkPreviewDraft(urlString: linkUrlString, title: title))
} }
// NOTE: imageSize(forFilePath:...) will call ows_isValidImage(...).
let imageSize = NSData.imageSize(forFilePath: imageFilePath, mimeType: imageMimeType)
let kMaxImageSize: CGFloat = 2048
guard imageSize.width > 0,
imageSize.height > 0,
imageSize.width < kMaxImageSize,
imageSize.height < kMaxImageSize else {
Logger.error("Image has invalid size: \(imageSize).")
return completion(OWSLinkPreviewDraft(urlString: linkUrlString, title: title))
}
let linkPreviewDraft = OWSLinkPreviewDraft(urlString: linkUrlString, title: title, imageFilePath: imageFilePath) let linkPreviewDraft = OWSLinkPreviewDraft(urlString: linkUrlString, title: title, imageFilePath: imageFilePath)
completion(linkPreviewDraft) completion(linkPreviewDraft)
}) })
} }

@ -435,6 +435,7 @@ open class ProxiedContentDownloader: NSObject, URLSessionTaskDelegate, URLSessio
// MARK: - Properties // MARK: - Properties
@objc
public static let defaultDownloader = ProxiedContentDownloader(downloadFolderName: "proxiedContent") public static let defaultDownloader = ProxiedContentDownloader(downloadFolderName: "proxiedContent")
private let downloadFolderName: String private let downloadFolderName: String
@ -462,8 +463,11 @@ open class ProxiedContentDownloader: NSObject, URLSessionTaskDelegate, URLSessio
AssertIsOnMainThread() AssertIsOnMainThread()
let configuration = ContentProxy.sessionConfiguration() let configuration = ContentProxy.sessionConfiguration()
// Don't use any caching to protect privacy of these requests.
configuration.urlCache = nil configuration.urlCache = nil
configuration.requestCachePolicy = .reloadIgnoringCacheData configuration.requestCachePolicy = .reloadIgnoringCacheData
configuration.httpMaximumConnectionsPerHost = 10 configuration.httpMaximumConnectionsPerHost = 10
let session = URLSession(configuration: configuration, let session = URLSession(configuration: configuration,
delegate: self, delegate: self,

Loading…
Cancel
Save