Begin implementation of NSURLSessionDownloadTask

This commit is contained in:
Nuntius 2021-08-27 21:56:08 +02:00
parent 99ef0c9665
commit d3e40dfc9d
4 changed files with 155 additions and 9 deletions

View file

@ -24,6 +24,7 @@
@class NSURLResponse;
@class NSURLSessionConfiguration;
@class NSURLSessionDataTask;
@class NSURLSessionDownloadTask;
/**
@ -110,6 +111,12 @@ GS_EXPORT_CLASS
/* Creates a data task to retrieve the contents of the given URL. */
- (NSURLSessionDataTask*) dataTaskWithURL: (NSURL*)url;
/* Creates a download task with the given request. */
- (NSURLSessionDownloadTask *) downloadTaskWithRequest: (NSURLRequest *)request;
/* Creates a download task to download the contents of the given URL. */
- (NSURLSessionDownloadTask *) downloadTaskWithURL: (NSURL *)url;
@end
typedef NS_ENUM(NSUInteger, NSURLSessionTaskState) {
@ -430,6 +437,37 @@ didReceiveChallenge: (NSURLAuthenticationChallenge*)challenge
@end
@protocol NSURLSessionDownloadDelegate <NSURLSessionTaskDelegate>
/* Sent when a download task that has completed a download. The delegate should
* copy or move the file at the given location to a new location as it will be
* removed when the delegate message returns. URLSession:task:didCompleteWithError: will
* still be called.
*/
- (void) URLSession: (NSURLSession *)session
downloadTask: (NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL: (NSURL *)location;
@optional
/* Sent periodically to notify the delegate of download progress. */
- (void) URLSession: (NSURLSession *)session
downloadTask: (NSURLSessionDownloadTask *)downloadTask
didWriteData: (int64_t)bytesWritten
totalBytesWritten: (int64_t)totalBytesWritten
totalBytesExpectedToWrite: (int64_t)totalBytesExpectedToWrite;
/* Sent when a download has been resumed. If a download failed with an
* error, the -userInfo dictionary of the error will contain an
* NSURLSessionDownloadTaskResumeData key, whose value is the resume
* data.
*/
- (void) URLSession: (NSURLSession *)session
downloadTask: (NSURLSessionDownloadTask *)downloadTask
didResumeAtOffset: (int64_t)fileOffset
expectedTotalBytes: (int64_t)expectedTotalBytes;
@end
#endif
#endif
#endif

View file

@ -9,6 +9,7 @@
#import "Foundation/NSURL.h"
#import "Foundation/NSURLError.h"
#import "Foundation/NSURLSession.h"
#import "Foundation/NSFileHandle.h"
static BOOL isEasyHandlePaused(GSNativeProtocolInternalState state)
@ -97,6 +98,8 @@ static BOOL isEasyHandleAddedToMultiHandle(GSNativeProtocolInternalState state)
- (void) setError: (NSError*)error;
- (void) setCountOfBytesReceived: (int64_t)count;
@end
@implementation NSURLSessionTask (Internal)
@ -138,6 +141,11 @@ static BOOL isEasyHandleAddedToMultiHandle(GSNativeProtocolInternalState state)
ASSIGN(_error, error);
}
- (void) setCountOfBytesReceived: (int64_t)count
{
_countOfBytesReceived = count;
}
@end
@implementation GSCompletionAction
@ -493,13 +501,16 @@ static BOOL isEasyHandleAddedToMultiHandle(GSNativeProtocolInternalState state)
- (void) notifyDelegateAboutReceivedData: (NSData*)data
{
NSURLSessionTask *task;
id<NSURLSessionDelegate> delegate;
NSURLSession *session;
NSURLSessionTask *task;
id<NSURLSessionDelegate> delegate;
task = [self task];
NSAssert(nil != task, @"Cannot notify");
session = [task session];
NSAssert(nil != session, @"Missing session");
delegate = [[task session] delegate];
if (nil != delegate
&& [task isKindOfClass: [NSURLSessionDataTask class]]
@ -507,10 +518,7 @@ static BOOL isEasyHandleAddedToMultiHandle(GSNativeProtocolInternalState state)
{
id<NSURLSessionDataDelegate> dataDelegate;
NSURLSessionDataTask *dataTask;
NSURLSession *session;
session = [task session];
NSAssert(nil != session, @"Missing session");
dataDelegate = (id<NSURLSessionDataDelegate>)delegate;
dataTask = (NSURLSessionDataTask*)task;
[[session delegateQueue] addOperationWithBlock:
@ -520,6 +528,40 @@ static BOOL isEasyHandleAddedToMultiHandle(GSNativeProtocolInternalState state)
didReceiveData: data];
}];
}
/* Don't check whether delegate respondsToSelector.
* This delegate is optional. */
if (nil != delegate
&& [task isKindOfClass: [NSURLSessionDownloadTask class]])
{
id<NSURLSessionDownloadDelegate> downloadDelegate;
NSURLSessionDownloadTask *downloadTask;
GSDataDrain *dataDrain;
NSFileHandle *fileHandle;
downloadDelegate = (id<NSURLSessionDownloadDelegate>)delegate;
downloadTask = (NSURLSessionDownloadTask*)task;
dataDrain = [_transferState bodyDataDrain];
/* Write to file. GSDataDrain opens the fileHandle. */
fileHandle = [dataDrain fileHandle];
[fileHandle seekToEndOfFile];
[fileHandle writeData: data];
if ([delegate respondsToSelector: @selector
(URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:)])
{
/* Calculate received data length */
[task setCountOfBytesReceived: (int64_t)[data length] + [task countOfBytesReceived]];
[[session delegateQueue] addOperationWithBlock:
^{
[downloadDelegate URLSession: session
downloadTask: downloadTask
didWriteData: (int64_t)[data length]
totalBytesWritten: [task countOfBytesReceived]
totalBytesExpectedToWrite: [task countOfBytesExpectedToReceive]];
}];
}
}
}
- (void) notifyDelegateAboutUploadedDataCount: (int64_t)count

