Merge pull request #2866 from dreampiggy/feature_response_modifier_data_decrypter
Feature response modifier data decrypter
This commit is contained in:
commit
75fb66c834
|
@ -60,9 +60,17 @@
|
|||
324DF4B6200A14DC008A84CC /* SDWebImageDefine.h in Headers */ = {isa = PBXBuildFile; fileRef = 324DF4B2200A14DC008A84CC /* SDWebImageDefine.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
324DF4BA200A14DC008A84CC /* SDWebImageDefine.m in Sources */ = {isa = PBXBuildFile; fileRef = 324DF4B3200A14DC008A84CC /* SDWebImageDefine.m */; };
|
||||
324DF4BC200A14DC008A84CC /* SDWebImageDefine.m in Sources */ = {isa = PBXBuildFile; fileRef = 324DF4B3200A14DC008A84CC /* SDWebImageDefine.m */; };
|
||||
3250C9EE2355D9DA0093A896 /* SDWebImageDownloaderDecryptor.h in Headers */ = {isa = PBXBuildFile; fileRef = 3250C9EC2355D9DA0093A896 /* SDWebImageDownloaderDecryptor.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
3250C9EF2355D9DA0093A896 /* SDWebImageDownloaderDecryptor.m in Sources */ = {isa = PBXBuildFile; fileRef = 3250C9ED2355D9DA0093A896 /* SDWebImageDownloaderDecryptor.m */; };
|
||||
3250C9F02355D9DA0093A896 /* SDWebImageDownloaderDecryptor.m in Sources */ = {isa = PBXBuildFile; fileRef = 3250C9ED2355D9DA0093A896 /* SDWebImageDownloaderDecryptor.m */; };
|
||||
3250C9F12355E3DF0093A896 /* SDWebImageDownloaderDecryptor.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3250C9EC2355D9DA0093A896 /* SDWebImageDownloaderDecryptor.h */; };
|
||||
325312CA200F09910046BF1E /* SDWebImageTransition.h in Headers */ = {isa = PBXBuildFile; fileRef = 325312C6200F09910046BF1E /* SDWebImageTransition.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
325312CE200F09910046BF1E /* SDWebImageTransition.m in Sources */ = {isa = PBXBuildFile; fileRef = 325312C7200F09910046BF1E /* SDWebImageTransition.m */; };
|
||||
325312D0200F09910046BF1E /* SDWebImageTransition.m in Sources */ = {isa = PBXBuildFile; fileRef = 325312C7200F09910046BF1E /* SDWebImageTransition.m */; };
|
||||
32542763235576E20042BAA4 /* SDWebImageDownloaderResponseModifier.h in Headers */ = {isa = PBXBuildFile; fileRef = 32542761235576E20042BAA4 /* SDWebImageDownloaderResponseModifier.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
32542764235576E20042BAA4 /* SDWebImageDownloaderResponseModifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 32542762235576E20042BAA4 /* SDWebImageDownloaderResponseModifier.m */; };
|
||||
32542765235576E20042BAA4 /* SDWebImageDownloaderResponseModifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 32542762235576E20042BAA4 /* SDWebImageDownloaderResponseModifier.m */; };
|
||||
325427662355783C0042BAA4 /* SDWebImageDownloaderResponseModifier.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 32542761235576E20042BAA4 /* SDWebImageDownloaderResponseModifier.h */; };
|
||||
3257EAFA21898AED0097B271 /* SDImageGraphics.h in Headers */ = {isa = PBXBuildFile; fileRef = 3257EAF721898AED0097B271 /* SDImageGraphics.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
3257EAFC21898AED0097B271 /* SDImageGraphics.m in Sources */ = {isa = PBXBuildFile; fileRef = 3257EAF821898AED0097B271 /* SDImageGraphics.m */; };
|
||||
3257EAFD21898AED0097B271 /* SDImageGraphics.m in Sources */ = {isa = PBXBuildFile; fileRef = 3257EAF821898AED0097B271 /* SDImageGraphics.m */; };
|
||||
|
@ -280,6 +288,8 @@
|
|||
dstPath = include/SDWebImage;
|
||||
dstSubfolderSpec = 16;
|
||||
files = (
|
||||
3250C9F12355E3DF0093A896 /* SDWebImageDownloaderDecryptor.h in Copy Headers */,
|
||||
325427662355783C0042BAA4 /* SDWebImageDownloaderResponseModifier.h in Copy Headers */,
|
||||
3298655F233723220071958B /* SDImageHEICCoder.h in Copy Headers */,
|
||||
32C78E3823336FC800C6B7F8 /* SDImageIOAnimatedCoder.h in Copy Headers */,
|
||||
32E5690822B1FFCA00CBABC6 /* SDWebImageOptionsProcessor.h in Copy Headers */,
|
||||
|
@ -368,8 +378,12 @@
|
|||
3248475C201775F600AF9E5A /* SDAnimatedImageView+WebCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "SDAnimatedImageView+WebCache.m"; path = "Core/SDAnimatedImageView+WebCache.m"; sourceTree = "<group>"; };
|
||||
324DF4B2200A14DC008A84CC /* SDWebImageDefine.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SDWebImageDefine.h; path = Core/SDWebImageDefine.h; sourceTree = "<group>"; };
|
||||
324DF4B3200A14DC008A84CC /* SDWebImageDefine.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SDWebImageDefine.m; path = Core/SDWebImageDefine.m; sourceTree = "<group>"; };
|
||||
3250C9EC2355D9DA0093A896 /* SDWebImageDownloaderDecryptor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SDWebImageDownloaderDecryptor.h; path = Core/SDWebImageDownloaderDecryptor.h; sourceTree = "<group>"; };
|
||||
3250C9ED2355D9DA0093A896 /* SDWebImageDownloaderDecryptor.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SDWebImageDownloaderDecryptor.m; path = Core/SDWebImageDownloaderDecryptor.m; sourceTree = "<group>"; };
|
||||
325312C6200F09910046BF1E /* SDWebImageTransition.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SDWebImageTransition.h; path = Core/SDWebImageTransition.h; sourceTree = "<group>"; };
|
||||
325312C7200F09910046BF1E /* SDWebImageTransition.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SDWebImageTransition.m; path = Core/SDWebImageTransition.m; sourceTree = "<group>"; };
|
||||
32542761235576E20042BAA4 /* SDWebImageDownloaderResponseModifier.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SDWebImageDownloaderResponseModifier.h; path = Core/SDWebImageDownloaderResponseModifier.h; sourceTree = "<group>"; };
|
||||
32542762235576E20042BAA4 /* SDWebImageDownloaderResponseModifier.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SDWebImageDownloaderResponseModifier.m; path = Core/SDWebImageDownloaderResponseModifier.m; sourceTree = "<group>"; };
|
||||
3257EAF721898AED0097B271 /* SDImageGraphics.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SDImageGraphics.h; path = Core/SDImageGraphics.h; sourceTree = "<group>"; };
|
||||
3257EAF821898AED0097B271 /* SDImageGraphics.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SDImageGraphics.m; path = Core/SDImageGraphics.m; sourceTree = "<group>"; };
|
||||
325C460022339330004CAE11 /* SDImageAssetManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDImageAssetManager.h; sourceTree = "<group>"; };
|
||||
|
@ -757,6 +771,10 @@
|
|||
32B9B536206ED4230026769D /* SDWebImageDownloaderConfig.m */,
|
||||
32F21B4F20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h */,
|
||||
32F21B5020788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m */,
|
||||
32542761235576E20042BAA4 /* SDWebImageDownloaderResponseModifier.h */,
|
||||
32542762235576E20042BAA4 /* SDWebImageDownloaderResponseModifier.m */,
|
||||
3250C9EC2355D9DA0093A896 /* SDWebImageDownloaderDecryptor.h */,
|
||||
3250C9ED2355D9DA0093A896 /* SDWebImageDownloaderDecryptor.m */,
|
||||
321B377D2083290D00C0EA77 /* SDImageLoader.h */,
|
||||
321B377E2083290D00C0EA77 /* SDImageLoader.m */,
|
||||
321B377F2083290E00C0EA77 /* SDImageLoadersManager.h */,
|
||||
|
@ -833,6 +851,7 @@
|
|||
4A2CAE181AB4BB6400B6BC39 /* SDWebImageCompat.h in Headers */,
|
||||
4A2CAE331AB4BB7500B6BC39 /* UIImageView+HighlightedWebCache.h in Headers */,
|
||||
328BB6C32082581100760D6C /* SDDiskCache.h in Headers */,
|
||||
32542763235576E20042BAA4 /* SDWebImageDownloaderResponseModifier.h in Headers */,
|
||||
4A2CAE1D1AB4BB6800B6BC39 /* SDWebImageDownloaderOperation.h in Headers */,
|
||||
4A2CAE2B1AB4BB7500B6BC39 /* UIButton+WebCache.h in Headers */,
|
||||
4A2CAE251AB4BB7000B6BC39 /* SDWebImagePrefetcher.h in Headers */,
|
||||
|
@ -854,6 +873,7 @@
|
|||
4A2CAE1B1AB4BB6800B6BC39 /* SDWebImageDownloader.h in Headers */,
|
||||
3248476B201775F600AF9E5A /* SDAnimatedImageView.h in Headers */,
|
||||
32D122322080B2EB003685A3 /* SDImageCachesManager.h in Headers */,
|
||||
3250C9EE2355D9DA0093A896 /* SDWebImageDownloaderDecryptor.h in Headers */,
|
||||
32F7C0862030719600873181 /* UIImage+Transform.h in Headers */,
|
||||
321E60C01F38E91700405457 /* UIImage+ForceDecode.h in Headers */,
|
||||
329F1243223FAD3400B309FD /* SDInternalMacros.h in Headers */,
|
||||
|
@ -1054,6 +1074,7 @@
|
|||
325C46232233A02E004CAE11 /* UIColor+HexString.m in Sources */,
|
||||
321E60C61F38E91700405457 /* UIImage+ForceDecode.m in Sources */,
|
||||
3244062E2296C5F400A36084 /* SDWebImageOptionsProcessor.m in Sources */,
|
||||
3250C9F02355D9DA0093A896 /* SDWebImageDownloaderDecryptor.m in Sources */,
|
||||
328BB6A42081FED200760D6C /* SDWebImageCacheKeyFilter.m in Sources */,
|
||||
4A2CAE2E1AB4BB7500B6BC39 /* UIImage+GIF.m in Sources */,
|
||||
80B6DF822142B44400BCB334 /* NSButton+WebCache.m in Sources */,
|
||||
|
@ -1073,6 +1094,7 @@
|
|||
3298655E2337230C0071958B /* SDImageHEICCoder.m in Sources */,
|
||||
32F7C0802030719600873181 /* UIImage+Transform.m in Sources */,
|
||||
327054DC206CD8B3006EA328 /* SDImageAPNGCoder.m in Sources */,
|
||||
32542765235576E20042BAA4 /* SDWebImageDownloaderResponseModifier.m in Sources */,
|
||||
325312D0200F09910046BF1E /* SDWebImageTransition.m in Sources */,
|
||||
321E609C1F38E8ED00405457 /* SDImageIOCoder.m in Sources */,
|
||||
4A2CAE261AB4BB7000B6BC39 /* SDWebImagePrefetcher.m in Sources */,
|
||||
|
@ -1119,6 +1141,7 @@
|
|||
325C46222233A02E004CAE11 /* UIColor+HexString.m in Sources */,
|
||||
321E60C41F38E91700405457 /* UIImage+ForceDecode.m in Sources */,
|
||||
3244062D2296C5F400A36084 /* SDWebImageOptionsProcessor.m in Sources */,
|
||||
3250C9EF2355D9DA0093A896 /* SDWebImageDownloaderDecryptor.m in Sources */,
|
||||
328BB6A22081FED200760D6C /* SDWebImageCacheKeyFilter.m in Sources */,
|
||||
53761309155AD0D5005750A4 /* SDImageCache.m in Sources */,
|
||||
80B6DF832142B44500BCB334 /* NSButton+WebCache.m in Sources */,
|
||||
|
@ -1138,6 +1161,7 @@
|
|||
3298655D2337230C0071958B /* SDImageHEICCoder.m in Sources */,
|
||||
321E609A1F38E8ED00405457 /* SDImageIOCoder.m in Sources */,
|
||||
327054DA206CD8B3006EA328 /* SDImageAPNGCoder.m in Sources */,
|
||||
32542764235576E20042BAA4 /* SDWebImageDownloaderResponseModifier.m in Sources */,
|
||||
325312CE200F09910046BF1E /* SDWebImageTransition.m in Sources */,
|
||||
5376130C155AD0D5005750A4 /* SDWebImageManager.m in Sources */,
|
||||
5376130D155AD0D5005750A4 /* SDWebImagePrefetcher.m in Sources */,
|
||||
|
|
|
@ -233,6 +233,16 @@ FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextAnimat
|
|||
*/
|
||||
FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextDownloadRequestModifier;
|
||||
|
||||
/**
|
||||
A id<SDWebImageDownloaderResponseModifier> instance to modify the image download response. It's used for downloader to modify the original response from URL and options. If you provide one, it will ignore the `responseModifier` in downloader and use provided one instead. (id<SDWebImageDownloaderResponseModifier>)
|
||||
*/
|
||||
FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextDownloadResponseModifier;
|
||||
|
||||
/**
|
||||
A id<SDWebImageContextDownloadDecryptor> instance to decrypt the image download data. This can be used for image data decryption, such as Base64 encoded image. If you provide one, it will ignore the `decryptor` in downloader and use provided one instead. (id<SDWebImageContextDownloadDecryptor>)
|
||||
*/
|
||||
FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextDownloadDecryptor;
|
||||
|
||||
/**
|
||||
A id<SDWebImageCacheKeyFilter> instance to convert an URL into a cache key. It's used when manager need cache key to use image cache. If you provide one, it will ignore the `cacheKeyFilter` in manager and use provided one instead. (id<SDWebImageCacheKeyFilter>)
|
||||
*/
|
||||
|
|
|
@ -126,5 +126,7 @@ SDWebImageContextOption const SDWebImageContextStoreCacheType = @"storeCacheType
|
|||
SDWebImageContextOption const SDWebImageContextOriginalStoreCacheType = @"originalStoreCacheType";
|
||||
SDWebImageContextOption const SDWebImageContextAnimatedImageClass = @"animatedImageClass";
|
||||
SDWebImageContextOption const SDWebImageContextDownloadRequestModifier = @"downloadRequestModifier";
|
||||
SDWebImageContextOption const SDWebImageContextDownloadResponseModifier = @"downloadResponseModifier";
|
||||
SDWebImageContextOption const SDWebImageContextDownloadDecryptor = @"downloadDecryptor";
|
||||
SDWebImageContextOption const SDWebImageContextCacheKeyFilter = @"cacheKeyFilter";
|
||||
SDWebImageContextOption const SDWebImageContextCacheSerializer = @"cacheSerializer";
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#import "SDWebImageOperation.h"
|
||||
#import "SDWebImageDownloaderConfig.h"
|
||||
#import "SDWebImageDownloaderRequestModifier.h"
|
||||
#import "SDWebImageDownloaderResponseModifier.h"
|
||||
#import "SDWebImageDownloaderDecryptor.h"
|
||||
#import "SDImageLoader.h"
|
||||
|
||||
/// Downloader options
|
||||
|
@ -142,12 +144,29 @@ typedef SDImageLoaderCompletedBlock SDWebImageDownloaderCompletedBlock;
|
|||
|
||||
/**
|
||||
* Set the request modifier to modify the original download request before image load.
|
||||
* This request modifier method will be called for each downloading image request. Return the original request means no modication. Return nil will cancel the download request.
|
||||
* This request modifier method will be called for each downloading image request. Return the original request means no modification. Return nil will cancel the download request.
|
||||
* Defaults to nil, means does not modify the original download request.
|
||||
* @note If you want to modify single request, consider using `SDWebImageContextDownloadRequestModifier` context option.
|
||||
*/
|
||||
@property (nonatomic, strong, nullable) id<SDWebImageDownloaderRequestModifier> requestModifier;
|
||||
|
||||
/**
|
||||
* Set the response modifier to modify the original download response during image load.
|
||||
* This request modifier method will be called for each downloading image response. Return the original response means no modification. Return nil will mark current download as cancelled.
|
||||
* Defaults to nil, means does not modify the original download response.
|
||||
* @note If you want to modify single response, consider using `SDWebImageContextDownloadResponseModifier` context option.
|
||||
*/
|
||||
@property (nonatomic, strong, nullable) id<SDWebImageDownloaderResponseModifier> responseModifier;
|
||||
|
||||
/**
|
||||
* Set the decryptor to decrypt the original download data before image decoding. This can be used for encrypted image data, like Base64.
|
||||
* This decryptor method will be called for each downloading image data. Return the original data means no modification. Return nil will mark this download failed.
|
||||
* Defaults to nil, means does not modify the original download data.
|
||||
* @note When using decryptor, progressive decoding will be disabled, to avoid data corrupt issue.
|
||||
* @note If you want to decrypt single download data, consider using `SDWebImageContextDownloadDecryptor` context option.
|
||||
*/
|
||||
@property (nonatomic, strong, nullable) id<SDWebImageDownloaderDecryptor> decryptor;
|
||||
|
||||
/**
|
||||
* The configuration in use by the internal NSURLSession. If you want to provide a custom sessionConfiguration, use `SDWebImageDownloaderConfig.sessionConfiguration` and create a new downloader instance.
|
||||
@note This is immutable according to NSURLSession's documentation. Mutating this object directly has no effect.
|
||||
|
|
|
@ -272,6 +272,16 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext;
|
|||
SD_LOCK(self.HTTPHeadersLock);
|
||||
mutableRequest.allHTTPHeaderFields = self.HTTPHeaders;
|
||||
SD_UNLOCK(self.HTTPHeadersLock);
|
||||
|
||||
// Context Option
|
||||
SDWebImageMutableContext *mutableContext;
|
||||
if (context) {
|
||||
mutableContext = [context mutableCopy];
|
||||
} else {
|
||||
mutableContext = [NSMutableDictionary dictionary];
|
||||
}
|
||||
|
||||
// Request Modifier
|
||||
id<SDWebImageDownloaderRequestModifier> requestModifier;
|
||||
if ([context valueForKey:SDWebImageContextDownloadRequestModifier]) {
|
||||
requestModifier = [context valueForKey:SDWebImageContextDownloadRequestModifier];
|
||||
|
@ -291,6 +301,30 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext;
|
|||
} else {
|
||||
request = [mutableRequest copy];
|
||||
}
|
||||
// Response Modifier
|
||||
id<SDWebImageDownloaderResponseModifier> responseModifier;
|
||||
if ([context valueForKey:SDWebImageContextDownloadResponseModifier]) {
|
||||
responseModifier = [context valueForKey:SDWebImageContextDownloadResponseModifier];
|
||||
} else {
|
||||
responseModifier = self.responseModifier;
|
||||
}
|
||||
if (responseModifier) {
|
||||
mutableContext[SDWebImageContextDownloadResponseModifier] = responseModifier;
|
||||
}
|
||||
// Decryptor
|
||||
id<SDWebImageDownloaderDecryptor> decryptor;
|
||||
if ([context valueForKey:SDWebImageContextDownloadDecryptor]) {
|
||||
decryptor = [context valueForKey:SDWebImageContextDownloadDecryptor];
|
||||
} else {
|
||||
decryptor = self.decryptor;
|
||||
}
|
||||
if (decryptor) {
|
||||
mutableContext[SDWebImageContextDownloadDecryptor] = decryptor;
|
||||
}
|
||||
|
||||
context = [mutableContext copy];
|
||||
|
||||
// Operation Class
|
||||
Class operationClass = self.config.operationClass;
|
||||
if (operationClass && [operationClass isSubclassOfClass:[NSOperation class]] && [operationClass conformsToProtocol:@protocol(SDWebImageDownloaderOperation)]) {
|
||||
// Custom operation class
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "SDWebImageCompat.h"
|
||||
|
||||
typedef NSData * _Nullable (^SDWebImageDownloaderDecryptorBlock)(NSData * _Nonnull data, NSURLResponse * _Nullable response);
|
||||
|
||||
/**
|
||||
This is the protocol for downloader decryptor. Which decrypt the original encrypted data before decoding. Note progressive decoding is not compatible for decryptor.
|
||||
We can use a block to specify the downloader decryptor. But Using protocol can make this extensible, and allow Swift user to use it easily instead of using `@convention(block)` to store a block into context options.
|
||||
*/
|
||||
@protocol SDWebImageDownloaderDecryptor <NSObject>
|
||||
|
||||
/// Decrypt the original download data and return a new data. You can use this to decrypt the data using your perfereed algorithm.
|
||||
/// @param data The original download data
|
||||
/// @param response The URL response for data. If you modifiy the original URL response via response modifier, the modified version will be here. This arg is nullable.
|
||||
/// @note If nil is returned, the image download will be marked as failed with error `SDWebImageErrorBadImageData`
|
||||
- (nullable NSData *)decryptedDataWithData:(nonnull NSData *)data response:(nullable NSURLResponse *)response;
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
A downloader response modifier class with block.
|
||||
*/
|
||||
@interface SDWebImageDownloaderDecryptor : NSObject <SDWebImageDownloaderDecryptor>
|
||||
|
||||
- (nonnull instancetype)initWithBlock:(nonnull SDWebImageDownloaderDecryptorBlock)block;
|
||||
+ (nonnull instancetype)decryptorWithBlock:(nonnull SDWebImageDownloaderDecryptorBlock)block;
|
||||
|
||||
@end
|
||||
|
||||
/// Convenience way to create decryptor for common data encryption.
|
||||
@interface SDWebImageDownloaderDecryptor (Conveniences)
|
||||
|
||||
/// Base64 Encoded image data decryptor
|
||||
@property (class, readonly, nonnull) SDWebImageDownloaderDecryptor *base64Decryptor;
|
||||
|
||||
@end
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#import "SDWebImageDownloaderDecryptor.h"
|
||||
|
||||
@interface SDWebImageDownloaderDecryptor ()
|
||||
|
||||
@property (nonatomic, copy, nonnull) SDWebImageDownloaderDecryptorBlock block;
|
||||
|
||||
@end
|
||||
|
||||
@implementation SDWebImageDownloaderDecryptor
|
||||
|
||||
- (instancetype)initWithBlock:(SDWebImageDownloaderDecryptorBlock)block {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.block = block;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (instancetype)decryptorWithBlock:(SDWebImageDownloaderDecryptorBlock)block {
|
||||
SDWebImageDownloaderDecryptor *decryptor = [[SDWebImageDownloaderDecryptor alloc] initWithBlock:block];
|
||||
return decryptor;
|
||||
}
|
||||
|
||||
- (nullable NSData *)decryptedDataWithData:(nonnull NSData *)data response:(nullable NSURLResponse *)response {
|
||||
if (!self.block) {
|
||||
return nil;
|
||||
}
|
||||
return self.block(data, response);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation SDWebImageDownloaderDecryptor (Conveniences)
|
||||
|
||||
+ (SDWebImageDownloaderDecryptor *)base64Decryptor {
|
||||
static SDWebImageDownloaderDecryptor *decryptor;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
decryptor = [SDWebImageDownloaderDecryptor decryptorWithBlock:^NSData * _Nullable(NSData * _Nonnull data, NSURLResponse * _Nullable response) {
|
||||
NSData *modifiedData = [[NSData alloc] initWithBase64EncodedData:data options:NSDataBase64DecodingIgnoreUnknownCharacters];
|
||||
return modifiedData;
|
||||
}];
|
||||
});
|
||||
return decryptor;
|
||||
}
|
||||
|
||||
@end
|
|
@ -9,6 +9,8 @@
|
|||
#import "SDWebImageDownloaderOperation.h"
|
||||
#import "SDWebImageError.h"
|
||||
#import "SDInternalMacros.h"
|
||||
#import "SDWebImageDownloaderResponseModifier.h"
|
||||
#import "SDWebImageDownloaderDecryptor.h"
|
||||
|
||||
// iOS 8 Foundation.framework extern these symbol but the define is in CFNetwork.framework. We just fix this without import CFNetwork.framework
|
||||
#if ((__IPHONE_OS_VERSION_MIN_REQUIRED && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0) || (__MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_11))
|
||||
|
@ -39,6 +41,9 @@ typedef NSMutableDictionary<NSString *, id> SDCallbacksDictionary;
|
|||
@property (strong, nonatomic, nullable) NSError *responseError;
|
||||
@property (assign, nonatomic) double previousProgress; // previous progress percent
|
||||
|
||||
@property (strong, nonatomic, nullable) id<SDWebImageDownloaderResponseModifier> responseModifier; // modifiy original URLResponse
|
||||
@property (strong, nonatomic, nullable) id<SDWebImageDownloaderDecryptor> decryptor; // decrypt image data
|
||||
|
||||
// This is weak because it is injected by whoever manages this session. If this gets nil-ed out, we won't be able to run
|
||||
// the task associated with this operation
|
||||
@property (weak, nonatomic, nullable) NSURLSession *unownedSession;
|
||||
|
@ -76,6 +81,8 @@ typedef NSMutableDictionary<NSString *, id> SDCallbacksDictionary;
|
|||
_options = options;
|
||||
_context = [context copy];
|
||||
_callbackBlocks = [NSMutableArray new];
|
||||
_responseModifier = context[SDWebImageContextDownloadResponseModifier];
|
||||
_decryptor = context[SDWebImageContextDownloadDecryptor];
|
||||
_executing = NO;
|
||||
_finished = NO;
|
||||
_expectedSize = 0;
|
||||
|
@ -293,13 +300,27 @@ typedef NSMutableDictionary<NSString *, id> SDCallbacksDictionary;
|
|||
didReceiveResponse:(NSURLResponse *)response
|
||||
completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler {
|
||||
NSURLSessionResponseDisposition disposition = NSURLSessionResponseAllow;
|
||||
|
||||
// Check response modifier, if return nil, will marked as cancelled.
|
||||
BOOL valid = YES;
|
||||
if (self.responseModifier && response) {
|
||||
response = [self.responseModifier modifiedResponseWithResponse:response];
|
||||
if (!response) {
|
||||
valid = NO;
|
||||
self.responseError = [NSError errorWithDomain:SDWebImageErrorDomain code:SDWebImageErrorInvalidDownloadResponse userInfo:nil];
|
||||
}
|
||||
}
|
||||
|
||||
NSInteger expected = (NSInteger)response.expectedContentLength;
|
||||
expected = expected > 0 ? expected : 0;
|
||||
self.expectedSize = expected;
|
||||
self.response = response;
|
||||
|
||||
NSInteger statusCode = [response respondsToSelector:@selector(statusCode)] ? ((NSHTTPURLResponse *)response).statusCode : 200;
|
||||
BOOL valid = statusCode >= 200 && statusCode < 400;
|
||||
if (!valid) {
|
||||
// Status code should between [200,400)
|
||||
BOOL statusCodeValid = statusCode >= 200 && statusCode < 400;
|
||||
if (!statusCodeValid) {
|
||||
valid = NO;
|
||||
self.responseError = [NSError errorWithDomain:SDWebImageErrorDomain code:SDWebImageErrorInvalidDownloadStatusCode userInfo:@{SDWebImageErrorDownloadStatusCodeKey : @(statusCode)}];
|
||||
}
|
||||
//'304 Not Modified' is an exceptional one
|
||||
|
@ -353,8 +374,10 @@ didReceiveResponse:(NSURLResponse *)response
|
|||
return;
|
||||
}
|
||||
self.previousProgress = currentProgress;
|
||||
|
||||
if (self.options & SDWebImageDownloaderProgressiveLoad) {
|
||||
|
||||
// Using data decryptor will disable the progressive decoding, since there are no support for progressive decrypt
|
||||
BOOL supportProgressive = (self.options & SDWebImageDownloaderProgressiveLoad) && !self.decryptor;
|
||||
if (supportProgressive) {
|
||||
// Get the image data
|
||||
NSData *imageData = [self.imageData copy];
|
||||
|
||||
|
@ -421,6 +444,10 @@ didReceiveResponse:(NSURLResponse *)response
|
|||
if ([self callbacksForKey:kCompletedCallbackKey].count > 0) {
|
||||
NSData *imageData = [self.imageData copy];
|
||||
self.imageData = nil;
|
||||
// data decryptor
|
||||
if (imageData && self.decryptor) {
|
||||
imageData = [self.decryptor decryptedDataWithData:imageData response:self.response];
|
||||
}
|
||||
if (imageData) {
|
||||
/** if you specified to only use cached data via `SDWebImageDownloaderIgnoreCachedResponse`,
|
||||
* then we should check if the cached data is equal to image data
|
||||
|
|
|
@ -17,6 +17,9 @@ typedef NSURLRequest * _Nullable (^SDWebImageDownloaderRequestModifierBlock)(NSU
|
|||
*/
|
||||
@protocol SDWebImageDownloaderRequestModifier <NSObject>
|
||||
|
||||
/// Modify the original URL request and return a new one instead. You can modify the HTTP header, cachePolicy, etc for this URL.
|
||||
/// @param request The original URL request for image loading
|
||||
/// @note If return nil, the URL request will be cancelled.
|
||||
- (nullable NSURLRequest *)modifiedRequestWithRequest:(nonnull NSURLRequest *)request;
|
||||
|
||||
@end
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "SDWebImageCompat.h"
|
||||
|
||||
typedef NSURLResponse * _Nullable (^SDWebImageDownloaderResponseModifierBlock)(NSURLResponse * _Nonnull response);
|
||||
|
||||
/**
|
||||
This is the protocol for downloader response modifier.
|
||||
We can use a block to specify the downloader response modifier. But Using protocol can make this extensible, and allow Swift user to use it easily instead of using `@convention(block)` to store a block into context options.
|
||||
*/
|
||||
@protocol SDWebImageDownloaderResponseModifier <NSObject>
|
||||
|
||||
/// Modify the original URL response and return a new response. You can use this to check MIME-Type, mock server response, etc.
|
||||
/// @param response The original URL response, note for HTTP request it's actually a `NSHTTPURLResponse` instance
|
||||
/// @note If nil is returned, the image download will marked as cancelled with error `SDWebImageErrorInvalidDownloadResponse`
|
||||
- (nullable NSURLResponse *)modifiedResponseWithResponse:(nonnull NSURLResponse *)response;
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
A downloader response modifier class with block.
|
||||
*/
|
||||
@interface SDWebImageDownloaderResponseModifier : NSObject <SDWebImageDownloaderResponseModifier>
|
||||
|
||||
- (nonnull instancetype)initWithBlock:(nonnull SDWebImageDownloaderResponseModifierBlock)block;
|
||||
+ (nonnull instancetype)responseModifierWithBlock:(nonnull SDWebImageDownloaderResponseModifierBlock)block;
|
||||
|
||||
@end
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
|
||||
#import "SDWebImageDownloaderResponseModifier.h"
|
||||
|
||||
@interface SDWebImageDownloaderResponseModifier ()
|
||||
|
||||
@property (nonatomic, copy, nonnull) SDWebImageDownloaderResponseModifierBlock block;
|
||||
|
||||
@end
|
||||
|
||||
@implementation SDWebImageDownloaderResponseModifier
|
||||
|
||||
- (instancetype)initWithBlock:(SDWebImageDownloaderResponseModifierBlock)block {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.block = block;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (instancetype)responseModifierWithBlock:(SDWebImageDownloaderResponseModifierBlock)block {
|
||||
SDWebImageDownloaderResponseModifier *responseModifier = [[SDWebImageDownloaderResponseModifier alloc] initWithBlock:block];
|
||||
return responseModifier;
|
||||
}
|
||||
|
||||
- (nullable NSURLResponse *)modifiedResponseWithResponse:(nonnull NSURLResponse *)response {
|
||||
if (!self.block) {
|
||||
return nil;
|
||||
}
|
||||
return self.block(response);
|
||||
}
|
||||
|
||||
@end
|
|
@ -22,4 +22,5 @@ typedef NS_ERROR_ENUM(SDWebImageErrorDomain, SDWebImageError) {
|
|||
SDWebImageErrorInvalidDownloadOperation = 2000, // The image download operation is invalid, such as nil operation or unexpected error occur when operation initialized
|
||||
SDWebImageErrorInvalidDownloadStatusCode = 2001, // The image download response a invalid status code. You can check the status code in error's userInfo under `SDWebImageErrorDownloadStatusCodeKey`
|
||||
SDWebImageErrorCancelled = 2002, // The image loading operation is cancelled before finished, during either async disk cache query, or waiting before actual network request. For actual network request error, check `NSURLErrorDomain` error domain and code.
|
||||
SDWebImageErrorInvalidDownloadResponse = 2003, // When using response modifier, the modified download response is nil and marked as cancelled.
|
||||
};
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#import "SDWebImageTestDownloadOperation.h"
|
||||
#import "SDWebImageTestCoder.h"
|
||||
#import "SDWebImageTestLoader.h"
|
||||
#import <compression.h>
|
||||
|
||||
#define kPlaceholderTestURLTemplate @"https://via.placeholder.com/10000x%d.png"
|
||||
|
||||
|
@ -542,6 +543,105 @@
|
|||
[self waitForExpectationsWithCommonTimeout];
|
||||
}
|
||||
|
||||
- (void)test24ThatDownloadResponseModifierWorks {
|
||||
XCTestExpectation *expectation1 = [self expectationWithDescription:@"Download response modifier for webURL"];
|
||||
XCTestExpectation *expectation2 = [self expectationWithDescription:@"Download response modifier invalid response"];
|
||||
|
||||
SDWebImageDownloader *downloader = [[SDWebImageDownloader alloc] init];
|
||||
|
||||
// 1. Test webURL to response custom status code and header
|
||||
SDWebImageDownloaderResponseModifier *responseModifier = [SDWebImageDownloaderResponseModifier responseModifierWithBlock:^NSURLResponse * _Nullable(NSURLResponse * _Nonnull response) {
|
||||
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
|
||||
NSMutableDictionary *mutableHeaderFields = [httpResponse.allHeaderFields mutableCopy];
|
||||
mutableHeaderFields[@"Foo"] = @"Bar";
|
||||
NSHTTPURLResponse *modifiedResponse = [[NSHTTPURLResponse alloc] initWithURL:response.URL statusCode:404 HTTPVersion:nil headerFields:[mutableHeaderFields copy]];
|
||||
return [modifiedResponse copy];
|
||||
}];
|
||||
downloader.responseModifier = responseModifier;
|
||||
|
||||
__block SDWebImageDownloadToken *token;
|
||||
token = [downloader downloadImageWithURL:[NSURL URLWithString:kTestJPEGURL] completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) {
|
||||
expect(error).notTo.beNil();
|
||||
expect(error.code).equal(SDWebImageErrorInvalidDownloadStatusCode);
|
||||
expect(error.userInfo[SDWebImageErrorDownloadStatusCodeKey]).equal(404);
|
||||
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)token.response;
|
||||
expect(httpResponse).notTo.beNil();
|
||||
expect(httpResponse.allHeaderFields[@"Foo"]).equal(@"Bar");
|
||||
[expectation1 fulfill];
|
||||
}];
|
||||
|
||||
// 2. Test nil response will cancel the download
|
||||
responseModifier = [SDWebImageDownloaderResponseModifier responseModifierWithBlock:^NSURLResponse * _Nullable(NSURLResponse * _Nonnull response) {
|
||||
return nil;
|
||||
}];
|
||||
[downloader downloadImageWithURL:[NSURL URLWithString:kTestPNGURL] options:0 context:@{SDWebImageContextDownloadResponseModifier : responseModifier} progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) {
|
||||
expect(error).notTo.beNil();
|
||||
expect(error.code).equal(SDWebImageErrorInvalidDownloadResponse);
|
||||
[expectation2 fulfill];
|
||||
}];
|
||||
|
||||
[self waitForExpectationsWithCommonTimeoutUsingHandler:^(NSError * _Nullable error) {
|
||||
[downloader invalidateSessionAndCancel:YES];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)test25ThatDownloadDecryptorWorks {
|
||||
XCTestExpectation *expectation1 = [self expectationWithDescription:@"Download decryptor for fileURL"];
|
||||
XCTestExpectation *expectation2 = [self expectationWithDescription:@"Download decryptor for webURL"];
|
||||
XCTestExpectation *expectation3 = [self expectationWithDescription:@"Download decryptor invalid data"];
|
||||
|
||||
SDWebImageDownloader *downloader = [[SDWebImageDownloader alloc] init];
|
||||
downloader.decryptor = SDWebImageDownloaderDecryptor.base64Decryptor;
|
||||
|
||||
// 1. Test fileURL with Base64 encoded data works
|
||||
NSData *PNGData = [NSData dataWithContentsOfFile:[self testPNGPath]];
|
||||
NSData *base64PNGData = [PNGData base64EncodedDataWithOptions:0];
|
||||
expect(base64PNGData).notTo.beNil();
|
||||
NSURL *base64FileURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"TestBase64.png"]];
|
||||
[base64PNGData writeToURL:base64FileURL atomically:YES];
|
||||
[downloader downloadImageWithURL:base64FileURL options:0 progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) {
|
||||
expect(error).to.beNil();
|
||||
expect(image).notTo.beNil();
|
||||
[expectation1 fulfill];
|
||||
}];
|
||||
|
||||
// 2. Test webURL with Zip encoded data works
|
||||
SDWebImageDownloaderDecryptor *decryptor = [SDWebImageDownloaderDecryptor decryptorWithBlock:^NSData * _Nullable(NSData * _Nonnull data, NSURLResponse * _Nullable response) {
|
||||
if (@available(iOS 13, macOS 10.15, *)) {
|
||||
return [data decompressedDataUsingAlgorithm:NSDataCompressionAlgorithmZlib error:nil];
|
||||
} else if (@available (iOS 9, macOS 10.11, *)) {
|
||||
NSMutableData *decodedData = [NSMutableData dataWithLength:10 * data.length];
|
||||
compression_decode_buffer((uint8_t *)decodedData.bytes, decodedData.length, data.bytes, data.length, nil, COMPRESSION_ZLIB);
|
||||
return [decodedData copy];
|
||||
} else {
|
||||
// iOS 8 does not have built-in Zlib support, just mock the data
|
||||
return base64PNGData;
|
||||
}
|
||||
}];
|
||||
// Note this is not a Zip Archive, just PNG raw buffer data using zlib compression
|
||||
NSURL *zipURL = [NSURL URLWithString:@"https://github.com/SDWebImage/SDWebImage/files/3728087/SDWebImage_logo_small.png.zip"];
|
||||
|
||||
[downloader downloadImageWithURL:zipURL options:0 context:@{SDWebImageContextDownloadDecryptor : decryptor} progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) {
|
||||
expect(error).to.beNil();
|
||||
expect(image).notTo.beNil();
|
||||
[expectation2 fulfill];
|
||||
}];
|
||||
|
||||
// 3. Test nil data will mark download failed
|
||||
decryptor = [SDWebImageDownloaderDecryptor decryptorWithBlock:^NSData * _Nullable(NSData * _Nonnull data, NSURLResponse * _Nullable response) {
|
||||
return nil;
|
||||
}];
|
||||
[downloader downloadImageWithURL:[NSURL URLWithString:kTestJPEGURL] options:0 context:@{SDWebImageContextDownloadDecryptor : decryptor} progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) {
|
||||
expect(error).notTo.beNil();
|
||||
expect(error.code).equal(SDWebImageErrorBadImageData);
|
||||
[expectation3 fulfill];
|
||||
}];
|
||||
|
||||
[self waitForExpectationsWithCommonTimeoutUsingHandler:^(NSError * _Nullable error) {
|
||||
[downloader invalidateSessionAndCancel:YES];
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - SDWebImageLoader
|
||||
- (void)test30CustomImageLoaderWorks {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"Custom image not works"];
|
||||
|
@ -585,4 +685,11 @@
|
|||
[self waitForExpectationsWithCommonTimeout];
|
||||
}
|
||||
|
||||
#pragma mark - Helper
|
||||
|
||||
- (NSString *)testPNGPath {
|
||||
NSBundle *testBundle = [NSBundle bundleForClass:[self class]];
|
||||
return [testBundle pathForResource:@"TestImage" ofType:@"png"];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -36,6 +36,8 @@ FOUNDATION_EXPORT const unsigned char WebImageVersionString[];
|
|||
#import <SDWebImage/SDWebImageDownloaderConfig.h>
|
||||
#import <SDWebImage/SDWebImageDownloaderOperation.h>
|
||||
#import <SDWebImage/SDWebImageDownloaderRequestModifier.h>
|
||||
#import <SDWebImage/SDWebImageDownloaderResponseModifier.h>
|
||||
#import <SDWebImage/SDWebImageDownloaderDecryptor.h>
|
||||
#import <SDWebImage/SDImageLoader.h>
|
||||
#import <SDWebImage/SDImageLoadersManager.h>
|
||||
#import <SDWebImage/UIButton+WebCache.h>
|
||||
|
|
Loading…
Reference in New Issue