HTTPSURLLoader.m 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. // _____ _
  2. // |_ _| |_ _ _ ___ ___ _ __ __ _
  3. // | | | ' \| '_/ -_) -_) ' \/ _` |_
  4. // |_| |_||_|_| \___\___|_|_|_\__,_(_)
  5. //
  6. // Threema iOS Client
  7. // Copyright (c) 2013-2020 Threema GmbH
  8. //
  9. // This program is free software: you can redistribute it and/or modify
  10. // it under the terms of the GNU Affero General Public License, version 3,
  11. // as published by the Free Software Foundation.
  12. //
  13. // This program is distributed in the hope that it will be useful,
  14. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. // GNU Affero General Public License for more details.
  17. //
  18. // You should have received a copy of the GNU Affero General Public License
  19. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  20. #import "HTTPSURLLoader.h"
  21. #import "ThreemaError.h"
  22. #import "BlobUtil.h"
  23. #import "ActivityIndicatorProxy.h"
  24. #ifdef DEBUG
  25. static const DDLogLevel ddLogLevel = DDLogLevelVerbose;
  26. #else
  27. static const DDLogLevel ddLogLevel = DDLogLevelWarning;
  28. #endif
  29. @interface HTTPSURLLoader ()
  30. @property NSMutableData *receivedData;
  31. @property NSURLConnection *downloadConnection;
  32. @property (copy) void(^onCompletion)(NSData *data);
  33. @property (copy) void(^onError)(NSError *error);
  34. @end
  35. @implementation HTTPSURLLoader
  36. - (void)startWithURLRequest:(NSURLRequest*)urlRequest onCompletion:(void (^)(NSData *))onCompletion onError:(void (^)(NSError *))onError {
  37. DDLogVerbose(@"Requesting: %@", urlRequest.URL);
  38. _onCompletion = onCompletion;
  39. _onError = onError;
  40. _receivedData = [NSMutableData data];
  41. _downloadConnection = [[NSURLConnection alloc] initWithRequest:urlRequest delegate:self];
  42. [ActivityIndicatorProxy startActivity];
  43. }
  44. - (void)startWithBlobId:(NSData*)blobId onCompletion:(void (^)(NSData *))onCompletion onError:(void (^)(NSError *))onError {
  45. NSURL *blobUrl = [BlobUtil urlForBlobId:blobId];
  46. NSURLRequest *request = [NSURLRequest requestWithURL:blobUrl cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:kBlobLoadTimeout];
  47. [self startWithURLRequest:request onCompletion:onCompletion onError:onError];
  48. }
  49. #pragma mark - URL connection delegate
  50. - (void)connectionDidFinishLoading:(NSURLConnection *)connection {
  51. DDLogVerbose(@"Request succeeded - received %lu bytes", (unsigned long)[_receivedData length]);
  52. [ActivityIndicatorProxy stopActivity];
  53. _onCompletion(_receivedData);
  54. }
  55. - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
  56. DDLogError(@"Connection failed - error %@ %@",
  57. [error localizedDescription],
  58. [[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);
  59. [ActivityIndicatorProxy stopActivity];
  60. _onError(error);
  61. }
  62. /* this method ensures that HTTP errors get treated like connection failures etc. as well */
  63. - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
  64. [_receivedData setLength:0];
  65. NSHTTPURLResponse *httpURLResponse = ((NSHTTPURLResponse *)response);
  66. _responseHeaderFields = httpURLResponse.allHeaderFields;
  67. NSInteger statusCode = [httpURLResponse statusCode];
  68. if (statusCode >= 400)
  69. {
  70. [connection cancel]; // stop connecting; no more delegate messages
  71. NSDictionary *errorInfo = [NSDictionary dictionaryWithObject:[NSString stringWithFormat:
  72. NSLocalizedString(@"Server returned status code %d",@""),
  73. statusCode]
  74. forKey:NSLocalizedDescriptionKey];
  75. NSError *statusError = [NSError errorWithDomain:NSURLErrorDomain
  76. code:statusCode
  77. userInfo:errorInfo];
  78. [self connection:connection didFailWithError:statusError];
  79. }
  80. }
  81. - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
  82. [_receivedData appendData:data];
  83. if ([_delegate respondsToSelector:@selector(httpsLoaderShouldCancel)]) {
  84. if ([_delegate httpsLoaderShouldCancel]) {
  85. DDLogInfo(@"dowload cancelled");
  86. [connection cancel];
  87. [ActivityIndicatorProxy stopActivity];
  88. _onError([ThreemaError threemaError:@"User cancelled download" withCode:kErrorCodeUserCancelled]);
  89. return;
  90. }
  91. }
  92. if ([_delegate respondsToSelector:@selector(httpsLoaderReceivedData:)]) {
  93. [_delegate httpsLoaderReceivedData:_receivedData];
  94. }
  95. }
  96. - (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse {
  97. return nil;
  98. }
  99. @end