Don't locally enforce a max backup upload size limit
This commit is contained in:
parent
f23120e787
commit
92e5cca0f1
@ -200,7 +200,21 @@ public class BackupArchiveManagerImpl: BackupArchiveManager {
|
||||
localAci: localIdentifiers.aci,
|
||||
auth: auth
|
||||
)
|
||||
let form = try await backupRequestManager.fetchBackupUploadForm(auth: backupAuth)
|
||||
let form: Upload.Form
|
||||
do {
|
||||
form = try await backupRequestManager.fetchBackupUploadForm(
|
||||
backupByteLength: metadata.encryptedDataLength,
|
||||
auth: backupAuth
|
||||
)
|
||||
} catch let error {
|
||||
switch (error as? BackupArchive.Response.BackupUploadFormError) {
|
||||
case .tooLarge:
|
||||
Logger.warn("Backup too large! \(metadata.encryptedDataLength)")
|
||||
default:
|
||||
break
|
||||
}
|
||||
throw error
|
||||
}
|
||||
let result = try await attachmentUploadManager.uploadBackup(
|
||||
localUploadMetadata: metadata,
|
||||
form: form,
|
||||
|
||||
@ -391,6 +391,7 @@ private class BackupRequestManagerMock: BackupRequestManager {
|
||||
}
|
||||
|
||||
func fetchBackupUploadForm(
|
||||
backupByteLength: UInt32,
|
||||
auth: SignalServiceKit.BackupServiceAuth
|
||||
) async throws -> SignalServiceKit.Upload.Form {
|
||||
fatalError("Unimplemented")
|
||||
|
||||
@ -76,6 +76,15 @@ public extension BackupArchive {
|
||||
case outOfCapacity = 413
|
||||
case rateLimited = 429
|
||||
}
|
||||
|
||||
public enum BackupUploadFormError: Int, Error {
|
||||
case badArgument = 400
|
||||
case invalidAuth = 401
|
||||
case forbidden = 403
|
||||
/// The backup file is too large (as reported by us in `backupByteLength`.
|
||||
case tooLarge = 413
|
||||
case rateLimited = 429
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -95,7 +104,11 @@ public protocol BackupRequestManager {
|
||||
forceRefreshUnlessCachedPaidCredential: Bool
|
||||
) async throws -> BackupServiceAuth
|
||||
|
||||
func fetchBackupUploadForm(auth: BackupServiceAuth) async throws -> Upload.Form
|
||||
/// - parameter backupByteLength: length in bytes of the encrypted backup file we will upload
|
||||
func fetchBackupUploadForm(
|
||||
backupByteLength: UInt32,
|
||||
auth: BackupServiceAuth
|
||||
) async throws -> Upload.Form
|
||||
|
||||
func fetchBackupMediaAttachmentUploadForm(auth: BackupServiceAuth) async throws -> Upload.Form
|
||||
|
||||
@ -203,12 +216,31 @@ public struct BackupRequestManagerImpl: BackupRequestManager {
|
||||
// MARK: - Upload Forms
|
||||
|
||||
/// CDN upload form for uploading a backup
|
||||
public func fetchBackupUploadForm(auth: BackupServiceAuth) async throws -> Upload.Form {
|
||||
public func fetchBackupUploadForm(
|
||||
backupByteLength: UInt32,
|
||||
auth: BackupServiceAuth
|
||||
) async throws -> Upload.Form {
|
||||
owsAssertDebug(auth.type == .messages)
|
||||
return try await executeBackupService(
|
||||
auth: auth,
|
||||
requestFactory: OWSRequestFactory.backupUploadFormRequest(auth:)
|
||||
)
|
||||
do {
|
||||
return try await executeBackupService(
|
||||
auth: auth,
|
||||
requestFactory: { auth in
|
||||
OWSRequestFactory.backupUploadFormRequest(
|
||||
backupByteLength: backupByteLength,
|
||||
auth: auth
|
||||
)
|
||||
}
|
||||
)
|
||||
} catch let error {
|
||||
if
|
||||
let httpStatusCode = error.httpStatusCode,
|
||||
let error = BackupArchive.Response.BackupUploadFormError(rawValue: httpStatusCode)
|
||||
{
|
||||
throw error
|
||||
} else {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// CDN upload form for uploading backup media
|
||||
|
||||
@ -20,9 +20,15 @@ extension OWSRequestFactory {
|
||||
return request
|
||||
}
|
||||
|
||||
public static func backupUploadFormRequest(auth: BackupServiceAuth) -> TSRequest {
|
||||
/// - parameter backupByteLength: length in bytes of the encrypted backup file we will upload
|
||||
public static func backupUploadFormRequest(
|
||||
backupByteLength: UInt32,
|
||||
auth: BackupServiceAuth
|
||||
) -> TSRequest {
|
||||
var urlComps = URLComponents(string: "v1/archives/upload/form")!
|
||||
urlComps.queryItems = [URLQueryItem(name: "uploadLength", value: "\(backupByteLength)")]
|
||||
var request = TSRequest(
|
||||
url: URL(string: "v1/archives/upload/form")!,
|
||||
url: urlComps.url!,
|
||||
method: "GET",
|
||||
parameters: nil
|
||||
)
|
||||
|
||||
@ -124,6 +124,11 @@ public enum Upload {
|
||||
/// Does NOT take into account current backup plan state; just per-attachment
|
||||
/// backup eligibility.
|
||||
public let attachmentByteSize: UInt64
|
||||
|
||||
/// We don't enforce a size limit locally for backups; we let the server
|
||||
/// enforce the limit and fail the upload if we surpass it.
|
||||
public static var maxUploadSizeBytes: UInt { .max }
|
||||
public static var maxPlaintextSizeBytes: UInt { .max }
|
||||
}
|
||||
|
||||
public struct LocalUploadMetadata: AttachmentUploadMetadata, Codable {
|
||||
@ -143,6 +148,9 @@ public enum Upload {
|
||||
public let plaintextDataLength: UInt32
|
||||
|
||||
public var isReusedTransitTierUpload: Bool { false }
|
||||
|
||||
public static var maxUploadSizeBytes: UInt { OWSMediaUtils.kMaxAttachmentUploadSizeBytes }
|
||||
public static var maxPlaintextSizeBytes: UInt { OWSMediaUtils.kMaxFileSizeGeneric }
|
||||
}
|
||||
|
||||
public struct LinkNSyncUploadMetadata: UploadMetadata {
|
||||
@ -150,6 +158,11 @@ public enum Upload {
|
||||
public let fileUrl: URL
|
||||
/// The length of the file.
|
||||
public let encryptedDataLength: UInt32
|
||||
|
||||
/// We don't enforce a size limit locally for backups; we let the server
|
||||
/// enforce the limit and fail the upload if we surpass it.
|
||||
public static var maxUploadSizeBytes: UInt { .max }
|
||||
public static var maxPlaintextSizeBytes: UInt { .max }
|
||||
}
|
||||
|
||||
public struct ReusedUploadMetadata: AttachmentUploadMetadata {
|
||||
@ -170,6 +183,9 @@ public enum Upload {
|
||||
public let encryptedDataLength: UInt32
|
||||
|
||||
public var isReusedTransitTierUpload: Bool { false }
|
||||
|
||||
public static var maxUploadSizeBytes: UInt { OWSMediaUtils.kMaxAttachmentUploadSizeBytes }
|
||||
public static var maxPlaintextSizeBytes: UInt { OWSMediaUtils.kMaxFileSizeGeneric }
|
||||
}
|
||||
|
||||
public struct Result<Metadata: UploadMetadata> {
|
||||
@ -234,8 +250,8 @@ extension Upload.LocalUploadMetadata {
|
||||
let plaintextLength = UInt32(plaintextLengthRaw)
|
||||
|
||||
guard
|
||||
plaintextLength <= OWSMediaUtils.kMaxFileSizeGeneric,
|
||||
length <= OWSMediaUtils.kMaxAttachmentUploadSizeBytes
|
||||
plaintextLength <= Self.maxPlaintextSizeBytes,
|
||||
length <= Self.maxUploadSizeBytes
|
||||
else {
|
||||
throw OWSAssertionError("Data is too large: \(length).")
|
||||
}
|
||||
|
||||
@ -8,6 +8,9 @@ import Foundation
|
||||
/// Applies to attachment uploads, backup proto uploads, etc.
|
||||
public protocol UploadMetadata {
|
||||
var encryptedDataLength: UInt32 { get }
|
||||
|
||||
static var maxUploadSizeBytes: UInt { get }
|
||||
static var maxPlaintextSizeBytes: UInt { get }
|
||||
}
|
||||
|
||||
/// Includes extra info like digest for validation.
|
||||
|
||||
@ -130,7 +130,10 @@ class _AttachmentUploadManager_BackupRequestManagerMock: BackupRequestManager {
|
||||
|
||||
func registerBackupKeys(localAci: Aci, auth: ChatServiceAuth) async throws {}
|
||||
|
||||
func fetchBackupUploadForm(auth: BackupServiceAuth) async throws -> Upload.Form {
|
||||
func fetchBackupUploadForm(
|
||||
backupByteLength: UInt32,
|
||||
auth: BackupServiceAuth
|
||||
) async throws -> Upload.Form {
|
||||
fatalError("Unimplemented for tests")
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user