Add the response modifier and data decrypter, which allows user to provide a modified version of URL Response and image data, like Gzip or other encoding form

This commit is contained in:
DreamPiggy 2019-10-15 14:36:41 +08:00
parent a42a22ff88
commit 68d73f4cb2
10 changed files with 158 additions and 4 deletions

View File

@ -63,6 +63,10 @@
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 */; };
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 +284,7 @@
dstPath = include/SDWebImage;
dstSubfolderSpec = 16;
files = (
325427662355783C0042BAA4 /* SDWebImageDownloaderResponseModifier.h in Copy Headers */,
3298655F233723220071958B /* SDImageHEICCoder.h in Copy Headers */,
32C78E3823336FC800C6B7F8 /* SDImageIOAnimatedCoder.h in Copy Headers */,
32E5690822B1FFCA00CBABC6 /* SDWebImageOptionsProcessor.h in Copy Headers */,
@ -370,6 +375,8 @@
324DF4B3200A14DC008A84CC /* SDWebImageDefine.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SDWebImageDefine.m; path = Core/SDWebImageDefine.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 +764,8 @@
32B9B536206ED4230026769D /* SDWebImageDownloaderConfig.m */,
32F21B4F20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h */,
32F21B5020788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m */,
32542761235576E20042BAA4 /* SDWebImageDownloaderResponseModifier.h */,
32542762235576E20042BAA4 /* SDWebImageDownloaderResponseModifier.m */,
321B377D2083290D00C0EA77 /* SDImageLoader.h */,
321B377E2083290D00C0EA77 /* SDImageLoader.m */,
321B377F2083290E00C0EA77 /* SDImageLoadersManager.h */,
@ -833,6 +842,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 */,
@ -1073,6 +1083,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 */,
@ -1138,6 +1149,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 */,

View File

@ -233,6 +233,11 @@ FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextAnimat
*/
FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextDownloadRequestModifier;
/**
A id<SDWebImageDownloaderResponseModifier> instance to modify the image download response and download data. It's used for downloader to modify the original response and data from URL and options. This can be used for image data decryption, such as Gzipped image. 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<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>)
*/

View File

@ -126,5 +126,6 @@ SDWebImageContextOption const SDWebImageContextStoreCacheType = @"storeCacheType
SDWebImageContextOption const SDWebImageContextOriginalStoreCacheType = @"originalStoreCacheType";
SDWebImageContextOption const SDWebImageContextAnimatedImageClass = @"animatedImageClass";
SDWebImageContextOption const SDWebImageContextDownloadRequestModifier = @"downloadRequestModifier";
SDWebImageContextOption const SDWebImageContextDownloadResponseModifier = @"downloadResponseModifier";
SDWebImageContextOption const SDWebImageContextCacheKeyFilter = @"cacheKeyFilter";
SDWebImageContextOption const SDWebImageContextCacheSerializer = @"cacheSerializer";

View File

@ -12,6 +12,7 @@
#import "SDWebImageOperation.h"
#import "SDWebImageDownloaderConfig.h"
#import "SDWebImageDownloaderRequestModifier.h"
#import "SDWebImageDownloaderResponseModifier.h"
#import "SDImageLoader.h"
/// Downloader options
@ -148,6 +149,14 @@ typedef SDImageLoaderCompletedBlock SDWebImageDownloaderCompletedBlock;
*/
@property (nonatomic, strong, nullable) id<SDWebImageDownloaderRequestModifier> requestModifier;
/**
* Set the response modifier to modify the original download response or download data before decoding. This can be used for image data decryption, such as Gzipped image.
* This request modifier method will be called for each downloading image response. Return the original response or data means no modication. Return nil from either response or data, will mark this download failed, pay attention to this.
* Defaults to nil, means does not modify the original download response or download data.
* @note If you want to modify single response, consider using `SDWebImageContextDownloadResponseModifier` context option.
*/
@property (nonatomic, strong, nullable) id<SDWebImageDownloaderResponseModifier> responseModifier;
/**
* 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.

View File

@ -272,6 +272,7 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext;
SD_LOCK(self.HTTPHeadersLock);
mutableRequest.allHTTPHeaderFields = self.HTTPHeaders;
SD_UNLOCK(self.HTTPHeadersLock);
// Request Modifier
id<SDWebImageDownloaderRequestModifier> requestModifier;
if ([context valueForKey:SDWebImageContextDownloadRequestModifier]) {
requestModifier = [context valueForKey:SDWebImageContextDownloadRequestModifier];
@ -291,6 +292,25 @@ 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) {
SDWebImageMutableContext *mutableContext;
if (context) {
mutableContext = [context mutableCopy];
} else {
mutableContext = [NSMutableDictionary dictionary];
}
mutableContext[SDWebImageContextDownloadResponseModifier] = responseModifier;
context = [mutableContext copy];
}
// Operation Class
Class operationClass = self.config.operationClass;
if (operationClass && [operationClass isSubclassOfClass:[NSOperation class]] && [operationClass conformsToProtocol:@protocol(SDWebImageDownloaderOperation)]) {
// Custom operation class

View File

@ -9,6 +9,7 @@
#import "SDWebImageDownloaderOperation.h"
#import "SDWebImageError.h"
#import "SDInternalMacros.h"
#import "SDWebImageDownloaderResponseModifier.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))
@ -37,6 +38,7 @@ typedef NSMutableDictionary<NSString *, id> SDCallbacksDictionary;
@property (assign, nonatomic) NSUInteger receivedSize;
@property (strong, nonatomic, nullable, readwrite) NSURLResponse *response;
@property (strong, nonatomic, nullable) NSError *responseError;
@property (strong, nonatomic, nullable) id<SDWebImageDownloaderResponseModifier> responseModifier; // modifiy original URLResponse and Data
@property (assign, nonatomic) double previousProgress; // previous progress percent
// 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
@ -293,13 +295,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 +369,10 @@ didReceiveResponse:(NSURLResponse *)response
return;
}
self.previousProgress = currentProgress;
if (self.options & SDWebImageDownloaderProgressiveLoad) {
// Response Modifier disable the progressive decoding, no supporting for progressive data modification
BOOL supportProgressive = (self.options & SDWebImageDownloaderProgressiveLoad) && !self.responseModifier;
if (supportProgressive) {
// Get the image data
NSData *imageData = [self.imageData copy];
@ -421,6 +439,10 @@ didReceiveResponse:(NSURLResponse *)response
if ([self callbacksForKey:kCompletedCallbackKey].count > 0) {
NSData *imageData = [self.imageData copy];
self.imageData = nil;
// response modifier
if (imageData && self.responseModifier) {
imageData = [self.responseModifier modifiedDataWithData: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

View File

@ -0,0 +1,34 @@
/*
* 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);
typedef NSData * _Nullable (^SDWebImageDownloaderResponseModifierDataBlock)(NSData * _Nonnull data, NSURLResponse * _Nullable 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>
- (nullable NSData *)modifiedDataWithData:(nonnull NSData *)data response:(nullable NSURLResponse *)response;
- (nullable NSURLResponse *)modifiedResponseWithResponse:(nonnull NSURLResponse *)response;
@end
/**
A downloader response modifier class with block.
*/
@interface SDWebImageDownloaderResponseModifier : NSObject <SDWebImageDownloaderResponseModifier>
- (nonnull instancetype)initWithResponseBlock:(nonnull SDWebImageDownloaderResponseModifierBlock)responseBlock dataBlock:(nonnull SDWebImageDownloaderResponseModifierDataBlock)dataBlock;
+ (nonnull instancetype)responseModifierWithResponseBlock:(nonnull SDWebImageDownloaderResponseModifierBlock)responseBlock dataBlock:(nonnull SDWebImageDownloaderResponseModifierDataBlock)dataBlock;
@end

View File

@ -0,0 +1,49 @@
/*
* 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 responseBlock;
@property (nonatomic, copy, nonnull) SDWebImageDownloaderResponseModifierDataBlock dataBlock;
@end
@implementation SDWebImageDownloaderResponseModifier
- (instancetype)initWithResponseBlock:(SDWebImageDownloaderResponseModifierBlock)responseBlock dataBlock:(SDWebImageDownloaderResponseModifierDataBlock)dataBlock {
self = [super init];
if (self) {
self.responseBlock = responseBlock;
self.dataBlock = dataBlock;
}
return self;
}
+ (instancetype)responseModifierWithResponseBlock:(SDWebImageDownloaderResponseModifierBlock)responseBlock dataBlock:(SDWebImageDownloaderResponseModifierDataBlock)dataBlock {
SDWebImageDownloaderResponseModifier *responseModifier = [[SDWebImageDownloaderResponseModifier alloc] initWithResponseBlock:responseBlock dataBlock:dataBlock];
return responseModifier;
}
- (nullable NSData *)modifiedDataWithData:(nonnull NSData *)data response:(nullable NSURLResponse *)response {
if (!self.dataBlock) {
return nil;
}
return self.dataBlock(data, response);
}
- (nullable NSURLResponse *)modifiedResponseWithResponse:(nonnull NSURLResponse *)response {
if (!self.responseBlock) {
return nil;
}
return self.responseBlock(response);
}
@end

View File

@ -21,5 +21,6 @@ typedef NS_ERROR_ENUM(SDWebImageErrorDomain, SDWebImageError) {
SDWebImageErrorCacheNotModified = 1002, // The remote location specify that the cached image is not modified, such as the HTTP response 304 code. It's useful for `SDWebImageRefreshCached`
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`
SDWebImageErrorInvalidDownloadResponse = 2002, // When using response modifier, the modified download response is nil and marked as cancelled.
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.
};

View File

@ -36,6 +36,7 @@ FOUNDATION_EXPORT const unsigned char WebImageVersionString[];
#import <SDWebImage/SDWebImageDownloaderConfig.h>
#import <SDWebImage/SDWebImageDownloaderOperation.h>
#import <SDWebImage/SDWebImageDownloaderRequestModifier.h>
#import <SDWebImage/SDWebImageDownloaderResponseModifier.h>
#import <SDWebImage/SDImageLoader.h>
#import <SDWebImage/SDImageLoadersManager.h>
#import <SDWebImage/UIButton+WebCache.h>