Respond to CR.

// FREEBIE
pull/1/head
Matthew Chen 9 years ago
parent 8231f79977
commit 04a3e4323c

@ -237,38 +237,21 @@ NS_ASSUME_NONNULL_BEGIN
const long kMaxDownloadSize = 150 * 1024 * 1024; const long kMaxDownloadSize = 150 * 1024 * 1024;
// TODO stream this download rather than storing the entire blob. // TODO stream this download rather than storing the entire blob.
__block NSURLSessionDataTask *task = nil; __block NSURLSessionDataTask *task = nil;
// We only need to check the content length header once.
__block BOOL hasCheckedContentLength = NO; __block BOOL hasCheckedContentLength = NO;
task = [manager GET:location task = [manager GET:location
parameters:nil parameters:nil
progress:^(NSProgress *_Nonnull progress) { progress:^(NSProgress *_Nonnull progress) {
// Once we've received some bytes of the download, check the content length OWSAssert(progress != nil);
// header for the download.
if (progress.completedUnitCount > 0 && !hasCheckedContentLength) { // Don't do anything until we've received at least one byte of data.
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)task.response; if (progress.completedUnitCount < 1) {
if ([httpResponse isKindOfClass:[NSHTTPURLResponse class]]) {
NSDictionary *headers = [httpResponse allHeaderFields];
if ([headers isKindOfClass:[NSDictionary class]]) {
NSString *contentLength = headers[@"Content-Length"];
if ([contentLength isKindOfClass:[NSString class]]) {
if (contentLength.longLongValue > 0) {
if (contentLength.longLongValue <= kMaxDownloadSize) {
// This response has a valid content length that is less
// than our max download size. Proceed with the download.
hasCheckedContentLength = YES;
return; return;
} }
}
} void (^abortDownload)() = ^{
}
}
// If the task doesn't exist, or doesn't have a response, or is missing
// the expected headers, or has an invalid or oversize content length, etc.,
// abort the download.
OWSAssert(0); OWSAssert(0);
[task cancel]; [task cancel];
} else { };
OWSAssert(progress != nil);
if (progress.totalUnitCount > kMaxDownloadSize || progress.completedUnitCount > kMaxDownloadSize) { if (progress.totalUnitCount > kMaxDownloadSize || progress.completedUnitCount > kMaxDownloadSize) {
// A malicious service might send a misleading content length header, // A malicious service might send a misleading content length header,
@ -276,10 +259,61 @@ NS_ASSUME_NONNULL_BEGIN
// //
// If the current downloaded bytes or the expected total byes // If the current downloaded bytes or the expected total byes
// exceed the max download size, abort the download. // exceed the max download size, abort the download.
OWSAssert(0); DDLogError(@"%@ Attachment download exceed expected content length: %lld, %lld.",
[task cancel]; self.tag,
(long long) progress.totalUnitCount,
(long long) progress.completedUnitCount);
abortDownload();
return;
}
// We only need to check the content length header once.
if (hasCheckedContentLength) {
return;
} }
// Once we've received some bytes of the download, check the content length
// header for the download.
//
// If the task doesn't exist, or doesn't have a response, or is missing
// the expected headers, or has an invalid or oversize content length, etc.,
// abort the download.
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)task.response;
if (![httpResponse isKindOfClass:[NSHTTPURLResponse class]]) {
DDLogError(@"%@ Attachment download has missing or invalid response.",
self.tag);
abortDownload();
return;
}
NSDictionary *headers = [httpResponse allHeaderFields];
if (![headers isKindOfClass:[NSDictionary class]]) {
DDLogError(@"%@ Attachment download invalid headers.",
self.tag);
abortDownload();
return;
} }
NSString *contentLength = headers[@"Content-Length"];
if (![contentLength isKindOfClass:[NSString class]]) {
DDLogError(@"%@ Attachment download missing or invalid content length.",
self.tag);
abortDownload();
return;
}
if (contentLength.longLongValue > kMaxDownloadSize) {
DDLogError(@"%@ Attachment download content length exceeds max download size.",
self.tag);
abortDownload();
return;
}
// This response has a valid content length that is less
// than our max download size. Proceed with the download.
hasCheckedContentLength = YES;
} }
success:^(NSURLSessionDataTask *_Nonnull task, id _Nullable responseObject) { success:^(NSURLSessionDataTask *_Nonnull task, id _Nullable responseObject) {
if (![responseObject isKindOfClass:[NSData class]]) { if (![responseObject isKindOfClass:[NSData class]]) {

Loading…
Cancel
Save