2023-12-23 01:44:50 +00:00
|
|
|
|
/**
|
|
|
|
|
NSURLSession.m
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
Copyright (C) 2017-2023 Free Software Foundation, Inc.
|
2023-12-23 01:44:50 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
Written by: Daniel Ferreira <dtf@stanford.edu>
|
|
|
|
|
Date: November 2017
|
|
|
|
|
Author: Richard Frith-Macdonald <richard@brainstorm.co.uk>
|
2023-12-23 01:44:50 +00:00
|
|
|
|
|
|
|
|
|
This file is part of GNUStep-base
|
|
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
|
modify it under the terms of the GNU Lesser General Public
|
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
Lesser General Public License for more details.
|
|
|
|
|
|
|
|
|
|
If you are interested in a warranty or support for this source code,
|
|
|
|
|
contact Scott Christley <scottc@net-community.com> for more information.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
|
|
|
License along with this library; if not, write to the Free
|
|
|
|
|
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
|
|
|
Boston, MA 02110 USA.
|
|
|
|
|
*/
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
#import "GSURLPrivate.h"
|
|
|
|
|
#import <curl/curl.h>
|
|
|
|
|
|
|
|
|
|
#import "GSDispatch.h"
|
|
|
|
|
#import "GSEasyHandle.h"
|
|
|
|
|
#import "GSHTTPURLProtocol.h"
|
|
|
|
|
#import "GSMultiHandle.h"
|
|
|
|
|
#import "GSPThread.h"
|
|
|
|
|
#import "GSTaskRegistry.h"
|
|
|
|
|
#import "GSURLSessionTaskBody.h"
|
|
|
|
|
|
|
|
|
|
#import "Foundation/NSError.h"
|
|
|
|
|
#import "Foundation/NSException.h"
|
|
|
|
|
#import "Foundation/NSOperation.h"
|
|
|
|
|
#import "Foundation/NSPredicate.h"
|
|
|
|
|
#import "Foundation/NSURLError.h"
|
|
|
|
|
#import "Foundation/NSURLSession.h"
|
|
|
|
|
#import "Foundation/NSURLRequest.h"
|
|
|
|
|
#import "Foundation/NSValue.h"
|
|
|
|
|
|
|
|
|
|
GS_DECLARE const float NSURLSessionTaskPriorityDefault = 0.5;
|
|
|
|
|
GS_DECLARE const float NSURLSessionTaskPriorityLow = 0.0;
|
|
|
|
|
GS_DECLARE const float NSURLSessionTaskPriorityHigh = 1.0;
|
|
|
|
|
|
|
|
|
|
GS_DECLARE const int64_t NSURLSessionTransferSizeUnknown = -1;
|
|
|
|
|
|
|
|
|
|
/* NSURLSession API implementation overview
|
|
|
|
|
*
|
|
|
|
|
* This implementation uses libcurl for the HTTP layer implementation. At a
|
|
|
|
|
* high level, the [NSURLSession] keeps a curl *multi handle*, and each
|
|
|
|
|
* [NSURLSessionTask] has an *easy handle*. This way these two APIs somewhat
|
|
|
|
|
* have a 1-to-1 mapping.
|
|
|
|
|
*
|
|
|
|
|
* The [NSURLSessionTask] class is in charge of configuring its *easy handle*
|
|
|
|
|
* and adding it to the owning session’s *multi handle*. Adding / removing
|
|
|
|
|
* the handle effectively resumes / suspends the transfer.
|
|
|
|
|
*
|
|
|
|
|
* The [NSURLSessionTasks] class has subclasses, but this design puts all the
|
|
|
|
|
* logic into the parent [NSURLSessionTask].
|
|
|
|
|
*
|
|
|
|
|
* The session class uses the [GSTaskRegistry] to keep track of its tasks.
|
|
|
|
|
*
|
|
|
|
|
* The task class uses an GSInternalState type together with GSTransferState
|
|
|
|
|
* to keep track of its state and each transfer’s state.
|
|
|
|
|
* NB. a single task may do multiple transfers (e.g. as the result of a
|
|
|
|
|
* redirect).
|
|
|
|
|
*
|
|
|
|
|
* The [NSURLSession] has a libdispatch *work queue*, and all internal work is
|
|
|
|
|
* done on that queue, such that the code doesn't have to deal with thread
|
|
|
|
|
* safety beyond that. All work inside a [NSURLSessionTask] will run on this
|
|
|
|
|
* work queue, and so will code manipulating the session's *multi handle*.
|
|
|
|
|
*
|
|
|
|
|
* Delegate callbacks are, however, done on the passed in delegateQueue.
|
|
|
|
|
* Any calls into this API need to switch onto the *work queue* as needed.
|
|
|
|
|
*
|
|
|
|
|
* Most of HTTP is defined in [RFC 2616](https://tools.ietf.org/html/rfc2616).
|
|
|
|
|
* While libcurl handles many of these details, some are handled by this
|
|
|
|
|
* NSURLSession implementation.
|
|
|
|
|
*/
|
|
|
|
|
@interface NSURLSession ()
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (dispatch_queue_t) workQueue;
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
@end
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
@interface NSURLSessionTask()
|
|
|
|
|
- (instancetype) initWithSession: (NSURLSession*)session
|
|
|
|
|
request: (NSURLRequest*)request
|
|
|
|
|
taskIdentifier: (NSUInteger)identifier;
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (void) getProtocolWithCompletion: (void (^)(NSURLProtocol* protocol))completion;
|
2023-01-11 11:02:03 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (void) setState: (NSURLSessionTaskState)state;
|
2023-01-11 11:02:03 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (void) invalidateProtocol;
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (void (^)(NSData *data, NSURLResponse *response, NSError *error)) dataCompletionHandler;
|
|
|
|
|
- (void) setDataCompletionHandler: (void (^)(NSData *data, NSURLResponse *response, NSError *error))completionHandler;
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (void (^)(NSURL *location, NSURLResponse *response, NSError *error)) downloadCompletionHandler;
|
|
|
|
|
- (void) setDownloadCompletionHandler: (void (^)(NSURL *location, NSURLResponse *response, NSError *error))completionHandler;
|
|
|
|
|
@end
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
@interface NSURLSessionTask (URLProtocolClient) <NSURLProtocolClient>
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
typedef NS_ENUM(NSUInteger, NSURLSessionTaskProtocolState) {
|
|
|
|
|
NSURLSessionTaskProtocolStateToBeCreated = 0,
|
|
|
|
|
NSURLSessionTaskProtocolStateAwaitingCacheReply = 1,
|
|
|
|
|
NSURLSessionTaskProtocolStateExisting = 2,
|
|
|
|
|
NSURLSessionTaskProtocolStateInvalidated = 3,
|
|
|
|
|
};
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
static unsigned nextSessionIdentifier()
|
2020-11-29 11:57:47 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
static gs_mutex_t lock = GS_MUTEX_INIT_STATIC;
|
|
|
|
|
static unsigned sessionCounter = 0;
|
2023-01-16 11:48:28 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
GS_MUTEX_LOCK(lock);
|
|
|
|
|
sessionCounter += 1;
|
|
|
|
|
GS_MUTEX_UNLOCK(lock);
|
2023-01-16 11:48:28 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
return sessionCounter;
|
2020-11-29 11:57:47 +00:00
|
|
|
|
}
|
2017-06-21 00:03:43 +00:00
|
|
|
|
|
|
|
|
|
@implementation NSURLSession
|
2020-11-29 11:57:47 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
dispatch_queue_t _workQueue;
|
|
|
|
|
NSUInteger _nextTaskIdentifier;
|
|
|
|
|
BOOL _invalidated;
|
|
|
|
|
GSTaskRegistry *_taskRegistry;
|
2024-07-02 13:58:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
|
|
|
|
|
+ (NSURLSession*) sharedSession
|
2023-01-11 11:02:03 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
static NSURLSession *session = nil;
|
2023-01-11 11:02:03 +00:00
|
|
|
|
static dispatch_once_t predicate;
|
2024-07-02 18:19:14 +00:00
|
|
|
|
|
2023-01-11 11:02:03 +00:00
|
|
|
|
dispatch_once(&predicate, ^{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
|
|
|
|
|
session = [[NSURLSession alloc] initWithConfiguration: configuration
|
|
|
|
|
delegate: nil
|
|
|
|
|
delegateQueue: nil];
|
2023-01-11 11:02:03 +00:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return session;
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
+ (NSURLSession*) sessionWithConfiguration: (NSURLSessionConfiguration*)configuration
|
2023-01-11 11:02:03 +00:00
|
|
|
|
{
|
|
|
|
|
NSURLSession *session;
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
session = [[NSURLSession alloc] initWithConfiguration: configuration
|
|
|
|
|
delegate: nil
|
|
|
|
|
delegateQueue: nil];
|
2023-01-11 11:02:03 +00:00
|
|
|
|
|
|
|
|
|
return AUTORELEASE(session);
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
+ (NSURLSession*) sessionWithConfiguration: (NSURLSessionConfiguration*)configuration
|
|
|
|
|
delegate: (id <NSURLSessionDelegate>)delegate
|
|
|
|
|
delegateQueue: (NSOperationQueue*)queue
|
2020-11-29 11:57:47 +00:00
|
|
|
|
{
|
|
|
|
|
NSURLSession *session;
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
session = [[NSURLSession alloc] initWithConfiguration: configuration
|
|
|
|
|
delegate: delegate
|
|
|
|
|
delegateQueue: queue];
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
|
|
|
|
return AUTORELEASE(session);
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (instancetype) initWithConfiguration: (NSURLSessionConfiguration*)configuration
|
|
|
|
|
delegate: (id <NSURLSessionDelegate>)delegate
|
|
|
|
|
delegateQueue: (NSOperationQueue*)queue
|
2020-11-29 11:57:47 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
if (nil != (self = [super init]))
|
2020-11-29 11:57:47 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
char label[30];
|
|
|
|
|
dispatch_queue_t targetQueue;
|
2024-07-02 13:58:48 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
_taskRegistry = [[GSTaskRegistry alloc] init];
|
|
|
|
|
#if defined(CURLSSLBACKEND_GNUTLS)
|
|
|
|
|
curl_global_sslset(CURLSSLBACKEND_GNUTLS, NULL, NULL)l
|
|
|
|
|
#endif
|
|
|
|
|
curl_global_init(CURL_GLOBAL_SSL);
|
|
|
|
|
sprintf(label, "NSURLSession %u", nextSessionIdentifier());
|
|
|
|
|
targetQueue
|
|
|
|
|
= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
|
|
|
|
|
#if HAVE_DISPATCH_QUEUE_CREATE_WITH_TARGET
|
|
|
|
|
_workQueue = dispatch_queue_create_with_target(label,
|
|
|
|
|
DISPATCH_QUEUE_SERIAL, targetQueue);
|
|
|
|
|
#else
|
|
|
|
|
_workQueue = dispatch_queue_create(label, DISPATCH_QUEUE_SERIAL);
|
|
|
|
|
dispatch_set_target_queue(_workQueue, targetQueue);
|
|
|
|
|
#endif
|
|
|
|
|
if (nil != queue)
|
2020-11-29 11:57:47 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
ASSIGN(_delegateQueue, queue);
|
2020-11-29 11:57:47 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_delegateQueue = [[NSOperationQueue alloc] init];
|
2024-07-02 18:19:14 +00:00
|
|
|
|
[_delegateQueue setMaxConcurrentOperationCount: 1];
|
2020-11-29 11:57:47 +00:00
|
|
|
|
}
|
2024-07-02 18:19:14 +00:00
|
|
|
|
_delegate = delegate;
|
|
|
|
|
ASSIGN(_configuration, configuration);
|
|
|
|
|
_nextTaskIdentifier = 1;
|
|
|
|
|
_invalidated = NO;
|
|
|
|
|
_multiHandle = [[GSMultiHandle alloc] initWithConfiguration: configuration
|
|
|
|
|
workQueue: _workQueue];
|
|
|
|
|
[NSURLProtocol registerClass: [GSHTTPURLProtocol class]];
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) dealloc
|
|
|
|
|
{
|
|
|
|
|
DESTROY(_taskRegistry);
|
|
|
|
|
DESTROY(_configuration);
|
|
|
|
|
DESTROY(_delegateQueue);
|
|
|
|
|
DESTROY(_multiHandle);
|
|
|
|
|
[super dealloc];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (dispatch_queue_t) workQueue
|
|
|
|
|
{
|
|
|
|
|
return _workQueue;
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (NSOperationQueue*) delegateQueue
|
|
|
|
|
{
|
|
|
|
|
return _delegateQueue;
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (id <NSURLSessionDelegate>) delegate
|
|
|
|
|
{
|
|
|
|
|
return _delegate;
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (NSURLSessionConfiguration*) configuration
|
|
|
|
|
{
|
|
|
|
|
return _configuration;
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (NSString*) sessionDescription
|
|
|
|
|
{
|
|
|
|
|
return _sessionDescription;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) setSessionDescription: (NSString*)sessionDescription
|
|
|
|
|
{
|
|
|
|
|
ASSIGN(_sessionDescription, sessionDescription);
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (void) finishTasksAndInvalidate
|
|
|
|
|
{
|
|
|
|
|
dispatch_async(_workQueue,
|
|
|
|
|
^{
|
|
|
|
|
_invalidated = YES;
|
|
|
|
|
|
|
|
|
|
void (^invalidateSessionCallback)(void) =
|
|
|
|
|
^{
|
|
|
|
|
if (nil == _delegate) return;
|
|
|
|
|
|
|
|
|
|
[[self delegateQueue] addOperationWithBlock:
|
|
|
|
|
^{
|
|
|
|
|
if ([_delegate respondsToSelector: @selector(URLSession:didBecomeInvalidWithError:)])
|
|
|
|
|
{
|
|
|
|
|
[_delegate URLSession: self didBecomeInvalidWithError: nil];
|
|
|
|
|
}
|
|
|
|
|
_delegate = nil;
|
|
|
|
|
}];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (![_taskRegistry isEmpty])
|
|
|
|
|
{
|
|
|
|
|
[_taskRegistry notifyOnTasksCompletion: invalidateSessionCallback];
|
|
|
|
|
}
|
|
|
|
|
else
|
2020-11-29 11:57:47 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
invalidateSessionCallback();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (void) invalidateAndCancel
|
|
|
|
|
{
|
|
|
|
|
NSEnumerator *e;
|
|
|
|
|
NSURLSessionTask *task;
|
|
|
|
|
|
|
|
|
|
dispatch_sync(_workQueue,
|
|
|
|
|
^{
|
|
|
|
|
_invalidated = YES;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
e = [[_taskRegistry allTasks] objectEnumerator];
|
|
|
|
|
while (nil != (task = [e nextObject]))
|
|
|
|
|
{
|
|
|
|
|
[task cancel];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dispatch_async(_workQueue,
|
|
|
|
|
^{
|
|
|
|
|
if (nil == _delegate)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[[self delegateQueue] addOperationWithBlock:
|
|
|
|
|
^{
|
|
|
|
|
if ([_delegate respondsToSelector: @selector(URLSession:didBecomeInvalidWithError:)])
|
2024-07-02 13:58:48 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
[_delegate URLSession: self didBecomeInvalidWithError: nil];
|
2024-07-02 13:58:48 +00:00
|
|
|
|
}
|
2024-07-02 18:19:14 +00:00
|
|
|
|
_delegate = nil;
|
|
|
|
|
}];
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSURLSessionDataTask*) dataTaskWithRequest: (NSURLRequest*)request
|
|
|
|
|
{
|
|
|
|
|
NSURLSessionDataTask *task;
|
|
|
|
|
|
|
|
|
|
if (_invalidated)
|
|
|
|
|
{
|
|
|
|
|
return nil;
|
2020-11-29 11:57:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
task = [[NSURLSessionDataTask alloc] initWithSession: self
|
|
|
|
|
request: request
|
|
|
|
|
taskIdentifier: _nextTaskIdentifier++];
|
|
|
|
|
|
|
|
|
|
[self addTask: task];
|
|
|
|
|
|
|
|
|
|
return AUTORELEASE(task);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSURLSessionDataTask*) dataTaskWithURL: (NSURL*)url
|
|
|
|
|
{
|
|
|
|
|
NSMutableURLRequest *request;
|
|
|
|
|
|
|
|
|
|
request = [NSMutableURLRequest requestWithURL: url];
|
|
|
|
|
[request setHTTPMethod: @"POST"];
|
|
|
|
|
|
|
|
|
|
return [self dataTaskWithRequest: request];
|
2023-01-11 11:02:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (NSURLSessionUploadTask*) uploadTaskWithRequest: (NSURLRequest*)request
|
|
|
|
|
fromFile: (NSURL*)fileURL
|
|
|
|
|
{
|
|
|
|
|
return [self notImplemented: _cmd];
|
|
|
|
|
}
|
2021-08-27 19:56:08 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (NSURLSessionUploadTask*) uploadTaskWithRequest: (NSURLRequest*)request
|
|
|
|
|
fromData: (NSData*)bodyData
|
2021-08-27 19:56:08 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
return [self notImplemented: _cmd];
|
2021-08-27 19:56:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (NSURLSessionUploadTask*) uploadTaskWithStreamedRequest: (NSURLRequest*)request
|
2023-01-11 11:02:03 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
return [self notImplemented: _cmd];
|
2023-01-11 11:02:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (NSURLSessionDownloadTask*) downloadTaskWithRequest: (NSURLRequest*)request
|
2023-01-11 11:02:03 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
NSURLSessionDownloadTask *task;
|
|
|
|
|
|
|
|
|
|
if (_invalidated)
|
|
|
|
|
{
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
task = [[NSURLSessionDownloadTask alloc] initWithSession: self
|
|
|
|
|
request: request
|
|
|
|
|
taskIdentifier: _nextTaskIdentifier++];
|
|
|
|
|
|
|
|
|
|
[self addTask: task];
|
|
|
|
|
|
|
|
|
|
return AUTORELEASE(task);
|
2023-01-11 11:02:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (NSURLSessionDownloadTask*) downloadTaskWithURL: (NSURL*)url
|
2023-01-11 11:02:03 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
NSMutableURLRequest *request;
|
|
|
|
|
|
|
|
|
|
request = [NSMutableURLRequest requestWithURL: url];
|
|
|
|
|
[request setHTTPMethod: @"GET"];
|
2023-01-11 11:02:03 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
return [self downloadTaskWithRequest: request];
|
|
|
|
|
}
|
2023-01-11 11:02:03 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (NSURLSessionDownloadTask*) downloadTaskWithResumeData: (NSData*)resumeData
|
|
|
|
|
{
|
|
|
|
|
return [self notImplemented: _cmd];
|
2020-11-29 11:57:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (void) getTasksWithCompletionHandler: (void (^)(GS_GENERIC_CLASS(NSArray, NSURLSessionDataTask*) *dataTasks, GS_GENERIC_CLASS(NSArray, NSURLSessionUploadTask*) *uploadTasks, GS_GENERIC_CLASS(NSArray, NSURLSessionDownloadTask*) *downloadTasks))completionHandler
|
2020-11-29 11:57:47 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
NSArray *allTasks, *dataTasks, *uploadTasks, *downloadTasks;
|
|
|
|
|
|
|
|
|
|
allTasks = [_taskRegistry allTasks];
|
|
|
|
|
dataTasks = [allTasks filteredArrayUsingPredicate:
|
|
|
|
|
[NSPredicate predicateWithBlock:^BOOL(id task, NSDictionary* bindings) {
|
|
|
|
|
return [task isKindOfClass:[NSURLSessionDataTask class]];
|
|
|
|
|
}]];
|
|
|
|
|
uploadTasks = [allTasks filteredArrayUsingPredicate:
|
|
|
|
|
[NSPredicate predicateWithBlock:^BOOL(id task, NSDictionary* bindings) {
|
|
|
|
|
return [task isKindOfClass:[NSURLSessionUploadTask class]];
|
|
|
|
|
}]];
|
|
|
|
|
downloadTasks = [allTasks filteredArrayUsingPredicate:
|
|
|
|
|
[NSPredicate predicateWithBlock:^BOOL(id task, NSDictionary* bindings) {
|
|
|
|
|
return [task isKindOfClass:[NSURLSessionDownloadTask class]];
|
|
|
|
|
}]];
|
|
|
|
|
|
|
|
|
|
[[self delegateQueue] addOperationWithBlock:
|
|
|
|
|
^{
|
|
|
|
|
completionHandler(dataTasks, uploadTasks, downloadTasks);
|
|
|
|
|
}];
|
|
|
|
|
}
|
2023-01-11 11:02:03 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (void) getAllTasksWithCompletionHandler: (void (^)(GS_GENERIC_CLASS(NSArray, __kindof NSURLSessionTask*) *tasks))completionHandler
|
|
|
|
|
{
|
|
|
|
|
NSArray *allTasks = [_taskRegistry allTasks];
|
2023-01-11 11:02:03 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
[[self delegateQueue] addOperationWithBlock:
|
|
|
|
|
^{
|
|
|
|
|
completionHandler(allTasks);
|
|
|
|
|
}];
|
2023-01-11 11:02:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (void) addTask: (NSURLSessionTask*)task
|
2023-01-11 11:02:03 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
[_taskRegistry addTask: task];
|
2023-01-11 11:02:03 +00:00
|
|
|
|
}
|
2024-07-02 18:19:14 +00:00
|
|
|
|
|
|
|
|
|
- (void) removeTask: (NSURLSessionTask*)task
|
2023-01-11 11:02:03 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
[_taskRegistry removeTask: task];
|
2023-01-11 11:02:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation NSURLSession (NSURLSessionAsynchronousConvenience)
|
|
|
|
|
|
|
|
|
|
- (NSURLSessionDataTask*) dataTaskWithRequest: (NSURLRequest*)request
|
|
|
|
|
completionHandler: (void (^)(NSData *data, NSURLResponse *response, NSError *error))completionHandler
|
2023-01-11 11:02:03 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
NSURLSessionDataTask *task;
|
2023-01-11 11:02:03 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
if (_invalidated)
|
2023-01-11 11:02:03 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
return nil;
|
2023-01-11 11:02:03 +00:00
|
|
|
|
}
|
2024-07-02 18:19:14 +00:00
|
|
|
|
|
|
|
|
|
task = [[NSURLSessionDataTask alloc] initWithSession: self
|
|
|
|
|
request: request
|
|
|
|
|
taskIdentifier: _nextTaskIdentifier++];
|
|
|
|
|
[task setDataCompletionHandler: completionHandler];
|
|
|
|
|
|
|
|
|
|
[self addTask: task];
|
|
|
|
|
|
|
|
|
|
return AUTORELEASE(task);
|
2023-01-11 11:02:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (NSURLSessionDataTask*) dataTaskWithURL: (NSURL*)url
|
|
|
|
|
completionHandler: (void (^)(NSData *data, NSURLResponse *response, NSError *error))completionHandler
|
2020-11-29 11:57:47 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
NSMutableURLRequest *request;
|
|
|
|
|
|
|
|
|
|
request = [NSMutableURLRequest requestWithURL: url];
|
|
|
|
|
[request setHTTPMethod: @"POST"];
|
|
|
|
|
|
|
|
|
|
return [self dataTaskWithRequest: request
|
|
|
|
|
completionHandler: completionHandler];
|
2020-11-29 11:57:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (NSURLSessionUploadTask*) uploadTaskWithRequest: (NSURLRequest*)request
|
|
|
|
|
fromFile: (NSURL*)fileURL
|
|
|
|
|
completionHandler: (void (^)(NSData *data, NSURLResponse *response, NSError *error))completionHandler
|
2020-11-29 11:57:47 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
return [self notImplemented: _cmd];
|
2020-11-29 11:57:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (NSURLSessionUploadTask*) uploadTaskWithRequest: (NSURLRequest*)request
|
|
|
|
|
fromData: (NSData*)bodyData
|
|
|
|
|
completionHandler: (void (^)(NSData *data, NSURLResponse *response, NSError *error))completionHandler
|
|
|
|
|
{
|
|
|
|
|
return [self notImplemented: _cmd];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSURLSessionDownloadTask*) downloadTaskWithRequest: (NSURLRequest*)request
|
|
|
|
|
completionHandler: (void (^)(NSURL *location, NSURLResponse *response, NSError *error))completionHandler
|
2020-11-29 11:57:47 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
NSURLSessionDataTask *task;
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
if (_invalidated)
|
2020-11-29 11:57:47 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
return nil;
|
2020-11-29 11:57:47 +00:00
|
|
|
|
}
|
2024-07-02 18:19:14 +00:00
|
|
|
|
|
|
|
|
|
task = [[NSURLSessionDataTask alloc] initWithSession: self
|
|
|
|
|
request: request
|
|
|
|
|
taskIdentifier: _nextTaskIdentifier++];
|
|
|
|
|
[task setDownloadCompletionHandler: completionHandler];
|
|
|
|
|
|
|
|
|
|
[self addTask: task];
|
|
|
|
|
|
|
|
|
|
return AUTORELEASE(task);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSURLSessionDownloadTask*) downloadTaskWithURL: (NSURL*)url
|
|
|
|
|
completionHandler: (void (^)(NSURL *location, NSURLResponse *response, NSError *error))completionHandler
|
|
|
|
|
{
|
|
|
|
|
NSMutableURLRequest *request;
|
|
|
|
|
|
|
|
|
|
request = [NSMutableURLRequest requestWithURL: url];
|
|
|
|
|
[request setHTTPMethod: @"GET"];
|
|
|
|
|
|
|
|
|
|
return [self downloadTaskWithRequest: request
|
|
|
|
|
completionHandler: completionHandler];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSURLSessionDownloadTask*) downloadTaskWithResumeData: (NSData*)resumeData
|
|
|
|
|
completionHandler: (void (^)(NSURL *location, NSURLResponse *response, NSError *error))completionHandler
|
|
|
|
|
{
|
|
|
|
|
return [self notImplemented: _cmd];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@implementation _NSURLProtocolClient
|
|
|
|
|
|
|
|
|
|
- (instancetype) init
|
|
|
|
|
{
|
|
|
|
|
if (nil != (self = [super init]))
|
2024-05-07 09:04:42 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
_cachePolicy = NSURLCacheStorageNotAllowed;
|
2024-05-07 09:04:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
return self;
|
2020-11-29 11:57:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (void) dealloc
|
2020-11-29 11:57:47 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
DESTROY(_cacheableData);
|
|
|
|
|
DESTROY(_cacheableResponse);
|
|
|
|
|
[super dealloc];
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (void) URLProtocol: (NSURLProtocol *)protocol
|
|
|
|
|
cachedResponseIsValid: (NSCachedURLResponse *)cachedResponse
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) URLProtocol: (NSURLProtocol *)protocol
|
|
|
|
|
didFailWithError: (NSError *)error
|
|
|
|
|
{
|
|
|
|
|
NSURLSessionTask *task = [protocol task];
|
|
|
|
|
|
|
|
|
|
NSAssert(nil != task, @"Missing task");
|
|
|
|
|
|
|
|
|
|
[self task: task didFailWithError: error];
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (void) task: (NSURLSessionTask *)task
|
|
|
|
|
didFailWithError: (NSError *)error
|
|
|
|
|
{
|
|
|
|
|
NSURLSession *session;
|
|
|
|
|
NSOperationQueue *delegateQueue;
|
|
|
|
|
id<NSURLSessionDelegate> delegate;
|
|
|
|
|
void (^dataCompletionHandler)(NSData *data, NSURLResponse *response, NSError *error);
|
|
|
|
|
void (^downloadCompletionHandler)(NSURL *location, NSURLResponse *response, NSError *error);
|
|
|
|
|
|
|
|
|
|
session = [task session];
|
|
|
|
|
NSAssert(nil != session, @"Missing session");
|
|
|
|
|
|
|
|
|
|
delegateQueue = [session delegateQueue];
|
|
|
|
|
delegate = [session delegate];
|
|
|
|
|
dataCompletionHandler = [task dataCompletionHandler];
|
|
|
|
|
downloadCompletionHandler = [task downloadCompletionHandler];
|
|
|
|
|
|
|
|
|
|
if (nil != delegate)
|
2020-11-29 11:57:47 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
[delegateQueue addOperationWithBlock:
|
|
|
|
|
^{
|
|
|
|
|
if (NSURLSessionTaskStateCompleted == [task state])
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ([delegate respondsToSelector:
|
|
|
|
|
@selector(URLSession:task:didCompleteWithError:)])
|
|
|
|
|
{
|
|
|
|
|
[(id<NSURLSessionTaskDelegate>)delegate URLSession: session
|
|
|
|
|
task: task
|
|
|
|
|
didCompleteWithError: error];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[task setState: NSURLSessionTaskStateCompleted];
|
|
|
|
|
dispatch_async([session workQueue],
|
|
|
|
|
^{
|
|
|
|
|
[session removeTask: task];
|
|
|
|
|
});
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
else if (nil != dataCompletionHandler)
|
|
|
|
|
{
|
|
|
|
|
[delegateQueue addOperationWithBlock:
|
|
|
|
|
^{
|
|
|
|
|
if (NSURLSessionTaskStateCompleted == [task state])
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dataCompletionHandler(nil, nil, error);
|
|
|
|
|
|
|
|
|
|
[task setState: NSURLSessionTaskStateCompleted];
|
|
|
|
|
|
|
|
|
|
dispatch_async([session workQueue],
|
|
|
|
|
^{
|
|
|
|
|
[session removeTask: task];
|
|
|
|
|
});
|
|
|
|
|
}];
|
2020-11-29 11:57:47 +00:00
|
|
|
|
}
|
2024-07-02 18:19:14 +00:00
|
|
|
|
else if (nil != downloadCompletionHandler)
|
|
|
|
|
{
|
|
|
|
|
[delegateQueue addOperationWithBlock:
|
|
|
|
|
^{
|
|
|
|
|
if (NSURLSessionTaskStateCompleted == [task state])
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
downloadCompletionHandler(nil, nil, error);
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
[task setState: NSURLSessionTaskStateCompleted];
|
|
|
|
|
|
|
|
|
|
dispatch_async([session workQueue],
|
|
|
|
|
^{
|
|
|
|
|
[session removeTask: task];
|
|
|
|
|
});
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
else
|
2020-11-29 11:57:47 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
if (NSURLSessionTaskStateCompleted == [task state])
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[task setState: NSURLSessionTaskStateCompleted];
|
|
|
|
|
dispatch_async([session workQueue],
|
|
|
|
|
^{
|
|
|
|
|
[session removeTask: task];
|
|
|
|
|
});
|
2020-11-29 11:57:47 +00:00
|
|
|
|
}
|
2024-07-02 18:19:14 +00:00
|
|
|
|
|
|
|
|
|
[task invalidateProtocol];
|
2020-11-29 11:57:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (void) URLProtocol: (NSURLProtocol *)protocol
|
|
|
|
|
didLoadData: (NSData *)data
|
2020-11-29 11:57:47 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
NSURLSessionTask *task = [protocol task];
|
|
|
|
|
NSURLSession *session;
|
|
|
|
|
id<NSURLSessionDelegate> delegate;
|
|
|
|
|
|
|
|
|
|
NSAssert(nil != task, @"Missing task");
|
|
|
|
|
|
|
|
|
|
session = [task session];
|
|
|
|
|
delegate = [session delegate];
|
|
|
|
|
|
|
|
|
|
switch (_cachePolicy)
|
2020-11-29 11:57:47 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
case NSURLCacheStorageAllowed:
|
|
|
|
|
case NSURLCacheStorageAllowedInMemoryOnly:
|
2024-07-02 13:58:48 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
if (nil != _cacheableData)
|
|
|
|
|
{
|
|
|
|
|
[_cacheableData addObject: data];
|
|
|
|
|
}
|
|
|
|
|
break;
|
2024-07-02 13:58:48 +00:00
|
|
|
|
}
|
2024-07-02 18:19:14 +00:00
|
|
|
|
case NSURLCacheStorageNotAllowed:
|
|
|
|
|
break;
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
if (nil != delegate
|
|
|
|
|
&& [task isKindOfClass: [NSURLSessionDataTask class]]
|
|
|
|
|
&& [delegate respondsToSelector:
|
|
|
|
|
@selector(URLSession:dataTask:didReceiveData:)])
|
|
|
|
|
{
|
|
|
|
|
[[session delegateQueue] addOperationWithBlock:
|
|
|
|
|
^{
|
|
|
|
|
[(id<NSURLSessionDataDelegate>)delegate URLSession: session
|
|
|
|
|
dataTask: (NSURLSessionDataTask*)task
|
|
|
|
|
didReceiveData: data];
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (void) URLProtocol: (NSURLProtocol *)protocol
|
|
|
|
|
didReceiveAuthenticationChallenge: (NSURLAuthenticationChallenge *)challenge
|
|
|
|
|
{
|
|
|
|
|
//FIXME
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) URLProtocol: (NSURLProtocol *)protocol
|
|
|
|
|
didReceiveResponse: (NSURLResponse *)response
|
|
|
|
|
cacheStoragePolicy: (NSURLCacheStoragePolicy)policy
|
|
|
|
|
{
|
|
|
|
|
NSURLSessionTask *task = [protocol task];
|
|
|
|
|
NSURLSession *session;
|
|
|
|
|
id<NSURLSessionDelegate> delegate;
|
|
|
|
|
|
|
|
|
|
NSAssert(nil != task, @"Missing task");
|
|
|
|
|
|
|
|
|
|
[task setResponse: response];
|
|
|
|
|
|
|
|
|
|
session = [task session];
|
|
|
|
|
|
|
|
|
|
if (![task isKindOfClass: [NSURLSessionDataTask class]])
|
|
|
|
|
{
|
|
|
|
|
return;
|
2020-11-29 11:57:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
_cachePolicy = policy;
|
|
|
|
|
|
|
|
|
|
if (nil != [[session configuration] URLCache])
|
2020-11-29 11:57:47 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
switch (policy)
|
2024-07-02 13:58:48 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
case NSURLCacheStorageAllowed:
|
|
|
|
|
case NSURLCacheStorageAllowedInMemoryOnly:
|
|
|
|
|
ASSIGN(_cacheableData, [NSMutableArray array]);
|
|
|
|
|
ASSIGN(_cacheableResponse, response);
|
|
|
|
|
break;
|
|
|
|
|
case NSURLCacheStorageNotAllowed:
|
|
|
|
|
break;
|
2024-07-02 13:58:48 +00:00
|
|
|
|
}
|
2024-07-02 18:19:14 +00:00
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
delegate = [session delegate];
|
|
|
|
|
if (nil != delegate)
|
|
|
|
|
{
|
|
|
|
|
[[session delegateQueue] addOperationWithBlock:
|
|
|
|
|
^{
|
|
|
|
|
if ([delegate respondsToSelector: @selector
|
|
|
|
|
(URLSession:dataTask:didReceiveResponse:completionHandler:)])
|
|
|
|
|
{
|
|
|
|
|
NSURLSessionDataTask *dataTask = (NSURLSessionDataTask*)task;
|
|
|
|
|
|
|
|
|
|
[(id<NSURLSessionDataDelegate>)delegate URLSession: session
|
|
|
|
|
dataTask: dataTask
|
|
|
|
|
didReceiveResponse: response
|
|
|
|
|
completionHandler:
|
|
|
|
|
^(NSURLSessionResponseDisposition disposition) {
|
|
|
|
|
if (disposition != NSURLSessionResponseAllow)
|
|
|
|
|
{
|
|
|
|
|
NSLog(@"Warning: ignoring disposition %d from completion handler",
|
|
|
|
|
(int)disposition);
|
|
|
|
|
}
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (void) URLProtocol: (NSURLProtocol *)protocol
|
|
|
|
|
wasRedirectedToRequest: (NSURLRequest *)request
|
|
|
|
|
redirectResponse: (NSURLResponse *)redirectResponse
|
|
|
|
|
{
|
|
|
|
|
NSAssert(NO, @"The NSURLSession implementation doesn't currently handle redirects directly.");
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (NSURLProtectionSpace*) _protectionSpaceFrom: (NSHTTPURLResponse*)response
|
|
|
|
|
{
|
|
|
|
|
NSURLProtectionSpace *space = nil;
|
|
|
|
|
NSString *auth;
|
|
|
|
|
|
|
|
|
|
auth = [[response allHeaderFields] objectForKey: @"WWW-Authenticate"];
|
|
|
|
|
if (nil != auth)
|
|
|
|
|
{
|
|
|
|
|
NSURL *url = [response URL];
|
|
|
|
|
NSString *host = [url host];
|
|
|
|
|
NSNumber *port = [url port];
|
|
|
|
|
NSString *scheme = [url scheme];
|
|
|
|
|
NSRange range;
|
|
|
|
|
NSString *realm;
|
|
|
|
|
NSString *method;
|
|
|
|
|
|
|
|
|
|
if (nil == host) host = @"";
|
|
|
|
|
if (nil == port) port = [NSNumber numberWithInt: 80];
|
|
|
|
|
method = [[auth componentsSeparatedByString: @" "] firstObject];
|
|
|
|
|
range = [auth rangeOfString: @"realm="];
|
|
|
|
|
realm = range.length > 0
|
|
|
|
|
? [auth substringFromIndex: NSMaxRange(range)] : @"";
|
|
|
|
|
space = AUTORELEASE([[NSURLProtectionSpace alloc]
|
|
|
|
|
initWithHost: host
|
|
|
|
|
port: [port integerValue]
|
|
|
|
|
protocol: scheme
|
|
|
|
|
realm: realm
|
|
|
|
|
authenticationMethod: method]);
|
|
|
|
|
}
|
|
|
|
|
return space;
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (void) URLProtocolDidFinishLoading: (NSURLProtocol *)protocol
|
|
|
|
|
{
|
|
|
|
|
NSURLSessionTask *task = [protocol task];
|
|
|
|
|
NSURLSession *session;
|
|
|
|
|
NSHTTPURLResponse *urlResponse;
|
|
|
|
|
NSURLCache *cache;
|
|
|
|
|
NSOperationQueue *delegateQueue;
|
|
|
|
|
id<NSURLSessionDelegate> delegate;
|
|
|
|
|
void (^dataCompletionHandler)(NSData *data, NSURLResponse *response, NSError *error);
|
|
|
|
|
void (^downloadCompletionHandler)(NSURL *location, NSURLResponse *response, NSError *error);
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
NSAssert(nil != task, @"Missing task");
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
session = [task session];
|
|
|
|
|
urlResponse = (NSHTTPURLResponse*)[task response];
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
if ([urlResponse statusCode] == 401)
|
|
|
|
|
{
|
|
|
|
|
[self _protectionSpaceFrom: urlResponse];
|
2020-11-29 11:57:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
delegate = [session delegate];
|
|
|
|
|
delegateQueue = [session delegateQueue];
|
|
|
|
|
dataCompletionHandler = [task dataCompletionHandler];
|
|
|
|
|
downloadCompletionHandler = [task downloadCompletionHandler];
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
if (nil != (cache = [[session configuration] URLCache])
|
|
|
|
|
&& [task isKindOfClass: [NSURLSessionDataTask class]]
|
|
|
|
|
&& nil != _cacheableData
|
|
|
|
|
&& nil != _cacheableResponse)
|
2020-11-29 11:57:47 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
NSCachedURLResponse *cacheable;
|
|
|
|
|
NSMutableData *data;
|
|
|
|
|
NSEnumerator *e;
|
|
|
|
|
NSData *d;
|
|
|
|
|
|
|
|
|
|
data = [NSMutableData data];
|
|
|
|
|
e = [_cacheableData objectEnumerator];
|
|
|
|
|
while (nil != (d = [e nextObject]))
|
2020-11-29 11:57:47 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
[data appendData: d];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cacheable = [[NSCachedURLResponse alloc] initWithResponse: urlResponse
|
|
|
|
|
data: data
|
|
|
|
|
userInfo: nil
|
|
|
|
|
storagePolicy: _cachePolicy];
|
|
|
|
|
[cache storeCachedResponse: cacheable
|
|
|
|
|
forDataTask: (NSURLSessionDataTask*)task];
|
|
|
|
|
RELEASE(cacheable);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (nil != dataCompletionHandler)
|
|
|
|
|
{
|
|
|
|
|
NSData *data = [NSURLProtocol propertyForKey: @"tempData"
|
|
|
|
|
inRequest: [protocol request]];
|
2023-01-16 14:40:43 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
[delegateQueue addOperationWithBlock:
|
|
|
|
|
^{
|
|
|
|
|
if (NSURLSessionTaskStateCompleted == [task state])
|
2023-01-16 14:40:43 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
return;
|
2023-01-16 14:40:43 +00:00
|
|
|
|
}
|
2024-07-02 18:19:14 +00:00
|
|
|
|
|
|
|
|
|
dataCompletionHandler(data, urlResponse, nil);
|
|
|
|
|
|
|
|
|
|
[task setState: NSURLSessionTaskStateCompleted];
|
|
|
|
|
|
|
|
|
|
dispatch_async([session workQueue],
|
|
|
|
|
^{
|
|
|
|
|
[session removeTask: task];
|
|
|
|
|
});
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
else if (nil != downloadCompletionHandler)
|
|
|
|
|
{
|
|
|
|
|
NSURL *fileURL = [NSURLProtocol propertyForKey: @"tempFileURL"
|
|
|
|
|
inRequest: [protocol request]];
|
|
|
|
|
|
|
|
|
|
[delegateQueue addOperationWithBlock:
|
|
|
|
|
^{
|
|
|
|
|
if (NSURLSessionTaskStateCompleted == [task state])
|
2023-01-16 14:40:43 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
return;
|
2023-01-16 14:40:43 +00:00
|
|
|
|
}
|
2023-01-11 11:02:03 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
downloadCompletionHandler(fileURL, urlResponse, nil);
|
2023-01-16 14:40:43 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
[task setState: NSURLSessionTaskStateCompleted];
|
2021-08-28 18:33:19 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
dispatch_async([session workQueue],
|
|
|
|
|
^{
|
|
|
|
|
[session removeTask: task];
|
|
|
|
|
});
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
else if (nil != delegate)
|
|
|
|
|
{
|
|
|
|
|
// Send delegate with temporary fileURL
|
|
|
|
|
if ([task isKindOfClass: [NSURLSessionDownloadTask class]]
|
|
|
|
|
&& [delegate respondsToSelector: @selector(URLSession:downloadTask:didFinishDownloadingToURL:)])
|
|
|
|
|
{
|
|
|
|
|
id<NSURLSessionDownloadDelegate> downloadDelegate;
|
|
|
|
|
NSURLSessionDownloadTask *downloadTask;
|
|
|
|
|
NSURL *fileURL;
|
|
|
|
|
|
|
|
|
|
downloadDelegate = (id<NSURLSessionDownloadDelegate>)delegate;
|
|
|
|
|
downloadTask = (NSURLSessionDownloadTask *)task;
|
|
|
|
|
fileURL = [NSURLProtocol propertyForKey: @"tempFileURL"
|
|
|
|
|
inRequest: [protocol request]];
|
|
|
|
|
|
|
|
|
|
[delegateQueue addOperationWithBlock:
|
|
|
|
|
^{
|
|
|
|
|
[downloadDelegate URLSession: session
|
|
|
|
|
downloadTask: downloadTask
|
|
|
|
|
didFinishDownloadingToURL: fileURL];
|
|
|
|
|
}];
|
|
|
|
|
}
|
2024-07-02 13:58:48 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
[delegateQueue addOperationWithBlock:
|
|
|
|
|
^{
|
|
|
|
|
if (NSURLSessionTaskStateCompleted == [task state])
|
2020-11-29 11:57:47 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
return;
|
2020-11-29 11:57:47 +00:00
|
|
|
|
}
|
2024-07-02 18:19:14 +00:00
|
|
|
|
|
|
|
|
|
if ([delegate respondsToSelector:
|
|
|
|
|
@selector(URLSession:task:didCompleteWithError:)])
|
|
|
|
|
{
|
|
|
|
|
[(id<NSURLSessionTaskDelegate>)delegate URLSession: session
|
|
|
|
|
task: task
|
|
|
|
|
didCompleteWithError: nil];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[task setState: NSURLSessionTaskStateCompleted];
|
|
|
|
|
|
|
|
|
|
dispatch_async([session workQueue],
|
|
|
|
|
^{
|
|
|
|
|
[session removeTask: task];
|
|
|
|
|
});
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (NSURLSessionTaskStateCompleted != [task state])
|
|
|
|
|
{
|
|
|
|
|
[task setState: NSURLSessionTaskStateCompleted];
|
|
|
|
|
dispatch_async([session workQueue],
|
|
|
|
|
^{
|
|
|
|
|
[session removeTask: task];
|
|
|
|
|
});
|
2020-11-29 11:57:47 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2024-07-02 18:19:14 +00:00
|
|
|
|
|
|
|
|
|
[task invalidateProtocol];
|
2020-11-29 11:57:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (void) URLProtocol: (NSURLProtocol *)protocol
|
|
|
|
|
didCancelAuthenticationChallenge: (NSURLAuthenticationChallenge *)challenge
|
2020-11-29 11:57:47 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
//FIXME
|
2020-11-29 11:57:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
@end
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
@implementation NSURLSessionTask
|
2020-11-29 11:57:47 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
NSURLSession *_session;
|
|
|
|
|
NSLock *_protocolLock;
|
|
|
|
|
NSURLSessionTaskProtocolState _protocolState;
|
|
|
|
|
NSURLProtocol *_protocol;
|
|
|
|
|
NSMutableArray *_protocolBag;
|
|
|
|
|
Class _protocolClass;
|
|
|
|
|
BOOL _hasTriggeredResume;
|
|
|
|
|
float _priority;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (instancetype) initWithSession: (NSURLSession*)session
|
|
|
|
|
request: (NSURLRequest*)request
|
|
|
|
|
taskIdentifier: (NSUInteger)identifier
|
|
|
|
|
{
|
|
|
|
|
NSEnumerator *e;
|
|
|
|
|
Class protocolClass;
|
|
|
|
|
|
|
|
|
|
if (nil != (self = [super init]))
|
2020-11-29 11:57:47 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
NSData *data;
|
|
|
|
|
NSInputStream *stream;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Only retain the session once the -resume method is called
|
|
|
|
|
* and release the session as the last thing done once the
|
|
|
|
|
* task has completed. This avoids a retain loop causing
|
|
|
|
|
* session and tasks to be leaked.
|
|
|
|
|
*/
|
|
|
|
|
_session = session;
|
|
|
|
|
ASSIGN(_originalRequest, request);
|
|
|
|
|
ASSIGN(_currentRequest, request);
|
|
|
|
|
if ([(data = [request HTTPBody]) length] > 0)
|
|
|
|
|
{
|
|
|
|
|
_knownBody = [[GSURLSessionTaskBody alloc] initWithData: data];
|
|
|
|
|
}
|
|
|
|
|
else if (nil != (stream = [request HTTPBodyStream]))
|
|
|
|
|
{
|
|
|
|
|
_knownBody = [[GSURLSessionTaskBody alloc]
|
|
|
|
|
initWithInputStream: stream];
|
|
|
|
|
}
|
|
|
|
|
_taskIdentifier = identifier;
|
|
|
|
|
#if HAVE_DISPATCH_QUEUE_CREATE_WITH_TARGET
|
|
|
|
|
_workQueue = dispatch_queue_create_with_target("org.gnustep.NSURLSessionTask.WorkQueue", DISPATCH_QUEUE_SERIAL, [session workQueue]);
|
|
|
|
|
#else
|
|
|
|
|
_workQueue = dispatch_queue_create("org.gnustep.NSURLSessionTask.WorkQueue", DISPATCH_QUEUE_SERIAL);
|
|
|
|
|
dispatch_set_target_queue(_workQueue, [session workQueue]);
|
|
|
|
|
#endif
|
|
|
|
|
_state = NSURLSessionTaskStateSuspended;
|
|
|
|
|
_suspendCount = 1;
|
|
|
|
|
_protocolLock = [[NSLock alloc] init];
|
|
|
|
|
_protocolState = NSURLSessionTaskProtocolStateToBeCreated;
|
|
|
|
|
_protocol = nil;
|
|
|
|
|
_hasTriggeredResume = NO;
|
|
|
|
|
_priority = NSURLSessionTaskPriorityDefault;
|
|
|
|
|
e = [[[session configuration] protocolClasses] objectEnumerator];
|
|
|
|
|
while (nil != (protocolClass = [e nextObject]))
|
|
|
|
|
{
|
|
|
|
|
if ([protocolClass canInitWithTask: self])
|
|
|
|
|
{
|
|
|
|
|
_protocolClass = protocolClass;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
NSAssert(nil != _protocolClass, @"Unsupported protocol for request: %@", request);
|
2020-11-29 11:57:47 +00:00
|
|
|
|
}
|
2024-07-02 18:19:14 +00:00
|
|
|
|
|
|
|
|
|
return self;
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (void) dealloc
|
|
|
|
|
{
|
|
|
|
|
DESTROY(_originalRequest);
|
|
|
|
|
DESTROY(_currentRequest);
|
|
|
|
|
DESTROY(_response);
|
|
|
|
|
DESTROY(_taskDescription);
|
|
|
|
|
DESTROY(_error);
|
|
|
|
|
DESTROY(_protocolLock);
|
|
|
|
|
DESTROY(_protocol);
|
|
|
|
|
DESTROY(_protocolBag);
|
|
|
|
|
DESTROY(_dataCompletionHandler);
|
|
|
|
|
DESTROY(_knownBody);
|
|
|
|
|
dispatch_release(_workQueue);
|
|
|
|
|
[super dealloc];
|
2020-11-29 11:57:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (NSURLSessionTaskState) updateTaskState
|
2020-11-29 11:57:47 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
if (0 == _suspendCount)
|
2024-07-02 13:58:48 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
_state = NSURLSessionTaskStateRunning;
|
2024-07-02 13:58:48 +00:00
|
|
|
|
}
|
2024-07-02 18:19:14 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_state = NSURLSessionTaskStateSuspended;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return _state;
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (NSUInteger) taskIdentifier
|
|
|
|
|
{
|
|
|
|
|
return _taskIdentifier;
|
2020-11-29 11:57:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (NSURLRequest*) originalRequest
|
2020-11-29 11:57:47 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
return _originalRequest;
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (NSURLRequest*) currentRequest
|
|
|
|
|
{
|
|
|
|
|
return _currentRequest;
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (NSURLResponse*) response
|
|
|
|
|
{
|
|
|
|
|
return _response;
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (void) setResponse: (NSURLResponse*)response
|
|
|
|
|
{
|
|
|
|
|
ASSIGN(_response, response);
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (int64_t) countOfBytesReceived
|
|
|
|
|
{
|
|
|
|
|
return _countOfBytesReceived;
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (int64_t) countOfBytesSent
|
|
|
|
|
{
|
|
|
|
|
return _countOfBytesSent;
|
2020-11-29 11:57:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (int64_t) countOfBytesExpectedToSend
|
2020-11-29 11:57:47 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
return _countOfBytesExpectedToSend;
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (int64_t) countOfBytesExpectedToReceive
|
|
|
|
|
{
|
|
|
|
|
return _countOfBytesExpectedToReceive;
|
2020-11-29 11:57:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (NSString*) taskDescription
|
2020-11-29 11:57:47 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
return _taskDescription;
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (void) setTaskDescription: (NSString*)taskDescription
|
|
|
|
|
{
|
|
|
|
|
ASSIGN(_taskDescription, taskDescription);
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (NSURLSessionTaskState) state
|
|
|
|
|
{
|
|
|
|
|
return _state;
|
|
|
|
|
}
|
2024-07-02 13:58:48 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (NSError*) error
|
|
|
|
|
{
|
|
|
|
|
return _error;
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (BOOL) isSuspendedAfterResume
|
|
|
|
|
{
|
|
|
|
|
return _hasTriggeredResume && (_state == NSURLSessionTaskStateSuspended);
|
2020-11-29 11:57:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (void) cancel
|
2020-11-29 11:57:47 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
dispatch_sync(_workQueue,
|
|
|
|
|
^{
|
|
|
|
|
if (!(NSURLSessionTaskStateRunning == _state
|
|
|
|
|
|| NSURLSessionTaskStateSuspended == _state))
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
_state = NSURLSessionTaskStateCanceling;
|
|
|
|
|
|
|
|
|
|
[self getProtocolWithCompletion:
|
|
|
|
|
^(NSURLProtocol *protocol) {
|
|
|
|
|
dispatch_async(_workQueue,
|
|
|
|
|
^{
|
|
|
|
|
_error = [[NSError alloc] initWithDomain: NSURLErrorDomain
|
|
|
|
|
code: NSURLErrorCancelled
|
|
|
|
|
userInfo: nil];
|
|
|
|
|
if (nil != protocol)
|
|
|
|
|
{
|
|
|
|
|
id<NSURLProtocolClient> client;
|
|
|
|
|
|
|
|
|
|
[protocol stopLoading];
|
|
|
|
|
if (nil != (client = [protocol client]))
|
|
|
|
|
{
|
|
|
|
|
[client URLProtocol: protocol didFailWithError: _error];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}];
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (void) suspend
|
|
|
|
|
{
|
|
|
|
|
dispatch_sync(_workQueue,
|
|
|
|
|
^{
|
|
|
|
|
if (NSURLSessionTaskStateCanceling == _state
|
|
|
|
|
|| NSURLSessionTaskStateCompleted == _state)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
_suspendCount++;
|
2024-07-02 13:58:48 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
[self updateTaskState];
|
|
|
|
|
|
|
|
|
|
if (1 == _suspendCount)
|
|
|
|
|
{
|
|
|
|
|
[self getProtocolWithCompletion:
|
|
|
|
|
^(NSURLProtocol *protocol){
|
|
|
|
|
dispatch_async(_workQueue,
|
|
|
|
|
^{
|
|
|
|
|
if (nil != protocol)
|
|
|
|
|
{
|
|
|
|
|
[protocol stopLoading];
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
});
|
2020-11-29 11:57:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (void) resume
|
2020-11-29 11:57:47 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
/*
|
|
|
|
|
* Properly retain the session to keep a reference
|
|
|
|
|
* to the task. This ensures correct API behaviour.
|
|
|
|
|
*/
|
|
|
|
|
RETAIN(_session);
|
2021-09-04 11:07:14 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
dispatch_sync(_workQueue,
|
|
|
|
|
^{
|
|
|
|
|
if (NSURLSessionTaskStateCanceling == _state
|
|
|
|
|
|| NSURLSessionTaskStateCompleted == _state)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
if (_suspendCount > 0)
|
|
|
|
|
{
|
|
|
|
|
_suspendCount--;
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
[self updateTaskState];
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
if (0 == _suspendCount)
|
|
|
|
|
{
|
|
|
|
|
_hasTriggeredResume = YES;
|
|
|
|
|
[self getProtocolWithCompletion:
|
|
|
|
|
^(NSURLProtocol* protocol) {
|
|
|
|
|
dispatch_async(_workQueue,
|
|
|
|
|
^{
|
|
|
|
|
if (_suspendCount != 0
|
|
|
|
|
|| NSURLSessionTaskStateCanceling == _state
|
|
|
|
|
|| NSURLSessionTaskStateCompleted == _state)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (nil != protocol)
|
|
|
|
|
{
|
|
|
|
|
[protocol startLoading];
|
|
|
|
|
}
|
|
|
|
|
else if (nil == _error)
|
|
|
|
|
{
|
|
|
|
|
NSDictionary *userInfo;
|
|
|
|
|
_NSURLProtocolClient *client;
|
|
|
|
|
|
|
|
|
|
userInfo = [NSDictionary dictionaryWithObjectsAndKeys:
|
|
|
|
|
[_originalRequest URL], NSURLErrorFailingURLErrorKey,
|
|
|
|
|
[[_originalRequest URL] absoluteString], NSURLErrorFailingURLStringErrorKey,
|
|
|
|
|
nil];
|
|
|
|
|
_error = [[NSError alloc] initWithDomain: NSURLErrorDomain
|
|
|
|
|
code: NSURLErrorUnsupportedURL
|
|
|
|
|
userInfo: userInfo];
|
|
|
|
|
client = AUTORELEASE([[_NSURLProtocolClient alloc] init]);
|
|
|
|
|
[client task: self didFailWithError: _error];
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
});
|
2020-11-29 11:57:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (float) priority
|
2023-01-11 11:02:03 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
return _priority;;
|
|
|
|
|
}
|
2023-01-11 11:02:03 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (void) setPriority: (float)priority
|
|
|
|
|
{
|
|
|
|
|
_priority = priority;
|
|
|
|
|
}
|
2023-01-11 11:02:03 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (id) copyWithZone: (NSZone*)zone
|
|
|
|
|
{
|
|
|
|
|
NSURLSessionTask *copy = [[[self class] alloc] init];
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
if (copy)
|
|
|
|
|
{
|
|
|
|
|
copy->_taskIdentifier = _taskIdentifier;
|
|
|
|
|
copy->_originalRequest = [_originalRequest copyWithZone: zone];
|
|
|
|
|
copy->_currentRequest = [_currentRequest copyWithZone: zone];
|
|
|
|
|
copy->_response = [_response copyWithZone: zone];
|
|
|
|
|
copy->_countOfBytesReceived = _countOfBytesReceived;
|
|
|
|
|
copy->_countOfBytesSent = _countOfBytesSent;
|
|
|
|
|
copy->_countOfBytesExpectedToSend = _countOfBytesExpectedToSend;
|
|
|
|
|
copy->_countOfBytesExpectedToReceive = _countOfBytesExpectedToReceive;
|
|
|
|
|
copy->_taskDescription = [_taskDescription copyWithZone: zone];
|
|
|
|
|
copy->_state = _state;
|
|
|
|
|
copy->_error = [_error copyWithZone: zone];
|
|
|
|
|
copy->_session = _session;
|
|
|
|
|
dispatch_retain(_workQueue);
|
|
|
|
|
copy->_workQueue = _workQueue;
|
|
|
|
|
copy->_suspendCount = _suspendCount;
|
|
|
|
|
copy->_protocolLock = [_protocolLock copy];
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
return copy;
|
2020-11-29 11:57:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (void) getProtocolWithCompletion: (void (^)(NSURLProtocol* protocol))completion
|
2020-11-29 11:57:47 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
[_protocolLock lock];
|
|
|
|
|
switch (_protocolState)
|
|
|
|
|
{
|
|
|
|
|
case NSURLSessionTaskProtocolStateToBeCreated:
|
|
|
|
|
{
|
|
|
|
|
NSURLCache *cache;
|
|
|
|
|
NSURLRequestCachePolicy cachePolicy;
|
|
|
|
|
NSCachedURLResponse *cachedResponse;
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
cache = [[_session configuration] URLCache];
|
|
|
|
|
cachePolicy = [[self currentRequest] cachePolicy];
|
|
|
|
|
|
|
|
|
|
if (nil != cache
|
|
|
|
|
&& [self isUsingLocalCacheWithPolicy: cachePolicy]
|
|
|
|
|
&& [self isKindOfClass: [NSURLSessionDataTask class]])
|
|
|
|
|
{
|
|
|
|
|
ASSIGN(_protocolBag, [NSMutableArray array]);
|
|
|
|
|
[_protocolBag addObject: completion];
|
|
|
|
|
|
|
|
|
|
_protocolState = NSURLSessionTaskProtocolStateAwaitingCacheReply;
|
|
|
|
|
|
|
|
|
|
[_protocolLock unlock];
|
|
|
|
|
|
|
|
|
|
cachedResponse =
|
|
|
|
|
[cache cachedResponseForDataTask: (NSURLSessionDataTask*)self];
|
|
|
|
|
|
|
|
|
|
_protocol = [[_protocolClass alloc] initWithTask: self
|
|
|
|
|
cachedResponse: cachedResponse
|
|
|
|
|
client: nil];
|
|
|
|
|
[self satisfyProtocolRequest];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_protocol = [[_protocolClass alloc] initWithTask: self
|
|
|
|
|
cachedResponse: nil
|
|
|
|
|
client: nil];
|
|
|
|
|
_protocolState = NSURLSessionTaskProtocolStateExisting;
|
|
|
|
|
[_protocolLock unlock];
|
|
|
|
|
completion(_protocol);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case NSURLSessionTaskProtocolStateAwaitingCacheReply:
|
|
|
|
|
{
|
|
|
|
|
[_protocolBag addObject: completion];
|
|
|
|
|
[_protocolLock unlock];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case NSURLSessionTaskProtocolStateExisting:
|
|
|
|
|
{
|
|
|
|
|
[_protocolLock unlock];
|
|
|
|
|
completion(_protocol);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case NSURLSessionTaskProtocolStateInvalidated:
|
|
|
|
|
{
|
|
|
|
|
[_protocolLock unlock];
|
|
|
|
|
completion(nil);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (void) satisfyProtocolRequest
|
2020-11-29 11:57:47 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
[_protocolLock lock];
|
|
|
|
|
switch (_protocolState)
|
|
|
|
|
{
|
|
|
|
|
case NSURLSessionTaskProtocolStateToBeCreated:
|
|
|
|
|
{
|
|
|
|
|
_protocolState = NSURLSessionTaskProtocolStateExisting;
|
|
|
|
|
[_protocolLock unlock];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case NSURLSessionTaskProtocolStateAwaitingCacheReply:
|
|
|
|
|
{
|
|
|
|
|
_protocolState = NSURLSessionTaskProtocolStateExisting;
|
|
|
|
|
[_protocolLock unlock];
|
|
|
|
|
void (^callback)(NSURLProtocol*);
|
|
|
|
|
for (int i = 0; i < [_protocolBag count]; i++)
|
|
|
|
|
{
|
|
|
|
|
callback = [_protocolBag objectAtIndex: i];
|
|
|
|
|
callback(_protocol);
|
|
|
|
|
}
|
|
|
|
|
DESTROY(_protocolBag);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case NSURLSessionTaskProtocolStateExisting:
|
|
|
|
|
case NSURLSessionTaskProtocolStateInvalidated:
|
|
|
|
|
{
|
|
|
|
|
[_protocolLock unlock];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (BOOL) isUsingLocalCacheWithPolicy: (NSURLRequestCachePolicy)policy
|
2020-11-29 11:57:47 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
switch (policy)
|
|
|
|
|
{
|
|
|
|
|
case NSURLRequestUseProtocolCachePolicy:
|
|
|
|
|
return true;
|
|
|
|
|
case NSURLRequestReloadIgnoringLocalCacheData:
|
|
|
|
|
return false;
|
|
|
|
|
case NSURLRequestReturnCacheDataElseLoad:
|
|
|
|
|
return true;
|
|
|
|
|
case NSURLRequestReturnCacheDataDontLoad:
|
|
|
|
|
return true;
|
|
|
|
|
case NSURLRequestReloadIgnoringLocalAndRemoteCacheData:
|
|
|
|
|
case NSURLRequestReloadRevalidatingCacheData:
|
|
|
|
|
return false;
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (NSURLSession*) session
|
|
|
|
|
{
|
|
|
|
|
return _session;
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (void) setState: (NSURLSessionTaskState)state
|
|
|
|
|
{
|
|
|
|
|
_state = state;
|
|
|
|
|
}
|
2023-01-11 11:02:03 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (void) invalidateProtocol
|
|
|
|
|
{
|
|
|
|
|
[_protocolLock lock];
|
|
|
|
|
_protocolState = NSURLSessionTaskProtocolStateInvalidated;
|
|
|
|
|
DESTROY(_protocol);
|
|
|
|
|
/*
|
|
|
|
|
* Release session at the end of the task
|
|
|
|
|
* and not when -dealloc is called.
|
|
|
|
|
*/
|
|
|
|
|
DESTROY(_session);
|
|
|
|
|
[_protocolLock unlock];
|
2023-01-11 11:02:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (void (^)(NSData *data, NSURLResponse *response, NSError *error)) dataCompletionHandler
|
2023-01-11 11:02:03 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
return _dataCompletionHandler;
|
2023-01-11 11:02:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (void) setDataCompletionHandler: (void (^)(NSData *data, NSURLResponse *response, NSError *error))completionHandler
|
|
|
|
|
{
|
|
|
|
|
ASSIGN(_dataCompletionHandler, completionHandler);
|
|
|
|
|
}
|
2024-07-02 13:58:48 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (void (^)(NSURL *location, NSURLResponse *response, NSError *error)) downloadCompletionHandler
|
2023-01-11 11:02:03 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
return _downloadCompletionHandler;
|
2023-01-11 11:02:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (void) setDownloadCompletionHandler: (void (^)(NSURL *location, NSURLResponse *response, NSError *error))completionHandler
|
2020-11-29 11:57:47 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
ASSIGN(_downloadCompletionHandler, completionHandler);
|
2020-11-29 11:57:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation NSURLSessionDataTask
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation NSURLSessionUploadTask
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation NSURLSessionDownloadTask
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation NSURLSessionConfiguration
|
|
|
|
|
|
|
|
|
|
static NSURLSessionConfiguration *def = nil;
|
|
|
|
|
|
|
|
|
|
+ (void) initialize
|
2020-11-29 11:57:47 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
if (nil == def)
|
|
|
|
|
{
|
|
|
|
|
def = [NSURLSessionConfiguration new];
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
+ (NSURLSessionConfiguration*) defaultSessionConfiguration
|
2023-01-11 11:02:03 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
return AUTORELEASE([def copy]);
|
2023-01-11 11:02:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
+ (NSURLSessionConfiguration*) ephemeralSessionConfiguration
|
2023-01-11 11:02:03 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
// return default session since we don't store any data on disk anyway
|
|
|
|
|
return AUTORELEASE([def copy]);
|
2023-01-11 11:02:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
+ (NSURLSessionConfiguration*) backgroundSessionConfigurationWithIdentifier:(NSString*)identifier
|
2020-11-29 11:57:47 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
NSURLSessionConfiguration *configuration = [def copy];
|
|
|
|
|
configuration->_identifier = [identifier copy];
|
|
|
|
|
return AUTORELEASE(configuration);
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (instancetype) init
|
|
|
|
|
{
|
|
|
|
|
if (nil != (self = [super init]))
|
|
|
|
|
{
|
|
|
|
|
_protocolClasses = [[NSArray alloc] initWithObjects:
|
|
|
|
|
[GSHTTPURLProtocol class], nil];
|
|
|
|
|
_HTTPMaximumConnectionsPerHost = 1;
|
|
|
|
|
_HTTPShouldUsePipelining = YES;
|
|
|
|
|
_HTTPCookieAcceptPolicy = NSHTTPCookieAcceptPolicyNever;
|
|
|
|
|
_HTTPCookieStorage = nil;
|
|
|
|
|
_HTTPShouldSetCookies = NO;
|
|
|
|
|
_HTTPAdditionalHeaders = nil;
|
|
|
|
|
_HTTPMaximumConnectionLifetime = 0; // Zero or less means default
|
|
|
|
|
}
|
2024-07-02 13:58:48 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
return self;
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (void) dealloc
|
|
|
|
|
{
|
|
|
|
|
DESTROY(_identifier);
|
|
|
|
|
DESTROY(_HTTPAdditionalHeaders);
|
|
|
|
|
DESTROY(_HTTPCookieStorage);
|
|
|
|
|
DESTROY(_protocolClasses);
|
|
|
|
|
DESTROY(_URLCache);
|
|
|
|
|
DESTROY(_URLCredentialStorage);
|
2020-11-29 11:57:47 +00:00
|
|
|
|
[super dealloc];
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (NSString*) identifier
|
2020-11-29 11:57:47 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
return _identifier;
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (NSURLCache*) URLCache
|
|
|
|
|
{
|
|
|
|
|
return _URLCache;
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (void) setURLCache: (NSURLCache*)cache
|
|
|
|
|
{
|
|
|
|
|
ASSIGN(_URLCache, cache);
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (void) setURLCredentialStorage: (NSURLCredentialStorage*)storage
|
|
|
|
|
{
|
|
|
|
|
ASSIGN(_URLCredentialStorage, storage);
|
2020-11-29 11:57:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (NSURLRequestCachePolicy) requestCachePolicy
|
2020-11-29 11:57:47 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
return _requestCachePolicy;
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (void) setRequestCachePolicy: (NSURLRequestCachePolicy)policy
|
|
|
|
|
{
|
|
|
|
|
_requestCachePolicy = policy;
|
2020-11-29 11:57:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (NSArray*) protocolClasses
|
2020-11-29 11:57:47 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
return _protocolClasses;
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (NSInteger) HTTPMaximumConnectionsPerHost
|
|
|
|
|
{
|
|
|
|
|
return _HTTPMaximumConnectionsPerHost;
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (void) setHTTPMaximumConnectionsPerHost: (NSInteger)n
|
|
|
|
|
{
|
|
|
|
|
_HTTPMaximumConnectionsPerHost = n;
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (NSInteger) HTTPMaximumConnectionLifetime
|
|
|
|
|
{
|
|
|
|
|
return _HTTPMaximumConnectionLifetime;
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (void) setHTTPMaximumConnectionLifetime: (NSInteger)n
|
|
|
|
|
{
|
|
|
|
|
_HTTPMaximumConnectionLifetime = n;
|
2020-11-29 11:57:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (BOOL) HTTPShouldUsePipelining
|
2020-11-29 11:57:47 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
return _HTTPShouldUsePipelining;
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (void) setHTTPShouldUsePipelining: (BOOL)flag
|
|
|
|
|
{
|
|
|
|
|
_HTTPShouldUsePipelining = flag;
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (NSHTTPCookieAcceptPolicy) HTTPCookieAcceptPolicy
|
|
|
|
|
{
|
|
|
|
|
return _HTTPCookieAcceptPolicy;
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (void) setHTTPCookieAcceptPolicy: (NSHTTPCookieAcceptPolicy)policy
|
|
|
|
|
{
|
|
|
|
|
_HTTPCookieAcceptPolicy = policy;
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (NSHTTPCookieStorage*) HTTPCookieStorage
|
|
|
|
|
{
|
|
|
|
|
return _HTTPCookieStorage;
|
2020-11-29 11:57:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (void) setHTTPCookieStorage: (NSHTTPCookieStorage*)storage
|
2020-11-29 11:57:47 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
ASSIGN(_HTTPCookieStorage, storage);
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (BOOL) HTTPShouldSetCookies
|
|
|
|
|
{
|
|
|
|
|
return _HTTPShouldSetCookies;
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (void) setHTTPShouldSetCookies: (BOOL)flag
|
|
|
|
|
{
|
|
|
|
|
_HTTPShouldSetCookies = flag;
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (NSDictionary*) HTTPAdditionalHeaders
|
|
|
|
|
{
|
|
|
|
|
return _HTTPAdditionalHeaders;
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (void) setHTTPAdditionalHeaders: (NSDictionary*)headers
|
|
|
|
|
{
|
|
|
|
|
ASSIGN(_HTTPAdditionalHeaders, headers);
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (NSURLRequest*) configureRequest: (NSURLRequest*)request
|
|
|
|
|
{
|
|
|
|
|
return [self setCookiesOnRequest: request];
|
2020-11-29 11:57:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (NSURLRequest*) setCookiesOnRequest: (NSURLRequest*)request
|
2020-11-29 11:57:47 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
NSMutableURLRequest *r = AUTORELEASE([request mutableCopy]);
|
|
|
|
|
|
|
|
|
|
if (_HTTPShouldSetCookies)
|
|
|
|
|
{
|
|
|
|
|
if (nil != _HTTPCookieStorage && nil != [request URL])
|
|
|
|
|
{
|
|
|
|
|
NSArray *cookies = [_HTTPCookieStorage cookiesForURL: [request URL]];
|
|
|
|
|
if (nil != cookies && [cookies count] > 0)
|
|
|
|
|
{
|
|
|
|
|
NSDictionary *cookiesHeaderFields;
|
|
|
|
|
NSString *cookieValue;
|
|
|
|
|
|
|
|
|
|
cookiesHeaderFields
|
|
|
|
|
= [NSHTTPCookie requestHeaderFieldsWithCookies: cookies];
|
|
|
|
|
cookieValue = [cookiesHeaderFields objectForKey: @"Cookie"];
|
|
|
|
|
if (nil != cookieValue && [cookieValue length] > 0)
|
|
|
|
|
{
|
|
|
|
|
[r setValue: cookieValue forHTTPHeaderField: @"Cookie"];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return AUTORELEASE([r copy]);
|
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (NSURLCredentialStorage*) URLCredentialStorage
|
|
|
|
|
{
|
|
|
|
|
return _URLCredentialStorage;
|
2024-07-02 13:58:48 +00:00
|
|
|
|
}
|
2020-11-29 11:57:47 +00:00
|
|
|
|
|
2024-07-02 18:19:14 +00:00
|
|
|
|
- (id) copyWithZone: (NSZone*)zone
|
2024-07-02 13:58:48 +00:00
|
|
|
|
{
|
2024-07-02 18:19:14 +00:00
|
|
|
|
NSURLSessionConfiguration *copy = [[[self class] alloc] init];
|
|
|
|
|
|
|
|
|
|
if (copy)
|
|
|
|
|
{
|
|
|
|
|
copy->_identifier = [_identifier copy];
|
|
|
|
|
copy->_URLCache = [_URLCache copy];
|
|
|
|
|
copy->_URLCredentialStorage = [_URLCredentialStorage copy];
|
|
|
|
|
copy->_protocolClasses = [_protocolClasses copyWithZone: zone];
|
|
|
|
|
copy->_HTTPMaximumConnectionsPerHost = _HTTPMaximumConnectionsPerHost;
|
|
|
|
|
copy->_HTTPShouldUsePipelining = _HTTPShouldUsePipelining;
|
|
|
|
|
copy->_HTTPCookieAcceptPolicy = _HTTPCookieAcceptPolicy;
|
|
|
|
|
copy->_HTTPCookieStorage = [_HTTPCookieStorage copy];
|
|
|
|
|
copy->_HTTPShouldSetCookies = _HTTPShouldSetCookies;
|
|
|
|
|
copy->_HTTPAdditionalHeaders
|
|
|
|
|
= [_HTTPAdditionalHeaders copyWithZone: zone];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return copy;
|
2020-11-29 11:57:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-06-21 00:03:43 +00:00
|
|
|
|
@end
|