View file

@ -10,6 +10,9 @@
#import "Foundation/NSURLError.h"
#import "Foundation/NSURLResponse.h"
#import "Foundation/NSURLSession.h"
#import "Foundation/NSUUID.h"
#import "Foundation/NSFileManager.h"
#import "Foundation/NSPathUtilities.h"
#define GS_DELIMITERS_CR 0x0d
#define GS_DELIMITERS_LR 0x0a
@ -277,6 +280,25 @@
- (NSURL*) fileURL
{
/* Generate a random fileURL if fileURL is not initialized.
* It would be nice to have this implemented in an initializer. */
if (!_fileURL)
{
NSUUID *randomUUID;
NSString *fileName;
NSURL *tempURL;
randomUUID = [NSUUID UUID];
fileName = [[randomUUID UUIDString] stringByAppendingPathExtension: @"tmp"];
tempURL = [NSURL fileURLWithPath: NSTemporaryDirectory()];
_fileURL = [NSURL fileURLWithPath: fileName relativeToURL: tempURL];
RELEASE(randomUUID);
RELEASE(fileName);
RELEASE(tempURL);
}
return _fileURL;
}
@ -287,6 +309,17 @@
- (NSFileHandle*) fileHandle
{
/* Create temporary file and open a fileHandle for writing. */
if (!_fileHandle)
{
NSFileManager *file = [NSFileManager defaultManager];
[file createFileAtPath: [[self fileURL] relativePath] contents: nil attributes: nil];
_fileHandle = [NSFileHandle fileHandleForWritingToURL: [self fileURL] error: NULL];
RELEASE(file);
}
return _fileHandle;
}

View file

@ -284,6 +284,34 @@ static int nextSessionIdentifier()
return [self dataTaskWithRequest: request];
}
- (NSURLSessionDownloadTask *) downloadTaskWithRequest: (NSURLRequest *)request
{
NSURLSessionDownloadTask *task;
if (_invalidated)
{
return nil;
}
task = [[NSURLSessionDownloadTask alloc] initWithSession: self
request: request
taskIdentifier: _nextTaskIdentifier++];
[self addTask: task];
return AUTORELEASE(task);
}
- (NSURLSessionDownloadTask *) downloadTaskWithURL: (NSURL *)url
{
NSMutableURLRequest *request;
request = [NSMutableURLRequest requestWithURL: url];
[request setHTTPMethod: @"GET"];
return [self downloadTaskWithRequest: request];
}
- (void) addTask: (NSURLSessionTask*)task
{
[_taskRegistry addTask: task];
@ -632,7 +660,7 @@ static int nextSessionIdentifier()
@implementation NSURLSessionTask
{
NSURLSession *_session; /* not retained */
NSURLSession *_session;
NSLock *_protocolLock;
NSURLSessionTaskProtocolState _protocolState;
NSURLProtocol *_protocol;
@ -653,7 +681,7 @@ static int nextSessionIdentifier()
NSData *data;
NSInputStream *stream;
_session = session;
ASSIGN(_session, session);
ASSIGN(_originalRequest, request);
ASSIGN(_currentRequest, request);
if ([(data = [request HTTPBody]) length] > 0)
@ -694,6 +722,7 @@ static int nextSessionIdentifier()
- (void) dealloc
{
DESTROY(_session);
DESTROY(_originalRequest);
DESTROY(_currentRequest);
DESTROY(_response);
@ -1083,6 +1112,10 @@ static int nextSessionIdentifier()
@end
@implementation NSURLSessionDownloadTask
@end
@implementation NSURLSessionConfiguration
static NSURLSessionConfiguration *def = nil;