Files
OrderScheduling/Pods/CocoaDebug/Sources/CustomHTTPProtocol/_QNSURLSessionDemux.m
DDIsFriend 63ca919ed5 update
2023-08-23 09:24:40 +08:00

280 lines
10 KiB
Objective-C

//
// 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