update
This commit is contained in:
22
Pods/CocoaDebug/Sources/CustomHTTPProtocol/_CacheStoragePolicy.h
generated
Normal file
22
Pods/CocoaDebug/Sources/CustomHTTPProtocol/_CacheStoragePolicy.h
generated
Normal file
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// Example
|
||||
// man
|
||||
//
|
||||
// Created by man 11/11/2018.
|
||||
// Copyright © 2020 man. All rights reserved.
|
||||
//
|
||||
|
||||
@import Foundation;
|
||||
|
||||
/*! Determines the cache storage policy for a response.
|
||||
* \details When we provide a response up to the client we need to tell the client whether
|
||||
* the response is cacheable or not. The default HTTP/HTTPS protocol has a reasonable
|
||||
* complex chunk of code to determine this, but we can't get at it. Thus, we have to
|
||||
* reimplement it ourselves. This is split off into a separate file to emphasise that
|
||||
* this is standard boilerplate that you probably don't need to look at.
|
||||
* \param request The request that generated the response; must not be nil.
|
||||
* \param response The response itself; must not be nil.
|
||||
* \returns A cache storage policy to use.
|
||||
*/
|
||||
|
||||
extern NSURLCacheStoragePolicy CacheStoragePolicyForRequestAndResponse(NSURLRequest * request, NSHTTPURLResponse * response);
|
||||
85
Pods/CocoaDebug/Sources/CustomHTTPProtocol/_CacheStoragePolicy.m
generated
Normal file
85
Pods/CocoaDebug/Sources/CustomHTTPProtocol/_CacheStoragePolicy.m
generated
Normal file
@@ -0,0 +1,85 @@
|
||||
//
|
||||
// Example
|
||||
// man
|
||||
//
|
||||
// Created by man 11/11/2018.
|
||||
// Copyright © 2020 man. All rights reserved.
|
||||
//
|
||||
|
||||
#import "_CacheStoragePolicy.h"
|
||||
|
||||
extern NSURLCacheStoragePolicy CacheStoragePolicyForRequestAndResponse(NSURLRequest * request, NSHTTPURLResponse * response)
|
||||
// See comment in header.
|
||||
{
|
||||
BOOL cacheable;
|
||||
NSURLCacheStoragePolicy result;
|
||||
|
||||
//assert(request != NULL);
|
||||
//assert(response != NULL);
|
||||
|
||||
// First determine if the request is cacheable based on its status code.
|
||||
|
||||
switch ([response statusCode]) {
|
||||
case 200:
|
||||
case 203:
|
||||
case 206:
|
||||
case 301:
|
||||
case 304:
|
||||
case 404:
|
||||
case 410: {
|
||||
cacheable = YES;
|
||||
} break;
|
||||
default: {
|
||||
cacheable = NO;
|
||||
} break;
|
||||
}
|
||||
|
||||
// If the response might be cacheable, look at the "Cache-Control" header in
|
||||
// the response.
|
||||
|
||||
// IMPORTANT: We can't rely on -rangeOfString: returning valid results if the target
|
||||
// string is nil, so we have to explicitly test for nil in the following two cases.
|
||||
|
||||
if (cacheable) {
|
||||
NSString * responseHeader;
|
||||
|
||||
responseHeader = [[response allHeaderFields][@"Cache-Control"] lowercaseString];
|
||||
if ( (responseHeader != nil) && [responseHeader rangeOfString:@"no-store"].location != NSNotFound) {
|
||||
cacheable = NO;
|
||||
}
|
||||
}
|
||||
|
||||
// If we still think it might be cacheable, look at the "Cache-Control" header in
|
||||
// the request.
|
||||
|
||||
if (cacheable) {
|
||||
NSString * requestHeader;
|
||||
|
||||
requestHeader = [[request allHTTPHeaderFields][@"Cache-Control"] lowercaseString];
|
||||
if ( (requestHeader != nil)
|
||||
&& ([requestHeader rangeOfString:@"no-store"].location != NSNotFound)
|
||||
&& ([requestHeader rangeOfString:@"no-cache"].location != NSNotFound) ) {
|
||||
cacheable = NO;
|
||||
}
|
||||
}
|
||||
|
||||
// Use the cacheable flag to determine the result.
|
||||
|
||||
if (cacheable) {
|
||||
|
||||
// This code only caches HTTPS data in memory. This is inline with earlier versions of
|
||||
// iOS. Modern versions of iOS use file protection to protect the cache, and thus are
|
||||
// happy to cache HTTPS on disk. I've not made the correspondencing change because
|
||||
// it's nice to see all three cache policies in action.
|
||||
|
||||
if ([[[[request URL] scheme] lowercaseString] isEqual:@"https"]) {
|
||||
result = NSURLCacheStorageAllowedInMemoryOnly;
|
||||
} else {
|
||||
result = NSURLCacheStorageAllowed;
|
||||
}
|
||||
} else {
|
||||
result = NSURLCacheStorageNotAllowed;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
25
Pods/CocoaDebug/Sources/CustomHTTPProtocol/_CanonicalRequest.h
generated
Normal file
25
Pods/CocoaDebug/Sources/CustomHTTPProtocol/_CanonicalRequest.h
generated
Normal file
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// Example
|
||||
// man
|
||||
//
|
||||
// Created by man 11/11/2018.
|
||||
// Copyright © 2020 man. All rights reserved.
|
||||
//
|
||||
|
||||
@import Foundation;
|
||||
|
||||
/*! Returns a canonical form of the supplied request.
|
||||
* \details The Foundation URL loading system needs to be able to canonicalize URL
|
||||
* requests for various reasons (for example, to look for cache hits). The default
|
||||
* HTTP/HTTPS protocol has a complex chunk of code to perform this function. Unfortunately
|
||||
* there's no way for third party code to access this. Instead, we have to reimplement
|
||||
* it all ourselves. This is split off into a separate file to emphasise that this
|
||||
* is standard boilerplate that you probably don't need to look at.
|
||||
*
|
||||
* IMPORTANT: While you can take most of this code as read, you might want to tweak
|
||||
* the handling of the "Accept-Language" in the CanonicaliseHeaders routine.
|
||||
* \param request The request to canonicalise; must not be nil.
|
||||
* \returns The canonical request; should never be nil.
|
||||
*/
|
||||
|
||||
extern NSMutableURLRequest * CanonicalRequestForRequest(NSURLRequest *request);
|
||||
397
Pods/CocoaDebug/Sources/CustomHTTPProtocol/_CanonicalRequest.m
generated
Normal file
397
Pods/CocoaDebug/Sources/CustomHTTPProtocol/_CanonicalRequest.m
generated
Normal file
@@ -0,0 +1,397 @@
|
||||
//
|
||||
// Example
|
||||
// man
|
||||
//
|
||||
// Created by man 11/11/2018.
|
||||
// Copyright © 2020 man. All rights reserved.
|
||||
//
|
||||
|
||||
#import "_CanonicalRequest.h"
|
||||
|
||||
#include <xlocale.h>
|
||||
|
||||
#pragma mark * URL canonicalization steps
|
||||
|
||||
/*! A step in the canonicalisation process.
|
||||
* \details The canonicalisation process is made up of a sequence of steps, each of which is
|
||||
* implemented by a function that matches this function pointer. The function gets a URL
|
||||
* and a mutable buffer holding that URL as bytes. The function can mutate the buffer as it
|
||||
* sees fit. It typically does this by calling CFURLGetByteRangeForComponent to find the range
|
||||
* of interest in the buffer. In that case bytesInserted is the amount to adjust that range,
|
||||
* and the function should modify that to account for any bytes it inserts or deletes. If
|
||||
* the function modifies the buffer too much, it can return kCFNotFound to force the system
|
||||
* to re-create the URL from the buffer.
|
||||
* \param url The original URL to work on.
|
||||
* \param urlData The URL as a mutable buffer; the routine modifies this.
|
||||
* \param bytesInserted The number of bytes that have been inserted so far the mutable buffer.
|
||||
* \returns An updated value of bytesInserted or kCFNotFound if the URL must be reparsed.
|
||||
*/
|
||||
|
||||
typedef CFIndex (*CanonicalRequestStepFunction)(NSURL *url, NSMutableData *urlData, CFIndex bytesInserted);
|
||||
|
||||
/*! The post-scheme separate should be "://"; if that's not the case, fix it.
|
||||
* \param url The original URL to work on.
|
||||
* \param urlData The URL as a mutable buffer; the routine modifies this.
|
||||
* \param bytesInserted The number of bytes that have been inserted so far the mutable buffer.
|
||||
* \returns An updated value of bytesInserted or kCFNotFound if the URL must be reparsed.
|
||||
*/
|
||||
|
||||
static CFIndex FixPostSchemeSeparator(NSURL *url, NSMutableData *urlData, CFIndex bytesInserted)
|
||||
{
|
||||
CFRange range;
|
||||
uint8_t * urlDataBytes;
|
||||
NSUInteger urlDataLength;
|
||||
NSUInteger cursor;
|
||||
NSUInteger separatorLength;
|
||||
NSUInteger expectedSeparatorLength;
|
||||
|
||||
//assert(url != nil);
|
||||
//assert(urlData != nil);
|
||||
//assert(bytesInserted >= 0);
|
||||
|
||||
range = CFURLGetByteRangeForComponent( (CFURLRef) url, kCFURLComponentScheme, NULL);
|
||||
if (range.location != kCFNotFound) {
|
||||
//assert(range.location >= 0);
|
||||
//assert(range.length >= 0);
|
||||
|
||||
urlDataBytes = [urlData mutableBytes];
|
||||
urlDataLength = [urlData length];
|
||||
|
||||
separatorLength = 0;
|
||||
cursor = (NSUInteger) range.location + (NSUInteger) bytesInserted + (NSUInteger) range.length;
|
||||
if ( (cursor < urlDataLength) && (urlDataBytes[cursor] == ':') ) {
|
||||
cursor += 1;
|
||||
separatorLength += 1;
|
||||
if ( (cursor < urlDataLength) && (urlDataBytes[cursor] == '/') ) {
|
||||
cursor += 1;
|
||||
separatorLength += 1;
|
||||
if ( (cursor < urlDataLength) && (urlDataBytes[cursor] == '/') ) {
|
||||
cursor += 1;
|
||||
separatorLength += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma unused(cursor) // quietens an analyser warning
|
||||
|
||||
expectedSeparatorLength = strlen("://");
|
||||
if (separatorLength != expectedSeparatorLength) {
|
||||
[urlData replaceBytesInRange:NSMakeRange((NSUInteger) range.location + (NSUInteger) bytesInserted + (NSUInteger) range.length, separatorLength) withBytes:"://" length:expectedSeparatorLength];
|
||||
bytesInserted = kCFNotFound; // have to build everything now
|
||||
}
|
||||
}
|
||||
|
||||
return bytesInserted;
|
||||
}
|
||||
|
||||
/*! The scheme should be lower case; if it's not, make it so.
|
||||
* \param url The original URL to work on.
|
||||
* \param urlData The URL as a mutable buffer; the routine modifies this.
|
||||
* \param bytesInserted The number of bytes that have been inserted so far the mutable buffer.
|
||||
* \returns An updated value of bytesInserted or kCFNotFound if the URL must be reparsed.
|
||||
*/
|
||||
|
||||
static CFIndex LowercaseScheme(NSURL *url, NSMutableData *urlData, CFIndex bytesInserted)
|
||||
{
|
||||
CFRange range;
|
||||
uint8_t * urlDataBytes;
|
||||
CFIndex i;
|
||||
|
||||
//assert(url != nil);
|
||||
//assert(urlData != nil);
|
||||
//assert(bytesInserted >= 0);
|
||||
|
||||
range = CFURLGetByteRangeForComponent( (CFURLRef) url, kCFURLComponentScheme, NULL);
|
||||
if (range.location != kCFNotFound) {
|
||||
//assert(range.location >= 0);
|
||||
//assert(range.length >= 0);
|
||||
|
||||
urlDataBytes = [urlData mutableBytes];
|
||||
for (i = range.location + bytesInserted; i < (range.location + bytesInserted + range.length); i++) {
|
||||
urlDataBytes[i] = (uint8_t) tolower_l(urlDataBytes[i], NULL);
|
||||
}
|
||||
}
|
||||
return bytesInserted;
|
||||
}
|
||||
|
||||
/*! The host should be lower case; if it's not, make it so.
|
||||
* \param url The original URL to work on.
|
||||
* \param urlData The URL as a mutable buffer; the routine modifies this.
|
||||
* \param bytesInserted The number of bytes that have been inserted so far the mutable buffer.
|
||||
* \returns An updated value of bytesInserted or kCFNotFound if the URL must be reparsed.
|
||||
*/
|
||||
|
||||
static CFIndex LowercaseHost(NSURL *url, NSMutableData *urlData, CFIndex bytesInserted)
|
||||
// The host should be lower case; if it's not, make it so.
|
||||
{
|
||||
CFRange range;
|
||||
uint8_t * urlDataBytes;
|
||||
CFIndex i;
|
||||
|
||||
//assert(url != nil);
|
||||
//assert(urlData != nil);
|
||||
//assert(bytesInserted >= 0);
|
||||
|
||||
range = CFURLGetByteRangeForComponent( (CFURLRef) url, kCFURLComponentHost, NULL);
|
||||
if (range.location != kCFNotFound) {
|
||||
//assert(range.location >= 0);
|
||||
//assert(range.length >= 0);
|
||||
|
||||
urlDataBytes = [urlData mutableBytes];
|
||||
for (i = range.location + bytesInserted; i < (range.location + bytesInserted + range.length); i++) {
|
||||
urlDataBytes[i] = (uint8_t) tolower_l(urlDataBytes[i], NULL);
|
||||
}
|
||||
}
|
||||
return bytesInserted;
|
||||
}
|
||||
|
||||
/*! An empty host should be treated as "localhost" case; if it's not, make it so.
|
||||
* \param url The original URL to work on.
|
||||
* \param urlData The URL as a mutable buffer; the routine modifies this.
|
||||
* \param bytesInserted The number of bytes that have been inserted so far the mutable buffer.
|
||||
* \returns An updated value of bytesInserted or kCFNotFound if the URL must be reparsed.
|
||||
*/
|
||||
|
||||
static CFIndex FixEmptyHost(NSURL *url, NSMutableData *urlData, CFIndex bytesInserted)
|
||||
{
|
||||
CFRange range;
|
||||
CFRange rangeWithSeparator;
|
||||
|
||||
//assert(url != nil);
|
||||
//assert(urlData != nil);
|
||||
//assert(bytesInserted >= 0);
|
||||
|
||||
range = CFURLGetByteRangeForComponent( (CFURLRef) url, kCFURLComponentHost, &rangeWithSeparator);
|
||||
if (range.length == 0) {
|
||||
NSUInteger localhostLength;
|
||||
|
||||
//assert(range.location >= 0);
|
||||
//assert(range.length >= 0);
|
||||
|
||||
localhostLength = strlen("localhost");
|
||||
if (range.location != kCFNotFound) {
|
||||
[urlData replaceBytesInRange:NSMakeRange( (NSUInteger) range.location + (NSUInteger) bytesInserted, 0) withBytes:"localhost" length:localhostLength];
|
||||
bytesInserted += localhostLength;
|
||||
} else if ( (rangeWithSeparator.location != kCFNotFound) && (rangeWithSeparator.length == 0) ) {
|
||||
[urlData replaceBytesInRange:NSMakeRange((NSUInteger) rangeWithSeparator.location + (NSUInteger) bytesInserted, 0) withBytes:"localhost" length:localhostLength];
|
||||
bytesInserted += localhostLength;
|
||||
}
|
||||
}
|
||||
return bytesInserted;
|
||||
}
|
||||
|
||||
/*! Transform an empty URL path to "/". For example, "http://www.apple.com" becomes "http://www.apple.com/".
|
||||
* \param url The original URL to work on.
|
||||
* \param urlData The URL as a mutable buffer; the routine modifies this.
|
||||
* \param bytesInserted The number of bytes that have been inserted so far the mutable buffer.
|
||||
* \returns An updated value of bytesInserted or kCFNotFound if the URL must be reparsed.
|
||||
*/
|
||||
|
||||
static CFIndex FixEmptyPath(NSURL *url, NSMutableData *urlData, CFIndex bytesInserted)
|
||||
{
|
||||
CFRange range;
|
||||
CFRange rangeWithSeparator;
|
||||
|
||||
//assert(url != nil);
|
||||
//assert(urlData != nil);
|
||||
//assert(bytesInserted >= 0);
|
||||
|
||||
range = CFURLGetByteRangeForComponent( (CFURLRef) url, kCFURLComponentPath, &rangeWithSeparator);
|
||||
// The following is not a typo. We use rangeWithSeparator to find where to insert the
|
||||
// "/" and the range length to decide whether we /need/ to insert the "/".
|
||||
if ( (rangeWithSeparator.location != kCFNotFound) && (range.length == 0) ) {
|
||||
//assert(range.location >= 0);
|
||||
//assert(range.length >= 0);
|
||||
//assert(rangeWithSeparator.location >= 0);
|
||||
//assert(rangeWithSeparator.length >= 0);
|
||||
|
||||
[urlData replaceBytesInRange:NSMakeRange( (NSUInteger) rangeWithSeparator.location + (NSUInteger) bytesInserted, 0) withBytes:"/" length:1];
|
||||
bytesInserted += 1;
|
||||
}
|
||||
return bytesInserted;
|
||||
}
|
||||
|
||||
/*! If the user specified the default port (80 for HTTP, 443 for HTTPS), remove it from the URL.
|
||||
* \details Actually this code is disabled because the equivalent code in the default protocol
|
||||
* handler has also been disabled; some setups depend on get the port number in the URL, even if it
|
||||
* is the default.
|
||||
* \param url The original URL to work on.
|
||||
* \param urlData The URL as a mutable buffer; the routine modifies this.
|
||||
* \param bytesInserted The number of bytes that have been inserted so far the mutable buffer.
|
||||
* \returns An updated value of bytesInserted or kCFNotFound if the URL must be reparsed.
|
||||
*/
|
||||
|
||||
__attribute__((unused)) static CFIndex DeleteDefaultPort(NSURL *url, NSMutableData *urlData, CFIndex bytesInserted)
|
||||
{
|
||||
NSString * scheme;
|
||||
BOOL isHTTP;
|
||||
BOOL isHTTPS;
|
||||
CFRange range;
|
||||
uint8_t * urlDataBytes;
|
||||
NSString * portNumberStr;
|
||||
int portNumber;
|
||||
|
||||
//assert(url != nil);
|
||||
//assert(urlData != nil);
|
||||
//assert(bytesInserted >= 0);
|
||||
|
||||
scheme = [[url scheme] lowercaseString];
|
||||
//assert(scheme != nil);
|
||||
|
||||
isHTTP = [scheme isEqual:@"http" ];
|
||||
isHTTPS = [scheme isEqual:@"https"];
|
||||
|
||||
range = CFURLGetByteRangeForComponent( (CFURLRef) url, kCFURLComponentPort, NULL);
|
||||
if (range.location != kCFNotFound) {
|
||||
//assert(range.location >= 0);
|
||||
//assert(range.length >= 0);
|
||||
|
||||
urlDataBytes = [urlData mutableBytes];
|
||||
|
||||
portNumberStr = [[NSString alloc] initWithBytes:&urlDataBytes[range.location + bytesInserted] length:(NSUInteger) range.length encoding:NSUTF8StringEncoding];
|
||||
if (portNumberStr != nil) {
|
||||
portNumber = [portNumberStr intValue];
|
||||
if ( (isHTTP && (portNumber == 80)) || (isHTTPS && (portNumber == 443)) ) {
|
||||
// -1 and +1 to account for the leading ":"
|
||||
[urlData replaceBytesInRange:NSMakeRange((NSUInteger) range.location + (NSUInteger) bytesInserted - 1, (NSUInteger) range.length + 1) withBytes:NULL length:0];
|
||||
bytesInserted -= (range.length + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return bytesInserted;
|
||||
}
|
||||
|
||||
#pragma mark * Other request canonicalization
|
||||
|
||||
/*! Canonicalise the request headers.
|
||||
* \param request The request to canonicalise.
|
||||
*/
|
||||
|
||||
static void CanonicaliseHeaders(NSMutableURLRequest * request)
|
||||
{
|
||||
// If there's no content type and the request is a POST with a body, add a default
|
||||
// content type of "application/x-www-form-urlencoded".
|
||||
|
||||
if ( ([request valueForHTTPHeaderField:@"Content-Type"] == nil)
|
||||
&& ([[request HTTPMethod] caseInsensitiveCompare:@"POST"] == NSOrderedSame)
|
||||
&& (([request HTTPBody] != nil) || ([request HTTPBodyStream] != nil)) ) {
|
||||
[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
|
||||
}
|
||||
|
||||
// If there's no "Accept" header, add a default.
|
||||
|
||||
if ([request valueForHTTPHeaderField:@"Accept"] == nil) {
|
||||
[request setValue:@"*/*" forHTTPHeaderField:@"Accept"];
|
||||
}
|
||||
|
||||
// If there's not "Accept-Encoding" header, add a default.
|
||||
|
||||
if ([request valueForHTTPHeaderField:@"Accept-Encoding"] == nil) {
|
||||
[request setValue:@"gzip, deflate" forHTTPHeaderField:@"Accept-Encoding"];
|
||||
}
|
||||
|
||||
// If there's not an "Accept-Language" headre, add a default. This is quite bogus; ideally we
|
||||
// should derive the correct "Accept-Language" value from the langauge that the app is running
|
||||
// in. However, that's quite difficult to get right, so rather than show some general purpose
|
||||
// code that might fail in some circumstances, I've decided to just hardwire US English.
|
||||
// If you use this code in your own app you can customise it as you see fit. One option might be
|
||||
// to base this value on -[NSBundle preferredLocalizations], so that the web page comes back in
|
||||
// the language that the app is running in.
|
||||
|
||||
if ([request valueForHTTPHeaderField:@"Accept-Language"] == nil) {
|
||||
[request setValue:@"en-us" forHTTPHeaderField:@"Accept-Language"];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark * API
|
||||
|
||||
extern NSMutableURLRequest * CanonicalRequestForRequest(NSURLRequest *request)
|
||||
{
|
||||
NSMutableURLRequest * result;
|
||||
NSString * scheme;
|
||||
|
||||
//assert(request != nil);
|
||||
|
||||
// Make a mutable copy of the request.
|
||||
|
||||
result = [request mutableCopy];
|
||||
|
||||
// First up check that we're dealing with HTTP or HTTPS. If not, do nothing (why were we
|
||||
// we even called?).
|
||||
|
||||
scheme = [[[request URL] scheme] lowercaseString];
|
||||
//assert(scheme != nil);
|
||||
|
||||
if ( ! [scheme isEqual:@"http" ] && ! [scheme isEqual:@"https"]) {
|
||||
//assert(NO);
|
||||
} else {
|
||||
CFIndex bytesInserted;
|
||||
NSURL * requestURL;
|
||||
NSMutableData * urlData;
|
||||
static const CanonicalRequestStepFunction kStepFunctions[] = {
|
||||
FixPostSchemeSeparator,
|
||||
LowercaseScheme,
|
||||
LowercaseHost,
|
||||
FixEmptyHost,
|
||||
// DeleteDefaultPort, -- The built-in canonicalizer has stopped doing this, so we don't do it either.
|
||||
FixEmptyPath
|
||||
};
|
||||
size_t stepIndex;
|
||||
size_t stepCount;
|
||||
|
||||
// Canonicalise the URL by executing each of our step functions.
|
||||
|
||||
bytesInserted = kCFNotFound;
|
||||
urlData = nil;
|
||||
requestURL = [request URL];
|
||||
//assert(requestURL != nil);
|
||||
|
||||
stepCount = sizeof(kStepFunctions) / sizeof(*kStepFunctions);
|
||||
for (stepIndex = 0; stepIndex < stepCount; stepIndex++) {
|
||||
|
||||
// If we don't have valid URL data, create it from the URL.
|
||||
|
||||
//assert(requestURL != nil);
|
||||
if (bytesInserted == kCFNotFound) {
|
||||
NSData * urlDataImmutable;
|
||||
|
||||
urlDataImmutable = CFBridgingRelease( CFURLCreateData(NULL, (CFURLRef) requestURL, kCFStringEncodingUTF8, true) );
|
||||
//assert(urlDataImmutable != nil);
|
||||
|
||||
urlData = [urlDataImmutable mutableCopy];
|
||||
//assert(urlData != nil);
|
||||
|
||||
bytesInserted = 0;
|
||||
}
|
||||
//assert(urlData != nil);
|
||||
|
||||
// Run the step.
|
||||
|
||||
bytesInserted = kStepFunctions[stepIndex](requestURL, urlData, bytesInserted);
|
||||
|
||||
// Note: The following logging is useful when debugging this code. Change the
|
||||
// if expression to YES to enable it.
|
||||
|
||||
if (/* DISABLES CODE */ (NO)) {
|
||||
// fprintf(stderr, " [%zu] %.*s\n", stepIndex, (int) [urlData length], (const char *) [urlData bytes]);
|
||||
}
|
||||
|
||||
// If the step invalidated our URL (or we're on the last step, whereupon we'll need
|
||||
// the URL outside of the loop), recreate the URL from the URL data.
|
||||
|
||||
if ( (bytesInserted == kCFNotFound) || ((stepIndex + 1) == stepCount) ) {
|
||||
requestURL = CFBridgingRelease( CFURLCreateWithBytes(NULL, [urlData bytes], (CFIndex) [urlData length], kCFStringEncodingUTF8, NULL) );
|
||||
//assert(requestURL != nil);
|
||||
|
||||
urlData = nil;
|
||||
}
|
||||
}
|
||||
|
||||
[result setURL:requestURL];
|
||||
|
||||
// Canonicalise the headers.
|
||||
|
||||
CanonicaliseHeaders(result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
138
Pods/CocoaDebug/Sources/CustomHTTPProtocol/_CustomHTTPProtocol.h
generated
Normal file
138
Pods/CocoaDebug/Sources/CustomHTTPProtocol/_CustomHTTPProtocol.h
generated
Normal file
@@ -0,0 +1,138 @@
|
||||
//
|
||||
// Example
|
||||
// man
|
||||
//
|
||||
// Created by man 11/11/2018.
|
||||
// Copyright © 2020 man. All rights reserved.
|
||||
//
|
||||
|
||||
@import Foundation;
|
||||
|
||||
@protocol _CustomHTTPProtocolDelegate;
|
||||
|
||||
/*! An NSURLProtocol subclass that overrides the built-in HTTP/HTTPS protocol to intercept
|
||||
* authentication challenges for subsystems, ilke UIWebView, that don't otherwise allow it.
|
||||
* To use this class you should set up your delegate (+setDelegate:) and then call +start.
|
||||
* If you don't call +start the class is completely benign.
|
||||
*
|
||||
* The really tricky stuff here is related to the authentication challenge delegate
|
||||
* callbacks; see the docs for _CustomHTTPProtocolDelegate for the details.
|
||||
*/
|
||||
|
||||
@interface _CustomHTTPProtocol : NSURLProtocol
|
||||
|
||||
/*! Call this to start the module. Prior to this the module is just dormant, and
|
||||
* all HTTP requests proceed as normal. After this all HTTP and HTTPS requests
|
||||
* go through this module.
|
||||
*/
|
||||
|
||||
+ (void)start;
|
||||
|
||||
//liman
|
||||
+ (void)stop;
|
||||
|
||||
/*! Sets the delegate for the class.
|
||||
* \details Note that there's one delegate for the entire class, not one per
|
||||
* instance of the class as is more normal. The delegate is not retained in general,
|
||||
* but is retained for the duration of any given call. Once you set the delegate to nil
|
||||
* you can be assured that it won't be called unretained (that is, by the time that
|
||||
* -setDelegate: returns, we've already done all possible retains on the delegate).
|
||||
* \param newValue The new delegate to use; may be nil.
|
||||
*/
|
||||
|
||||
+ (void)setDelegate:(id<_CustomHTTPProtocolDelegate>)newValue;
|
||||
|
||||
/*! Returns the class delegate.
|
||||
*/
|
||||
|
||||
+ (id<_CustomHTTPProtocolDelegate>)delegate;
|
||||
|
||||
@property (atomic, strong, readonly ) NSURLAuthenticationChallenge * pendingChallenge; ///< The current authentication challenge; it's only safe to access this from the main thread.
|
||||
|
||||
/*! Call this method to resolve an authentication challeng. This must be called on the main thread.
|
||||
* \param challenge The challenge to resolve. This must match the pendingChallenge property.
|
||||
* \param credential The credential to use, or nil to continue without a credential.
|
||||
*/
|
||||
|
||||
- (void)resolveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge withCredential:(NSURLCredential *)credential;
|
||||
|
||||
@end
|
||||
|
||||
/*! The delegate for the CustomHTTPProtocol class (not its instances).
|
||||
* \details The delegate handles two different types of callbacks:
|
||||
*
|
||||
* - authentication challenges
|
||||
*
|
||||
* - logging
|
||||
*
|
||||
* The latter is very simple. The former is quite tricky. The basic idea is that each CustomHTTPProtocol
|
||||
* instance sends the delegate a serialised stream of authentication challenges, each of which it is
|
||||
* expected to resolve. The sequence is as follows:
|
||||
*
|
||||
* -# It calls -customHTTPProtocol:canAuthenticateAgainstProtectionSpace: to determine if the delegate
|
||||
* can handle the challenge. This can be call on an arbitrary background thread.
|
||||
*
|
||||
* -# If the delegate returns YES, it calls -customHTTPProtocol:didReceiveAuthenticationChallenge: to
|
||||
* actually process the challenge. This is always called on the main thread. The delegate can resolve
|
||||
* the challenge synchronously (that is, before returning from the call) or it can return from the call
|
||||
* and then, later on, resolve the challenge. Resolving the challenge involves calling
|
||||
* -[CustomHTTPProtocol resolveAuthenticationChallenge:withCredential:], which also must be called
|
||||
* on the main thread. Between the calls to -customHTTPProtocol:didReceiveAuthenticationChallenge:
|
||||
* and -[CustomHTTPProtocol resolveAuthenticationChallenge:withCredential:], the protocol's
|
||||
* pendingChallenge property will contain the challenge.
|
||||
*
|
||||
* -# While there is a pending challenge, the protocol may call -customHTTPProtocol:didCancelAuthenticationChallenge:
|
||||
* to cancel the challenge. This is always called on the main thread.
|
||||
*
|
||||
* Note that this design follows the original NSURLConnection model, not the newer NSURLConnection model
|
||||
* (introduced in OS X 10.7 / iOS 5) or the NSURLSession model, because of my concerns about performance.
|
||||
* Specifically, -customHTTPProtocol:canAuthenticateAgainstProtectionSpace: can be called on any thread
|
||||
* but -customHTTPProtocol:didReceiveAuthenticationChallenge: is called on the main thread. If I unified
|
||||
* them I'd end up calling the resulting single routine on the main thread, which meanings a lot more
|
||||
* bouncing between threads, much of which would be pointless in the common case where you don't want to
|
||||
* customise the default behaviour. Alternatively I could call the unified routine on an arbitrary thread,
|
||||
* but that would make it harder for clients and require a major rework of my implementation.
|
||||
*/
|
||||
|
||||
@protocol _CustomHTTPProtocolDelegate <NSObject>
|
||||
|
||||
@optional
|
||||
|
||||
/*! Called by an CustomHTTPProtocol instance to ask the delegate whether it's prepared to handle
|
||||
* a particular authentication challenge. Can be called on any thread.
|
||||
* \param protocol The protocol instance itself; will not be nil.
|
||||
* \param protectionSpace The protection space for the authentication challenge; will not be nil.
|
||||
* \returns Return YES if you want the -customHTTPProtocol:didReceiveAuthenticationChallenge: delegate
|
||||
* callback, or NO for the challenge to be handled in the default way.
|
||||
*/
|
||||
|
||||
- (BOOL)customHTTPProtocol:(_CustomHTTPProtocol *)protocol canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace;
|
||||
|
||||
/*! Called by an CustomHTTPProtocol instance to request that the delegate process on authentication
|
||||
* challenge. Will be called on the main thread. Unless the challenge is cancelled (see below)
|
||||
* the delegate must eventually resolve it by calling -resolveAuthenticationChallenge:withCredential:.
|
||||
* \param protocol The protocol instance itself; will not be nil.
|
||||
* \param challenge The authentication challenge; will not be nil.
|
||||
*/
|
||||
|
||||
- (void)customHTTPProtocol:(_CustomHTTPProtocol *)protocol didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;
|
||||
|
||||
/*! Called by an CustomHTTPProtocol instance to cancel an issued authentication challenge.
|
||||
* Will be called on the main thread.
|
||||
* \param protocol The protocol instance itself; will not be nil.
|
||||
* \param challenge The authentication challenge; will not be nil; will match the challenge
|
||||
* previously issued by -customHTTPProtocol:canAuthenticateAgainstProtectionSpace:.
|
||||
*/
|
||||
|
||||
- (void)customHTTPProtocol:(_CustomHTTPProtocol *)protocol didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;
|
||||
|
||||
/*! Called by the CustomHTTPProtocol to log various bits of information.
|
||||
* Can be called on any thread.
|
||||
* \param protocol The protocol instance itself; nil to indicate log messages from the class itself.
|
||||
* \param format A standard NSString-style format string; will not be nil.
|
||||
* \param arguments Arguments for that format string.
|
||||
*/
|
||||
|
||||
- (void)customHTTPProtocol:(_CustomHTTPProtocol *)protocol logWithFormat:(NSString *)format arguments:(va_list)arguments;
|
||||
|
||||
@end
|
||||
1189
Pods/CocoaDebug/Sources/CustomHTTPProtocol/_CustomHTTPProtocol.m
generated
Normal file
1189
Pods/CocoaDebug/Sources/CustomHTTPProtocol/_CustomHTTPProtocol.m
generated
Normal file
File diff suppressed because it is too large
Load Diff
52
Pods/CocoaDebug/Sources/CustomHTTPProtocol/_QNSURLSessionDemux.h
generated
Normal file
52
Pods/CocoaDebug/Sources/CustomHTTPProtocol/_QNSURLSessionDemux.h
generated
Normal file
@@ -0,0 +1,52 @@
|
||||
//
|
||||
// Example
|
||||
// man
|
||||
//
|
||||
// Created by man 11/11/2018.
|
||||
// Copyright © 2020 man. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
/*! A simple class for demultiplexing NSURLSession delegate callbacks to a per-task delegate object.
|
||||
|
||||
You initialise the class with a session configuration. After that you can create data tasks
|
||||
within that session by calling -dataTaskWithRequest:delegate:modes:. Any delegate callbacks
|
||||
for that data task are redirected to the delegate on the thread that created the task in
|
||||
one of the specified run loop modes. That thread must run its run loop in order to get
|
||||
these callbacks.
|
||||
*/
|
||||
|
||||
@interface _QNSURLSessionDemux : NSObject
|
||||
|
||||
/*! Create a demultiplex for the specified session configuration.
|
||||
* \param configuration The session configuration to use; if nil, a default session is created.
|
||||
* \returns An initialised instance.
|
||||
*/
|
||||
|
||||
- (instancetype)initWithConfiguration:(NSURLSessionConfiguration *)configuration;
|
||||
|
||||
@property (atomic, copy, readonly ) NSURLSessionConfiguration * configuration; ///< A copy of the configuration passed to -initWithConfiguration:.
|
||||
@property (atomic, strong, readonly ) NSURLSession * session; ///< The session created from the configuration passed to -initWithConfiguration:.
|
||||
|
||||
/*! Creates a new data task whose delegate callbacks are routed to the supplied delegate.
|
||||
* \details The callbacks are run on the current thread (that is, the thread that called this
|
||||
* method) in the specified modes.
|
||||
*
|
||||
* The delegate is retained until the task completes, that is, until after your
|
||||
* -URLSession:task:didCompleteWithError: delegate callback returns.
|
||||
*
|
||||
* The returned task is suspend. You must resume the returned task for the task to
|
||||
* make progress. Furthermore, it's not safe to simply discard the returned task
|
||||
* because in that case the task's delegate is never released.
|
||||
*
|
||||
* \param request The request that the data task executes; must not be nil.
|
||||
* \param delegate The delegate to receive the data task's delegate callbacks; must not be nil.
|
||||
* \param modes The run loop modes in which to run the data task's delegate callbacks; if nil or
|
||||
* empty, the default run loop mode (NSDefaultRunLoopMode is used).
|
||||
* \returns A suspended data task that you must resume.
|
||||
*/
|
||||
|
||||
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request delegate:(id<NSURLSessionDataDelegate>)delegate modes:(NSArray *)modes;
|
||||
|
||||
@end
|
||||
279
Pods/CocoaDebug/Sources/CustomHTTPProtocol/_QNSURLSessionDemux.m
generated
Normal file
279
Pods/CocoaDebug/Sources/CustomHTTPProtocol/_QNSURLSessionDemux.m
generated
Normal file
@@ -0,0 +1,279 @@
|
||||
//
|
||||
// Example
|
||||
// man
|
||||
//
|
||||
// Created by man 11/11/2018.
|
||||
// Copyright © 2020 man. All rights reserved.
|
||||
//
|
||||
|
||||
#import "_QNSURLSessionDemux.h"
|
||||
|
||||
@interface _QNSURLSessionDemuxTaskInfo : NSObject
|
||||
|
||||
- (instancetype)initWithTask:(NSURLSessionDataTask *)task delegate:(id<NSURLSessionDataDelegate>)delegate modes:(NSArray *)modes;
|
||||
|
||||
@property (atomic, strong, readonly ) NSURLSessionDataTask * task;
|
||||
@property (atomic, strong, readonly ) id<NSURLSessionDataDelegate> delegate;
|
||||
@property (atomic, strong, readonly ) NSThread * thread;
|
||||
@property (atomic, copy, readonly ) NSArray * modes;
|
||||
|
||||
- (void)performBlock:(dispatch_block_t)block;
|
||||
|
||||
- (void)invalidate;
|
||||
|
||||
@end
|
||||
|
||||
@interface _QNSURLSessionDemuxTaskInfo ()
|
||||
|
||||
@property (atomic, strong, readwrite) id<NSURLSessionDataDelegate> delegate;
|
||||
@property (atomic, strong, readwrite) NSThread * thread;
|
||||
|
||||
@end
|
||||
|
||||
@implementation _QNSURLSessionDemuxTaskInfo
|
||||
|
||||
- (instancetype)initWithTask:(NSURLSessionDataTask *)task delegate:(id<NSURLSessionDataDelegate>)delegate modes:(NSArray *)modes
|
||||
{
|
||||
//assert(task != nil);
|
||||
//assert(delegate != nil);
|
||||
//assert(modes != nil);
|
||||
|
||||
self = [super init];
|
||||
if (self != nil) {
|
||||
self->_task = task;
|
||||
self->_delegate = delegate;
|
||||
self->_thread = [NSThread currentThread];
|
||||
self->_modes = [modes copy];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)performBlock:(dispatch_block_t)block
|
||||
{
|
||||
//assert(self.delegate != nil);
|
||||
//assert(self.thread != nil);
|
||||
[self performSelector:@selector(performBlockOnClientThread:) onThread:self.thread withObject:[block copy] waitUntilDone:NO modes:self.modes];
|
||||
}
|
||||
|
||||
- (void)performBlockOnClientThread:(dispatch_block_t)block
|
||||
{
|
||||
//assert([NSThread currentThread] == self.thread);
|
||||
block();
|
||||
}
|
||||
|
||||
- (void)invalidate
|
||||
{
|
||||
self.delegate = nil;
|
||||
self.thread = nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface _QNSURLSessionDemux () <NSURLSessionDataDelegate>
|
||||
|
||||
@property (atomic, strong, readonly ) NSMutableDictionary * taskInfoByTaskID; // keys NSURLSessionTask taskIdentifier, values are SessionManager
|
||||
@property (atomic, strong, readonly ) NSOperationQueue * sessionDelegateQueue;
|
||||
|
||||
@end
|
||||
|
||||
@implementation _QNSURLSessionDemux
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
return [self initWithConfiguration:nil];
|
||||
}
|
||||
|
||||
- (instancetype)initWithConfiguration:(NSURLSessionConfiguration *)configuration
|
||||
{
|
||||
// configuration may be nil
|
||||
self = [super init];
|
||||
if (self != nil) {
|
||||
if (configuration == nil) {
|
||||
configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
|
||||
}
|
||||
self->_configuration = [configuration copy];
|
||||
|
||||
self->_taskInfoByTaskID = [[NSMutableDictionary alloc] init];
|
||||
|
||||
self->_sessionDelegateQueue = [[NSOperationQueue alloc] init];
|
||||
[self->_sessionDelegateQueue setMaxConcurrentOperationCount:1];
|
||||
[self->_sessionDelegateQueue setName:@"_QNSURLSessionDemux"];
|
||||
|
||||
self->_session = [NSURLSession sessionWithConfiguration:self->_configuration delegate:self delegateQueue:self->_sessionDelegateQueue];
|
||||
self->_session.sessionDescription = @"_QNSURLSessionDemux";
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request delegate:(id<NSURLSessionDataDelegate>)delegate modes:(NSArray *)modes
|
||||
{
|
||||
NSURLSessionDataTask * task;
|
||||
_QNSURLSessionDemuxTaskInfo * taskInfo;
|
||||
|
||||
//assert(request != nil);
|
||||
//assert(delegate != nil);
|
||||
// modes may be nil
|
||||
|
||||
if ([modes count] == 0) {
|
||||
modes = @[ NSDefaultRunLoopMode ];
|
||||
}
|
||||
|
||||
task = [self.session dataTaskWithRequest:request];
|
||||
//assert(task != nil);
|
||||
|
||||
taskInfo = [[_QNSURLSessionDemuxTaskInfo alloc] initWithTask:task delegate:delegate modes:modes];
|
||||
|
||||
@synchronized (self) {
|
||||
self.taskInfoByTaskID[@(task.taskIdentifier)] = taskInfo;
|
||||
}
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
- (_QNSURLSessionDemuxTaskInfo *)taskInfoForTask:(NSURLSessionTask *)task
|
||||
{
|
||||
_QNSURLSessionDemuxTaskInfo * result;
|
||||
|
||||
//assert(task != nil);
|
||||
|
||||
@synchronized (self) {
|
||||
result = self.taskInfoByTaskID[@(task.taskIdentifier)];
|
||||
//assert(result != nil);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task willPerformHTTPRedirection:(NSHTTPURLResponse *)response newRequest:(NSURLRequest *)newRequest completionHandler:(void (^)(NSURLRequest *))completionHandler
|
||||
{
|
||||
_QNSURLSessionDemuxTaskInfo * taskInfo;
|
||||
|
||||
taskInfo = [self taskInfoForTask:task];
|
||||
if ([taskInfo.delegate respondsToSelector:@selector(URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:)]) {
|
||||
[taskInfo performBlock:^{
|
||||
[taskInfo.delegate URLSession:session task:task willPerformHTTPRedirection:response newRequest:newRequest completionHandler:completionHandler];
|
||||
}];
|
||||
} else {
|
||||
completionHandler(newRequest);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
|
||||
{
|
||||
_QNSURLSessionDemuxTaskInfo * taskInfo;
|
||||
|
||||
taskInfo = [self taskInfoForTask:task];
|
||||
if ([taskInfo.delegate respondsToSelector:@selector(URLSession:task:didReceiveChallenge:completionHandler:)]) {
|
||||
[taskInfo performBlock:^{
|
||||
[taskInfo.delegate URLSession:session task:task didReceiveChallenge:challenge completionHandler:completionHandler];
|
||||
}];
|
||||
} else {
|
||||
completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task needNewBodyStream:(void (^)(NSInputStream *bodyStream))completionHandler
|
||||
{
|
||||
_QNSURLSessionDemuxTaskInfo * taskInfo;
|
||||
|
||||
taskInfo = [self taskInfoForTask:task];
|
||||
if ([taskInfo.delegate respondsToSelector:@selector(URLSession:task:needNewBodyStream:)]) {
|
||||
[taskInfo performBlock:^{
|
||||
[taskInfo.delegate URLSession:session task:task needNewBodyStream:completionHandler];
|
||||
}];
|
||||
} else {
|
||||
completionHandler(nil);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend
|
||||
{
|
||||
_QNSURLSessionDemuxTaskInfo * taskInfo;
|
||||
|
||||
taskInfo = [self taskInfoForTask:task];
|
||||
if ([taskInfo.delegate respondsToSelector:@selector(URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:)]) {
|
||||
[taskInfo performBlock:^{
|
||||
[taskInfo.delegate URLSession:session task:task didSendBodyData:bytesSent totalBytesSent:totalBytesSent totalBytesExpectedToSend:totalBytesExpectedToSend];
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
|
||||
{
|
||||
_QNSURLSessionDemuxTaskInfo * taskInfo;
|
||||
|
||||
taskInfo = [self taskInfoForTask:task];
|
||||
|
||||
// This is our last delegate callback so we remove our task info record.
|
||||
|
||||
@synchronized (self) {
|
||||
[self.taskInfoByTaskID removeObjectForKey:@(taskInfo.task.taskIdentifier)];
|
||||
}
|
||||
|
||||
// Call the delegate if required. In that case we invalidate the task info on the client thread
|
||||
// after calling the delegate, otherwise the client thread side of the -performBlock: code can
|
||||
// find itself with an invalidated task info.
|
||||
|
||||
if ([taskInfo.delegate respondsToSelector:@selector(URLSession:task:didCompleteWithError:)]) {
|
||||
[taskInfo performBlock:^{
|
||||
[taskInfo.delegate URLSession:session task:task didCompleteWithError:error];
|
||||
[taskInfo invalidate];
|
||||
}];
|
||||
} else {
|
||||
[taskInfo invalidate];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler
|
||||
{
|
||||
_QNSURLSessionDemuxTaskInfo * taskInfo;
|
||||
|
||||
taskInfo = [self taskInfoForTask:dataTask];
|
||||
if ([taskInfo.delegate respondsToSelector:@selector(URLSession:dataTask:didReceiveResponse:completionHandler:)]) {
|
||||
[taskInfo performBlock:^{
|
||||
[taskInfo.delegate URLSession:session dataTask:dataTask didReceiveResponse:response completionHandler:completionHandler];
|
||||
}];
|
||||
} else {
|
||||
completionHandler(NSURLSessionResponseAllow);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask
|
||||
{
|
||||
_QNSURLSessionDemuxTaskInfo * taskInfo;
|
||||
|
||||
taskInfo = [self taskInfoForTask:dataTask];
|
||||
if ([taskInfo.delegate respondsToSelector:@selector(URLSession:dataTask:didBecomeDownloadTask:)]) {
|
||||
[taskInfo performBlock:^{
|
||||
[taskInfo.delegate URLSession:session dataTask:dataTask didBecomeDownloadTask:downloadTask];
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
|
||||
{
|
||||
_QNSURLSessionDemuxTaskInfo * taskInfo;
|
||||
|
||||
taskInfo = [self taskInfoForTask:dataTask];
|
||||
if ([taskInfo.delegate respondsToSelector:@selector(URLSession:dataTask:didReceiveData:)]) {
|
||||
[taskInfo performBlock:^{
|
||||
[taskInfo.delegate URLSession:session dataTask:dataTask didReceiveData:data];
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask willCacheResponse:(NSCachedURLResponse *)proposedResponse completionHandler:(void (^)(NSCachedURLResponse *cachedResponse))completionHandler
|
||||
{
|
||||
_QNSURLSessionDemuxTaskInfo * taskInfo;
|
||||
|
||||
taskInfo = [self taskInfoForTask:dataTask];
|
||||
if ([taskInfo.delegate respondsToSelector:@selector(URLSession:dataTask:willCacheResponse:completionHandler:)]) {
|
||||
[taskInfo performBlock:^{
|
||||
[taskInfo.delegate URLSession:session dataTask:dataTask willCacheResponse:proposedResponse completionHandler:completionHandler];
|
||||
}];
|
||||
} else {
|
||||
completionHandler(proposedResponse);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
Reference in New Issue
Block a user