mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-31 08:41:03 +00:00
Revert "NSURLSession Reimplementation (#411)"
This reverts commit 07233534e6
.
This commit is contained in:
parent
07233534e6
commit
3fedf31c2d
50 changed files with 7197 additions and 5391 deletions
1
Tests/base/NSURLSession/.gitignore
vendored
1
Tests/base/NSURLSession/.gitignore
vendored
|
@ -1 +0,0 @@
|
|||
Helpers/HTTPServer.bundle
|
|
@ -1,8 +1,5 @@
|
|||
|
||||
include $(GNUSTEP_MAKEFILES)/common.make
|
||||
|
||||
ifeq ($(the_library_combo), ng-gnu-gnu)
|
||||
SUBPROJECTS = Helpers
|
||||
SUBPROJECTS = ../NSURLConnection/Helpers
|
||||
|
||||
include $(GNUSTEP_MAKEFILES)/aggregate.make
|
||||
endif
|
||||
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
include $(GNUSTEP_MAKEFILES)/common.make
|
||||
|
||||
BUNDLE_NAME = HTTPServer
|
||||
|
||||
NEEDS_GUI=NO
|
||||
|
||||
HTTPServer_OBJC_FILES = HTTPServer.m
|
||||
HTTPServer_OBJC_LIBS += -ldispatch
|
||||
|
||||
ifeq ($(GNUSTEP_TARGET_OS), windows)
|
||||
HTTPServer_OBJC_LIBS += -lws2_32
|
||||
endif
|
||||
|
||||
HTTPServer_OBJCFLAGS += -fobjc-arc
|
||||
#HTTPServer_RESOURCE_FILES += key.pem certificate.pem
|
||||
HTTPServer_PRINCIPAL_CLASS = HTTPServer
|
||||
|
||||
-include GNUmakefile.preamble
|
||||
include $(GNUSTEP_MAKEFILES)/bundle.make
|
||||
-include GNUmakefile.postamble
|
|
@ -1,30 +0,0 @@
|
|||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSObject.h>
|
||||
#import <Foundation/NSURLRequest.h>
|
||||
#import <Foundation/NSURLResponse.h>
|
||||
|
||||
typedef NSData * (^RequestHandlerBlock)(NSURLRequest *);
|
||||
|
||||
@interface Route : NSObject
|
||||
|
||||
+ (instancetype)routeWithURL:(NSURL *)url
|
||||
method:(NSString *)method
|
||||
handler:(RequestHandlerBlock)block;
|
||||
|
||||
- (NSString *)method;
|
||||
- (NSURL *)url;
|
||||
- (RequestHandlerBlock)block;
|
||||
|
||||
- (BOOL)acceptsURL:(NSURL *)url method:(NSString *)method;
|
||||
|
||||
@end
|
||||
|
||||
@interface HTTPServer : NSObject
|
||||
- initWithPort:(NSInteger)port routes:(NSArray<Route *> *)routes;
|
||||
|
||||
- (NSInteger)port;
|
||||
- (void)resume;
|
||||
- (void)suspend;
|
||||
|
||||
- (void)setRoutes:(NSArray<Route *> *)routes;
|
||||
@end
|
|
@ -1,402 +0,0 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import <dispatch/dispatch.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#import <winsock2.h>
|
||||
|
||||
#define close(x) closesocket(x)
|
||||
#else
|
||||
|
||||
#import <netinet/in.h>
|
||||
#import <sys/socket.h>
|
||||
|
||||
#endif
|
||||
|
||||
#import "HTTPServer.h"
|
||||
|
||||
@interface
|
||||
NSString (ServerAdditions)
|
||||
- (void)enumerateLinesUsingBlock2:
|
||||
(void (^)(NSString *line, NSUInteger lineEndIndex, BOOL *stop))block;
|
||||
@end
|
||||
|
||||
@implementation
|
||||
NSString (ServerAdditions)
|
||||
|
||||
- (void)enumerateLinesUsingBlock2:
|
||||
(void (^)(NSString *line, NSUInteger lineEndIndex, BOOL *stop))block
|
||||
{
|
||||
NSUInteger length;
|
||||
NSUInteger lineStart, lineEnd, contentsEnd;
|
||||
NSRange currentLocationRange;
|
||||
BOOL stop;
|
||||
|
||||
length = [self length];
|
||||
lineStart = lineEnd = contentsEnd = 0;
|
||||
stop = NO;
|
||||
|
||||
// Enumerate through the string line by line
|
||||
while (lineStart < length && !stop)
|
||||
{
|
||||
NSString *line;
|
||||
NSRange lineRange;
|
||||
|
||||
currentLocationRange = NSMakeRange(lineStart, 0);
|
||||
[self getLineStart:&lineStart
|
||||
end:&lineEnd
|
||||
contentsEnd:&contentsEnd
|
||||
forRange:currentLocationRange];
|
||||
|
||||
lineRange = NSMakeRange(lineStart, contentsEnd - lineStart);
|
||||
line = [self substringWithRange:lineRange];
|
||||
|
||||
// Execute the block
|
||||
block(line, lineEnd, &stop);
|
||||
|
||||
// Move to the next line
|
||||
lineStart = lineEnd;
|
||||
}
|
||||
}
|
||||
@end
|
||||
|
||||
/* We don't need this once toll-free bridging works */
|
||||
NSData *
|
||||
copyDispatchDataToNSData(dispatch_data_t dispatchData)
|
||||
{
|
||||
NSMutableData *mutableData =
|
||||
[NSMutableData dataWithCapacity:dispatch_data_get_size(dispatchData)];
|
||||
|
||||
dispatch_data_apply(dispatchData, ^bool(dispatch_data_t region, size_t offset,
|
||||
const void *buffer, size_t size) {
|
||||
[mutableData appendBytes:buffer length:size];
|
||||
return true; // Continue iterating
|
||||
});
|
||||
|
||||
return [mutableData copy];
|
||||
}
|
||||
|
||||
@implementation Route
|
||||
{
|
||||
NSString *_method;
|
||||
NSURL *_url;
|
||||
RequestHandlerBlock _block;
|
||||
}
|
||||
+ (instancetype)routeWithURL:(NSURL *)url
|
||||
method:(NSString *)method
|
||||
handler:(RequestHandlerBlock)block
|
||||
{
|
||||
return [[Route alloc] initWithURL:url method:method handler:block];
|
||||
}
|
||||
|
||||
- (instancetype)initWithURL:(NSURL *)url
|
||||
method:(NSString *)method
|
||||
handler:(RequestHandlerBlock)block
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_url = url;
|
||||
_method = method;
|
||||
_block = block;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSString *)method
|
||||
{
|
||||
return _method;
|
||||
}
|
||||
- (NSURL *)url
|
||||
{
|
||||
return _url;
|
||||
}
|
||||
- (RequestHandlerBlock)block
|
||||
{
|
||||
return _block;
|
||||
}
|
||||
|
||||
- (BOOL)acceptsURL:(NSURL *)url method:(NSString *)method
|
||||
{
|
||||
return [[_url path] isEqualTo:[url path]];
|
||||
}
|
||||
|
||||
@end /* Route */
|
||||
|
||||
@implementation HTTPServer
|
||||
{
|
||||
_Atomic(BOOL) _stop;
|
||||
int _socket;
|
||||
NSInteger _port;
|
||||
NSArray<Route *> *_routes;
|
||||
dispatch_queue_t _queue;
|
||||
dispatch_queue_t _acceptQueue;
|
||||
}
|
||||
|
||||
- initWithPort:(NSInteger)port routes:(NSArray<Route *> *)routes
|
||||
{
|
||||
self = [super init];
|
||||
if (!self)
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
WSADATA wsaData;
|
||||
|
||||
// Initialise WinSock2 API
|
||||
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
|
||||
{
|
||||
NSLog(@"Error Creating Socket: %d", WSAGetLastError());
|
||||
return nil;
|
||||
}
|
||||
#endif
|
||||
|
||||
_stop = YES;
|
||||
_socket = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (_socket == -1)
|
||||
{
|
||||
NSLog(@"Error creating socket %s", strerror(errno));
|
||||
return nil;
|
||||
}
|
||||
|
||||
_routes = [routes copy];
|
||||
|
||||
struct sockaddr_in serverAddr;
|
||||
NSUInteger addrLen = sizeof(struct sockaddr_in);
|
||||
serverAddr.sin_family = AF_INET;
|
||||
serverAddr.sin_port = NSSwapHostShortToBig(port);
|
||||
serverAddr.sin_addr.s_addr = INADDR_ANY;
|
||||
|
||||
int rc;
|
||||
int yes = 1;
|
||||
rc = setsockopt(_socket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
|
||||
if (rc == -1)
|
||||
{
|
||||
NSLog(@"Error setting socket options %s", strerror(errno));
|
||||
return nil;
|
||||
}
|
||||
|
||||
rc = bind(_socket, (struct sockaddr *) &serverAddr, sizeof(struct sockaddr));
|
||||
if (rc < 0)
|
||||
{
|
||||
NSLog(@"Error binding to socket %s", strerror(errno));
|
||||
return nil;
|
||||
}
|
||||
|
||||
// Get Port Number
|
||||
if (getsockname(_socket, (struct sockaddr *) &serverAddr, &addrLen) == -1)
|
||||
{
|
||||
NSLog(@"Error getting socket name %s", strerror(errno));
|
||||
return nil;
|
||||
}
|
||||
_port = NSSwapBigShortToHost(serverAddr.sin_port);
|
||||
|
||||
rc = listen(_socket, 20);
|
||||
if (rc < 0)
|
||||
{
|
||||
NSLog(@"Error listening on socket %s", strerror(errno));
|
||||
return nil;
|
||||
}
|
||||
|
||||
_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
|
||||
_acceptQueue = dispatch_queue_create("org.gnustep.HTTPServer.AcceptQueue",
|
||||
DISPATCH_QUEUE_CONCURRENT);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)acceptConnection
|
||||
{
|
||||
struct sockaddr_in clientAddr;
|
||||
dispatch_io_t ioChannel;
|
||||
NSUInteger sin_size;
|
||||
int clientSocket;
|
||||
|
||||
sin_size = sizeof(struct sockaddr_in);
|
||||
clientSocket = accept(_socket, (struct sockaddr *) &clientAddr, &sin_size);
|
||||
if (clientSocket < 0)
|
||||
{
|
||||
NSLog(@"Error accepting connection %s", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
ioChannel
|
||||
= dispatch_io_create(DISPATCH_IO_STREAM, clientSocket, _queue,
|
||||
^(int error) {
|
||||
close(clientSocket);
|
||||
|
||||
if (error)
|
||||
{
|
||||
NSLog(@"Error creating dispatch I/O channel %s",
|
||||
strerror(error));
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
dispatch_io_set_low_water(ioChannel, 1);
|
||||
|
||||
dispatch_io_read(ioChannel, 0, SIZE_MAX, _queue,
|
||||
^(bool done, dispatch_data_t data, int error) {
|
||||
if (error)
|
||||
{
|
||||
NSLog(@"Error reading data %s", strerror(error));
|
||||
dispatch_io_close(ioChannel, DISPATCH_IO_STOP);
|
||||
return;
|
||||
}
|
||||
if (data && dispatch_data_get_size(data) != 0)
|
||||
{
|
||||
[self handleConnectionData:data
|
||||
forSocket:clientSocket];
|
||||
}
|
||||
if (done)
|
||||
{
|
||||
dispatch_io_close(ioChannel, DISPATCH_IO_STOP);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (void)handleConnectionData:(dispatch_data_t)data forSocket:(int)sock
|
||||
{
|
||||
NSData *reqData;
|
||||
NSString *reqString;
|
||||
NSRange bodyRange;
|
||||
NSString *method, *url, *version;
|
||||
NSURL *requestURL;
|
||||
NSScanner *scanner;
|
||||
Route *selectedRoute = nil;
|
||||
|
||||
__block NSString *firstLine = nil;
|
||||
__block NSMutableURLRequest *request = [NSMutableURLRequest new];
|
||||
__block NSUInteger headerEndIndex = 1;
|
||||
|
||||
reqData = copyDispatchDataToNSData(data);
|
||||
reqString = [[NSString alloc] initWithData:reqData
|
||||
encoding:NSUTF8StringEncoding];
|
||||
|
||||
/*
|
||||
* generic-message = Request-Line
|
||||
* *(message-header CRLF)
|
||||
* CRLF
|
||||
* [ message-body ]
|
||||
* Request-Line = Method SP Request-URI SP HTTP-Version CRLF
|
||||
*/
|
||||
[reqString enumerateLinesUsingBlock2:^(NSString *line,
|
||||
NSUInteger lineEndIndex, BOOL *stop) {
|
||||
NSRange range;
|
||||
NSString *key, *value;
|
||||
NSCharacterSet *set;
|
||||
|
||||
set = [NSCharacterSet whitespaceCharacterSet];
|
||||
|
||||
/* Parse Request Line */
|
||||
if (nil == firstLine)
|
||||
{
|
||||
firstLine = [line stringByTrimmingCharactersInSet:set];
|
||||
return;
|
||||
}
|
||||
|
||||
/* Reached end of message header. Stop. */
|
||||
if ([line length] == 0)
|
||||
{
|
||||
*stop = YES;
|
||||
headerEndIndex = lineEndIndex;
|
||||
}
|
||||
|
||||
range = [line rangeOfString:@":"];
|
||||
/* Ignore this line */
|
||||
if (NSNotFound == range.location)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
key = [[line substringToIndex:range.location]
|
||||
stringByTrimmingCharactersInSet:set];
|
||||
value = [[line substringFromIndex:range.location + 1]
|
||||
stringByTrimmingCharactersInSet:set];
|
||||
|
||||
[request addValue:value forHTTPHeaderField:key];
|
||||
}];
|
||||
|
||||
/* Calculate remaining body range */
|
||||
bodyRange = NSMakeRange(headerEndIndex, [reqData length] - headerEndIndex);
|
||||
reqData = [reqData subdataWithRange:bodyRange];
|
||||
|
||||
/* Parse Request Line */
|
||||
scanner = [NSScanner scannerWithString:firstLine];
|
||||
[scanner scanUpToString:@" " intoString:&method];
|
||||
[scanner scanUpToString:@" " intoString:&url];
|
||||
[scanner scanUpToString:@" " intoString:&version];
|
||||
|
||||
requestURL = [NSURL URLWithString:url];
|
||||
|
||||
[request setURL:requestURL];
|
||||
[request setHTTPMethod:method];
|
||||
[request setHTTPBody:reqData];
|
||||
|
||||
for (Route *r in _routes)
|
||||
{
|
||||
if ([r acceptsURL:requestURL method:method])
|
||||
{
|
||||
selectedRoute = r;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
NSData *responseData;
|
||||
if (selectedRoute)
|
||||
{
|
||||
responseData = [selectedRoute block]([request copy]);
|
||||
}
|
||||
else
|
||||
{
|
||||
responseData = [@"HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\n\r\n"
|
||||
dataUsingEncoding:NSASCIIStringEncoding];
|
||||
}
|
||||
|
||||
send(sock, [responseData bytes], [responseData length], 0);
|
||||
}
|
||||
|
||||
- (void)setRoutes:(NSArray<Route *> *)routes
|
||||
{
|
||||
_routes = [routes copy];
|
||||
}
|
||||
|
||||
- (NSInteger)port
|
||||
{
|
||||
return _port;
|
||||
}
|
||||
|
||||
- (void)resume
|
||||
{
|
||||
if (_stop)
|
||||
{
|
||||
_stop = NO;
|
||||
dispatch_async(_acceptQueue, ^{
|
||||
while (!_stop)
|
||||
{
|
||||
[self acceptConnection];
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
- (void)suspend
|
||||
{
|
||||
_stop = YES;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
#ifndef __APPLE__
|
||||
dispatch_release(_acceptQueue);
|
||||
#endif
|
||||
|
||||
close(_socket);
|
||||
#ifdef _WIN32
|
||||
WSACleanup();
|
||||
#endif
|
||||
}
|
||||
|
||||
@end
|
|
@ -1,26 +0,0 @@
|
|||
#import <Foundation/NSDate.h>
|
||||
#import <Foundation/NSRunLoop.h>
|
||||
|
||||
@interface
|
||||
NSRunLoop (TimeOutAdditions)
|
||||
- (void)runForSeconds:(NSTimeInterval)seconds conditionBlock:(BOOL (^)())block;
|
||||
@end
|
||||
|
||||
@implementation
|
||||
NSRunLoop (TimeOutAdditions)
|
||||
- (void)runForSeconds:(NSTimeInterval)seconds conditionBlock:(BOOL (^)())block
|
||||
{
|
||||
NSDate *startDate = [NSDate date];
|
||||
NSTimeInterval endTime = [startDate timeIntervalSince1970] + seconds;
|
||||
NSTimeInterval interval = 0.1; // Interval to check the condition
|
||||
|
||||
while (block() && [[NSDate date] timeIntervalSince1970] < endTime)
|
||||
{
|
||||
@autoreleasepool
|
||||
{
|
||||
[[NSRunLoop currentRunLoop]
|
||||
runUntilDate:[NSDate dateWithTimeIntervalSinceNow:interval]];
|
||||
}
|
||||
}
|
||||
}
|
||||
@end
|
|
@ -1,54 +0,0 @@
|
|||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas volutpat justo
|
||||
in aliquet venenatis. Aliquam eu odio volutpat, euismod turpis a, accumsan leo.
|
||||
Aliquam mauris urna, dictum a ex vel, fermentum faucibus enim. Donec eu massa
|
||||
ipsum. Vestibulum diam metus, dictum mattis urna vel, dignissim pretium magna.
|
||||
Phasellus quis mattis felis. Morbi non dapibus nunc. Fusce id ligula fringilla,
|
||||
varius tortor et, vulputate arcu. Quisque justo dolor, bibendum et imperdiet
|
||||
ultricies, posuere vel elit. Aliquam vel risus et sapien malesuada tempor.
|
||||
Aenean lorem metus, rutrum ut massa non, ultrices tincidunt neque. Nullam
|
||||
viverra rhoncus sem et convallis.
|
||||
|
||||
Sed id ligula non mauris lacinia mattis. Donec commodo tortor sed aliquet
|
||||
commodo. Curabitur auctor, nibh eu dignissim gravida, lacus eros tincidunt
|
||||
metus, ac fermentum mauris ex vitae magna. Vestibulum sed egestas elit, eu
|
||||
placerat enim. Vivamus ullamcorper sollicitudin ullamcorper. Mauris consequat
|
||||
quam et purus malesuada, quis euismod nisl scelerisque. Sed vestibulum dictum
|
||||
nisi a viverra. Ut rutrum aliquam porta. Pellentesque est augue, ullamcorper vel
|
||||
ultricies quis, posuere non turpis. Aenean suscipit nulla massa, vel venenatis
|
||||
felis molestie ut. Morbi in lorem quam. Quisque sed facilisis neque, et mattis
|
||||
ligula. Nam non placerat odio, ac sollicitudin dolor. Donec elit neque, rhoncus
|
||||
at risus fermentum, ultrices hendrerit massa. Nulla volutpat, urna id molestie
|
||||
scelerisque, ligula est laoreet mauris, eget maximus leo purus id mi.
|
||||
|
||||
Aenean arcu metus, ornare eget est sit amet, vehicula accumsan enim. Morbi ante
|
||||
diam, faucibus nec tempus molestie, vulputate auctor massa. Curabitur posuere
|
||||
iaculis pulvinar. Fusce id ligula at justo iaculis accumsan eu sed velit.
|
||||
Quisque condimentum augue non lobortis finibus. In quis interdum ligula, a
|
||||
varius ex. Vestibulum tristique orci eget velit lacinia, at lacinia lorem
|
||||
pretium. Sed ut varius mi. Vivamus elementum luctus arcu, vitae porta felis
|
||||
cursus nec.
|
||||
|
||||
Etiam sed nisl eu nulla scelerisque fermentum. Praesent blandit eros at lacus
|
||||
blandit auctor. Sed in eros sapien. Quisque ac laoreet nisi, a fringilla nunc.
|
||||
Sed auctor eros non mauris elementum vestibulum. Aenean vel urna orci.
|
||||
Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia
|
||||
curae; In sed blandit nibh. Aenean condimentum, lorem a tincidunt consequat,
|
||||
nulla nulla ornare lorem, eu cursus sapien mi aliquam arcu. Duis porttitor mi et
|
||||
ultricies porta. Donec tempus posuere lorem sit amet tincidunt. Nam nec purus
|
||||
sit amet sem accumsan consectetur. Ut a nisl volutpat, egestas diam non, feugiat
|
||||
mi.
|
||||
|
||||
Cras sed risus eget ligula tincidunt luctus. Vestibulum ut sapien dictum,
|
||||
sagittis elit vel, semper diam. Curabitur tristique ullamcorper lacus, quis
|
||||
finibus ex rutrum vel. Phasellus non blandit nisl, id tincidunt augue. Integer
|
||||
commodo metus at augue fringilla, sit amet posuere lectus iaculis. In nunc
|
||||
lacus, pulvinar scelerisque faucibus ut, fermentum ac ante. Duis in ante
|
||||
faucibus, ullamcorper est vel, convallis lacus. Nulla fermentum, nisi eget
|
||||
sollicitudin sodales, augue felis gravida est, id luctus sem augue non turpis.
|
||||
Sed a lorem vel diam maximus malesuada ut ut leo. Fusce venenatis, tellus a
|
||||
scelerisque dictum, metus elit vehicula purus, id gravida libero libero vitae
|
||||
arcu. Curabitur a cursus metus. Aenean efficitur rhoncus ante vitae imperdiet.
|
||||
Etiam ante lacus, aliquam id sem non, ullamcorper interdum libero. Sed fringilla
|
||||
dui sed est vehicula, vitae sollicitudin mauris tristique. Praesent ut arcu ut
|
||||
neque sollicitudin finibus. Vestibulum lacus risus, egestas vel lorem eget,
|
||||
pellentesque scelerisque lectus.
|
|
@ -1,224 +0,0 @@
|
|||
#import <Foundation/NSURLSession.h>
|
||||
#import <Foundation/NSData.h>
|
||||
|
||||
@class URLManager;
|
||||
|
||||
typedef void (^URLManagerCheckBlock)(URLManager *);
|
||||
|
||||
@interface URLManager
|
||||
: NSObject <NSURLSessionDataDelegate, NSURLSessionTaskDelegate,
|
||||
NSURLSessionDelegate, NSURLSessionDownloadDelegate>
|
||||
{
|
||||
URLManagerCheckBlock _checkBlock;
|
||||
|
||||
@public
|
||||
NSURLSession *currentSession;
|
||||
NSURLSessionResponseDisposition responseAnswer;
|
||||
|
||||
NSInteger numberOfExpectedTasksBeforeCheck;
|
||||
|
||||
NSInteger didCreateTaskCount;
|
||||
NSURLSessionTask *didCreateTask;
|
||||
|
||||
NSInteger didBecomeInvalidCount;
|
||||
NSError *didBecomeInvalidError;
|
||||
|
||||
NSInteger httpRedirectionCount;
|
||||
NSURLSessionTask *httpRedirectionTask;
|
||||
NSHTTPURLResponse *httpRedirectionResponse;
|
||||
NSURLRequest *httpRedirectionRequest;
|
||||
|
||||
NSInteger didCompleteCount;
|
||||
NSURLSessionTask *didCompleteTask;
|
||||
NSError *didCompleteError;
|
||||
|
||||
NSInteger didWriteDataCount;
|
||||
NSURLSessionDownloadTask *didWriteDataTask;
|
||||
int64_t downloadBytesWritten;
|
||||
int64_t downloadTotalBytesWritten;
|
||||
int64_t downloadTotalBytesExpectedToWrite;
|
||||
|
||||
NSInteger didFinishDownloadingCount;
|
||||
NSURLSessionDownloadTask *didFinishDownloadingTask;
|
||||
NSURL *didFinishDownloadingURL;
|
||||
|
||||
NSInteger didReceiveResponseCount;
|
||||
NSURLSessionDataTask *didReceiveResponseTask;
|
||||
NSURLResponse *didReceiveResponse;
|
||||
|
||||
NSInteger didReceiveDataCount;
|
||||
NSURLSessionDataTask *didReceiveDataTask;
|
||||
NSMutableData *accumulatedData;
|
||||
|
||||
BOOL cancelRedirect;
|
||||
}
|
||||
|
||||
- (void)setCheckBlock:(URLManagerCheckBlock)block;
|
||||
|
||||
@end
|
||||
|
||||
@implementation URLManager
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self)
|
||||
{
|
||||
responseAnswer = NSURLSessionResponseAllow;
|
||||
accumulatedData = [[NSMutableData alloc] init];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setCheckBlock:(URLManagerCheckBlock)block
|
||||
{
|
||||
_checkBlock = _Block_copy(block);
|
||||
}
|
||||
|
||||
#pragma mark - Session Lifecycle
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session
|
||||
didCreateTask:(NSURLSessionTask *)task
|
||||
{
|
||||
ASSIGN(currentSession, session);
|
||||
|
||||
didCreateTaskCount += 1;
|
||||
ASSIGN(didCreateTask, task);
|
||||
}
|
||||
- (void)URLSession:(NSURLSession *)session
|
||||
didBecomeInvalidWithError:(NSError *)error
|
||||
{
|
||||
ASSIGN(currentSession, session);
|
||||
ASSIGN(didBecomeInvalidError, error);
|
||||
|
||||
didBecomeInvalidCount += 1;
|
||||
}
|
||||
|
||||
#pragma mark - Task Updates
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session
|
||||
task:(NSURLSessionTask *)task
|
||||
willPerformHTTPRedirection:(NSHTTPURLResponse *)response
|
||||
newRequest:(NSURLRequest *)request
|
||||
completionHandler:(void (^)(NSURLRequest *))completionHandler
|
||||
{
|
||||
ASSIGN(currentSession, session);
|
||||
ASSIGN(httpRedirectionTask, task);
|
||||
ASSIGN(httpRedirectionResponse, response);
|
||||
ASSIGN(httpRedirectionRequest, request);
|
||||
|
||||
if (cancelRedirect)
|
||||
{
|
||||
completionHandler(NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
completionHandler(request);
|
||||
}
|
||||
|
||||
httpRedirectionCount += 1;
|
||||
}
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session
|
||||
task:(NSURLSessionTask *)task
|
||||
didCompleteWithError:(nullable NSError *)error
|
||||
{
|
||||
ASSIGN(currentSession, session);
|
||||
ASSIGN(didCompleteTask, task);
|
||||
ASSIGN(didCompleteError, error);
|
||||
|
||||
didCompleteCount += 1;
|
||||
if (didCompleteCount == numberOfExpectedTasksBeforeCheck
|
||||
&& _checkBlock != NULL)
|
||||
{
|
||||
_checkBlock(self);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Data Updates
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session
|
||||
dataTask:(NSURLSessionDataTask *)dataTask
|
||||
didReceiveResponse:(NSURLResponse *)response
|
||||
completionHandler:
|
||||
(void (^)(NSURLSessionResponseDisposition))completionHandler
|
||||
{
|
||||
ASSIGN(currentSession, session);
|
||||
ASSIGN(didReceiveResponseTask, dataTask);
|
||||
ASSIGN(didReceiveResponse, response);
|
||||
|
||||
didReceiveResponseCount += 1;
|
||||
|
||||
completionHandler(responseAnswer);
|
||||
}
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session
|
||||
dataTask:(NSURLSessionDataTask *)dataTask
|
||||
didReceiveData:(NSData *)data
|
||||
{
|
||||
ASSIGN(currentSession, session);
|
||||
ASSIGN(didReceiveResponseTask, dataTask);
|
||||
|
||||
didReceiveDataCount += 1;
|
||||
|
||||
[accumulatedData appendData:data];
|
||||
}
|
||||
|
||||
#pragma mark - Download Updates
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session
|
||||
downloadTask:(NSURLSessionDownloadTask *)downloadTask
|
||||
didWriteData:(int64_t)bytesWritten
|
||||
totalBytesWritten:(int64_t)totalBytesWritten
|
||||
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
|
||||
{
|
||||
ASSIGN(currentSession, session);
|
||||
|
||||
didWriteDataCount += 1;
|
||||
downloadBytesWritten = bytesWritten;
|
||||
downloadTotalBytesExpectedToWrite = totalBytesExpectedToWrite;
|
||||
downloadTotalBytesExpectedToWrite = totalBytesExpectedToWrite;
|
||||
}
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session
|
||||
downloadTask:(NSURLSessionDownloadTask *)downloadTask
|
||||
didFinishDownloadingToURL:(NSURL *)location
|
||||
{
|
||||
ASSIGN(currentSession, session);
|
||||
ASSIGN(didFinishDownloadingTask, downloadTask);
|
||||
ASSIGN(didFinishDownloadingURL, location);
|
||||
|
||||
didFinishDownloadingCount += 1;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
RELEASE(currentSession);
|
||||
|
||||
RELEASE(didCreateTask);
|
||||
RELEASE(didBecomeInvalidError);
|
||||
|
||||
RELEASE(httpRedirectionTask);
|
||||
RELEASE(httpRedirectionResponse);
|
||||
RELEASE(httpRedirectionRequest);
|
||||
|
||||
RELEASE(didCompleteTask);
|
||||
RELEASE(didCompleteError);
|
||||
|
||||
RELEASE(didWriteDataTask);
|
||||
|
||||
RELEASE(didFinishDownloadingTask);
|
||||
RELEASE(didFinishDownloadingURL);
|
||||
|
||||
RELEASE(didReceiveResponseTask);
|
||||
RELEASE(didReceiveResponse);
|
||||
|
||||
RELEASE(didReceiveDataTask);
|
||||
RELEASE(accumulatedData);
|
||||
|
||||
_Block_release(_checkBlock);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@end
|
131
Tests/base/NSURLSession/delegate.g
Normal file
131
Tests/base/NSURLSession/delegate.g
Normal file
|
@ -0,0 +1,131 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
#import "Testing.h"
|
||||
#import "ObjectTesting.h"
|
||||
|
||||
@interface MyDelegate : NSObject <NSURLSessionDelegate>
|
||||
{
|
||||
BOOL _finished;
|
||||
NSMutableArray *_order;
|
||||
NSURLResponse *_response;
|
||||
NSData *_taskData;
|
||||
NSString *_taskText;
|
||||
NSError *_taskError;
|
||||
NSURL *_taskLocation;
|
||||
}
|
||||
- (BOOL) finished;
|
||||
- (void) reset;
|
||||
@end
|
||||
|
||||
@implementation MyDelegate
|
||||
- (void) dealloc
|
||||
{
|
||||
[self reset];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (BOOL) finished
|
||||
{
|
||||
return _finished;
|
||||
}
|
||||
|
||||
- (id) init
|
||||
{
|
||||
if (nil != (self = [super init]))
|
||||
{
|
||||
_order = [NSMutableArray new];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSMutableArray*) order
|
||||
{
|
||||
return _order;
|
||||
}
|
||||
|
||||
- (void) reset
|
||||
{
|
||||
DESTROY(_order);
|
||||
DESTROY(_response);
|
||||
DESTROY(_taskData);
|
||||
DESTROY(_taskError);
|
||||
DESTROY(_taskText);
|
||||
DESTROY(_taskLocation);
|
||||
_finished = NO;
|
||||
}
|
||||
|
||||
- (NSURLResponse*) response
|
||||
{
|
||||
return _response;
|
||||
}
|
||||
- (NSData*) taskData
|
||||
{
|
||||
return _taskData;
|
||||
}
|
||||
- (NSError*) taskError
|
||||
{
|
||||
return _taskError;
|
||||
}
|
||||
- (NSString*) taskText
|
||||
{
|
||||
return _taskText;
|
||||
}
|
||||
|
||||
- (NSURL*) taskLocation
|
||||
{
|
||||
return _taskLocation;
|
||||
}
|
||||
|
||||
- (void) URLSession: (NSURLSession*)session
|
||||
dataTask: (NSURLSessionDataTask*)dataTask
|
||||
didReceiveResponse: (NSURLResponse*)response
|
||||
completionHandler: (void (^)(NSURLSessionResponseDisposition disposition))completionHandler
|
||||
{
|
||||
[_order addObject: NSStringFromSelector(_cmd)];
|
||||
ASSIGN(_response, response);
|
||||
completionHandler(NSURLSessionResponseAllow);
|
||||
}
|
||||
|
||||
- (void) URLSession: (NSURLSession*)session
|
||||
dataTask: (NSURLSessionDataTask*)dataTask
|
||||
didReceiveData: (NSData*)data
|
||||
{
|
||||
[_order addObject: NSStringFromSelector(_cmd)];
|
||||
|
||||
NSString *text;
|
||||
|
||||
ASSIGN(_taskData, data);
|
||||
text = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
|
||||
if (nil != text)
|
||||
{
|
||||
ASSIGN(_taskText, text);
|
||||
}
|
||||
RELEASE(text);
|
||||
}
|
||||
|
||||
/* NSURLSessionDownloadDelegate */
|
||||
- (void) URLSession: (NSURLSession *)session
|
||||
downloadTask: (NSURLSessionDownloadTask *)downloadTask
|
||||
didFinishDownloadingToURL: (NSURL *)location
|
||||
{
|
||||
ASSIGN(_taskLocation, location);
|
||||
}
|
||||
|
||||
- (void) URLSession: (NSURLSession*)session
|
||||
task: (NSURLSessionTask*)task
|
||||
didCompleteWithError: (NSError*)error
|
||||
{
|
||||
[_order addObject: NSStringFromSelector(_cmd)];
|
||||
_finished = YES;
|
||||
|
||||
if (error == nil)
|
||||
{
|
||||
NSLog(@"Download is Successful");
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog(@"Error %@", [error userInfo]);
|
||||
}
|
||||
ASSIGN(_taskError, error);
|
||||
}
|
||||
@end
|
||||
|
79
Tests/base/NSURLSession/gdbinit
Normal file
79
Tests/base/NSURLSession/gdbinit
Normal file
|
@ -0,0 +1,79 @@
|
|||
def print_ivar
|
||||
set $adr = malloc(1000)
|
||||
call strcpy(($adr),($arg1))
|
||||
call GSObjCPrint(($arg0),($adr))
|
||||
call free($adr)
|
||||
end
|
||||
|
||||
def print_ivars
|
||||
if ((($arg0)->isa->info & 0x01) || (($arg0)->isa->info == 2816))
|
||||
# arg0 is a pointer to an object
|
||||
set $cls = ($arg0)->isa
|
||||
else
|
||||
if (($arg0)->isa->info & 0x02)
|
||||
# arg0 is a pointer to a class
|
||||
set $cls = ($arg0)
|
||||
else
|
||||
# arg0 is something else
|
||||
set $cls = 0
|
||||
end
|
||||
end
|
||||
while (($cls) != 0)
|
||||
set $ivars = ($cls)->ivars
|
||||
if (($ivars) != 0)
|
||||
set $i = 0
|
||||
while ($i < ($ivars)->count)
|
||||
output ($ivars)->ivar_list[$i]
|
||||
echo \n
|
||||
set $i = $i + 1
|
||||
end
|
||||
end
|
||||
set $cls = ($cls)->super_class
|
||||
end
|
||||
end
|
||||
|
||||
def pivi
|
||||
print *(int *)((char *)($arg0) + ($arg1)))
|
||||
end
|
||||
|
||||
def pivl
|
||||
print *(long *)((char *)($arg0) + ($arg1)))
|
||||
end
|
||||
|
||||
def pivp
|
||||
print *(void *)((char *)($arg0) + ($arg1)))
|
||||
end
|
||||
|
||||
def pivo
|
||||
po *((id *)((char *)($arg0) + ($arg1)))
|
||||
end
|
||||
|
||||
|
||||
document print_ivars
|
||||
Recursively print the instance varibles of the object or a class given
|
||||
as first (and only) argument.
|
||||
end
|
||||
|
||||
document pivi
|
||||
Print the value of the an instance variable as an int.
|
||||
The first argument is the pointer to the object and the second the
|
||||
offset of the instance variable.
|
||||
end
|
||||
|
||||
document pivl
|
||||
Print the value of the an instance variable as a long.
|
||||
The first argument is the pointer to the object and the second the
|
||||
offset of the instance variable.
|
||||
end
|
||||
|
||||
document pivp
|
||||
Print the value of the an instance variable as a pointer (to void).
|
||||
The first argument is the pointer to the object and the second the
|
||||
offset of the instance variable.
|
||||
end
|
||||
|
||||
document pivo
|
||||
Ask an instance variable to print itself (using po).
|
||||
The first argument is the pointer to the object and the second the
|
||||
offset of the instance variable.
|
||||
end
|
|
@ -1,886 +0,0 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
|
||||
#if GS_HAVE_NSURLSESSION
|
||||
|
||||
#import "Helpers/HTTPServer.h"
|
||||
#import "NSRunLoop+TimeOutAdditions.h"
|
||||
#import "URLManager.h"
|
||||
#import "Testing.h"
|
||||
|
||||
/* Timeout in Seconds */
|
||||
static NSInteger testTimeOut = 60;
|
||||
static NSTimeInterval expectedCountOfTasksToComplete = 0;
|
||||
|
||||
/* Accessed in delegate on different thread.
|
||||
*/
|
||||
static _Atomic(NSInteger) currentCountOfCompletedTasks = 0;
|
||||
static NSLock *countLock;
|
||||
|
||||
static NSDictionary *requestCookieProperties;
|
||||
|
||||
static NSArray<Route *> *
|
||||
createRoutes(Class routeClass, NSURL *baseURL)
|
||||
{
|
||||
Route *routeOKWithContent;
|
||||
Route *routeTmpRedirectToOK;
|
||||
Route *routeTmpRelativeRedirectToOK;
|
||||
Route *routeSetCookiesOK;
|
||||
Route *routeFoldedHeaders;
|
||||
Route *routeIncorrectlyFoldedHeaders;
|
||||
NSURL *routeOKWithContentURL;
|
||||
NSURL *routeTmpRedirectToOKURL;
|
||||
NSURL *routeTmpRelativeRedirectToOKURL;
|
||||
NSURL *routeSetCookiesOKURL;
|
||||
NSURL *routeFoldedHeadersURL;
|
||||
NSURL *routeIncorrectlyFoldedHeadersURL;
|
||||
|
||||
routeOKWithContentURL = [NSURL URLWithString:@"/contentOK"];
|
||||
routeTmpRedirectToOKURL = [NSURL URLWithString:@"/tmpRedirectToOK"];
|
||||
routeTmpRelativeRedirectToOKURL =
|
||||
[NSURL URLWithString:@"/tmpRelativeRedirectToOK"];
|
||||
routeSetCookiesOKURL = [NSURL URLWithString:@"/setCookiesOK"];
|
||||
routeFoldedHeadersURL = [NSURL URLWithString:@"/foldedHeaders"];
|
||||
routeIncorrectlyFoldedHeadersURL =
|
||||
[NSURL URLWithString:@"/incorrectFoldedHeaders"];
|
||||
|
||||
routeOKWithContent = [routeClass
|
||||
routeWithURL:routeOKWithContentURL
|
||||
method:@"GET"
|
||||
handler:^NSData *(NSURLRequest *req) {
|
||||
NSData *response;
|
||||
|
||||
response =
|
||||
[@"HTTP/1.1 200 OK\r\nContent-Length: 12\r\n\r\nHello World!"
|
||||
dataUsingEncoding:NSASCIIStringEncoding];
|
||||
return response;
|
||||
}];
|
||||
|
||||
routeTmpRedirectToOK = [routeClass
|
||||
routeWithURL:routeTmpRedirectToOKURL
|
||||
method:@"GET"
|
||||
handler:^NSData *(NSURLRequest *req) {
|
||||
NSData *response;
|
||||
NSString *responseString;
|
||||
|
||||
responseString = [NSString
|
||||
stringWithFormat:@"HTTP/1.1 307 Temporary Redirect\r\nLocation: "
|
||||
@"%@\r\nContent-Length: 0\r\n\r\n",
|
||||
[baseURL
|
||||
URLByAppendingPathComponent:@"contentOK"]];
|
||||
|
||||
response = [responseString dataUsingEncoding:NSASCIIStringEncoding];
|
||||
return response;
|
||||
}];
|
||||
|
||||
routeTmpRelativeRedirectToOK = [routeClass
|
||||
routeWithURL:routeTmpRelativeRedirectToOKURL
|
||||
method:@"GET"
|
||||
handler:^NSData *(NSURLRequest *req) {
|
||||
NSData *response;
|
||||
NSString *responseString;
|
||||
|
||||
responseString = [NSString
|
||||
stringWithFormat:@"HTTP/1.1 307 Temporary Redirect\r\nLocation: "
|
||||
@"contentOK\r\nContent-Length: 0\r\n\r\n"];
|
||||
|
||||
response = [responseString dataUsingEncoding:NSASCIIStringEncoding];
|
||||
return response;
|
||||
}];
|
||||
|
||||
routeSetCookiesOK = [routeClass
|
||||
routeWithURL:routeSetCookiesOKURL
|
||||
method:@"GET"
|
||||
handler:^NSData *(NSURLRequest *req) {
|
||||
NSData *response;
|
||||
NSString *httpResponse;
|
||||
|
||||
httpResponse = @"HTTP/1.1 200 OK\r\n"
|
||||
"Content-Type: text/html; charset=UTF-8\r\n"
|
||||
"Set-Cookie: sessionId=abc123; Expires=Wed, 09 Jun "
|
||||
"2100 10:18:14 GMT; Path=/\r\n"
|
||||
"Content-Length: 13\r\n"
|
||||
"\r\n"
|
||||
"Hello, world!";
|
||||
|
||||
NSString *cookie = [req allHTTPHeaderFields][@"Cookie"];
|
||||
PASS(cookie != nil, "Cookie field is not nil");
|
||||
PASS([cookie containsString:@"RequestCookie=1234"],
|
||||
"cookie contains request cookie");
|
||||
|
||||
response = [httpResponse dataUsingEncoding:NSASCIIStringEncoding];
|
||||
return response;
|
||||
}];
|
||||
|
||||
routeFoldedHeaders = [routeClass
|
||||
routeWithURL:routeFoldedHeadersURL
|
||||
method:@"GET"
|
||||
handler:^NSData *(NSURLRequest *req) {
|
||||
NSData *response;
|
||||
|
||||
response =
|
||||
[@"HTTP/1.1 200 OK\r\nContent-Length: 12\r\nFolded-Header-SP: "
|
||||
@"Test\r\n ing\r\nFolded-Header-TAB: Test\r\n\ting\r\n\r\nHello "
|
||||
@"World!" dataUsingEncoding:NSASCIIStringEncoding];
|
||||
return response;
|
||||
}];
|
||||
|
||||
routeIncorrectlyFoldedHeaders = [routeClass
|
||||
routeWithURL:routeIncorrectlyFoldedHeadersURL
|
||||
method:@"GET"
|
||||
handler:^NSData *(NSURLRequest *req) {
|
||||
NSData *response;
|
||||
|
||||
response = [@"HTTP/1.1 200 OK\r\n"
|
||||
@" ing\r\nFolded-Header-TAB: Test\r\n\ting\r\n\r\nHello "
|
||||
@"World!" dataUsingEncoding:NSASCIIStringEncoding];
|
||||
return response;
|
||||
}];
|
||||
|
||||
return @[
|
||||
routeOKWithContent, routeTmpRedirectToOK, routeTmpRelativeRedirectToOK,
|
||||
routeSetCookiesOK, routeFoldedHeaders, routeIncorrectlyFoldedHeaders
|
||||
];
|
||||
}
|
||||
|
||||
/* Block needs to be released */
|
||||
static URLManagerCheckBlock
|
||||
downloadCheckBlock(const char *prefix, NSURLSession *session,
|
||||
NSURLSessionTask *task)
|
||||
{
|
||||
return _Block_copy(^(URLManager *mgr) {
|
||||
NSURL *location;
|
||||
NSData *data;
|
||||
NSString *string;
|
||||
NSFileManager *fm;
|
||||
|
||||
location = mgr->didFinishDownloadingURL;
|
||||
fm = [NSFileManager defaultManager];
|
||||
|
||||
PASS_EQUAL(mgr->currentSession, session,
|
||||
"%s URLManager Session is equal to session", prefix);
|
||||
|
||||
/* Check URLSession:didCreateTask: callback */
|
||||
PASS(mgr->didCreateTaskCount == 1, "%s didCreateTask: Count is correct",
|
||||
prefix);
|
||||
PASS_EQUAL(mgr->didCreateTask, task,
|
||||
"%s didCreateTask: task is equal to returned task", prefix);
|
||||
|
||||
/* Check URLSession:task:didCompleteWithError: */
|
||||
PASS(nil == mgr->didCompleteError,
|
||||
"%s didCompleteWithError: No error occurred", prefix)
|
||||
PASS(mgr->didCompleteCount == 1,
|
||||
"%s didCompleteWithError: Count is correct", prefix);
|
||||
PASS_EQUAL(mgr->didCompleteTask, task,
|
||||
"%s didCompleteWithError: task is equal to returned task",
|
||||
prefix);
|
||||
|
||||
/* Check Progress Reporting */
|
||||
PASS(mgr->didWriteDataCount == 1, "%s didWriteData: count is correct",
|
||||
prefix);
|
||||
PASS(mgr->downloadTotalBytesWritten
|
||||
== mgr->downloadTotalBytesExpectedToWrite,
|
||||
"%s didWriteData: Downloaded all expected data", prefix);
|
||||
PASS(nil != mgr->didFinishDownloadingURL,
|
||||
"%s didWriteData: Download location is not nil", prefix);
|
||||
PASS([location isFileURL], "%s location is a fileURL", prefix);
|
||||
|
||||
data = [NSData dataWithContentsOfURL:location];
|
||||
PASS(nil != data, "%s dataWithContentsOfURL is not nil", prefix)
|
||||
|
||||
string = [[NSString alloc] initWithData:data
|
||||
encoding:NSASCIIStringEncoding];
|
||||
PASS(nil != string, "%s string from data is not nil", prefix);
|
||||
PASS_EQUAL(string, @"Hello World!", "%s data is correct", prefix);
|
||||
|
||||
[string release];
|
||||
|
||||
/* Remove Downloaded Item */
|
||||
if (location)
|
||||
{
|
||||
[fm removeItemAtURL:location error:NULL];
|
||||
}
|
||||
|
||||
[countLock lock];
|
||||
currentCountOfCompletedTasks += 1;
|
||||
[countLock unlock];
|
||||
});
|
||||
}
|
||||
|
||||
static URLManagerCheckBlock
|
||||
dataCheckBlock(const char *prefix, NSURLSession *session,
|
||||
NSURLSessionTask *task)
|
||||
{
|
||||
return _Block_copy(^(URLManager *mgr) {
|
||||
PASS_EQUAL(mgr->currentSession, session,
|
||||
"%s URLManager Session is equal to session", prefix);
|
||||
|
||||
/* Check URLSession:didCreateTask: callback */
|
||||
PASS(mgr->didCreateTaskCount == 1, "%s didCreateTask: Count is correct",
|
||||
prefix);
|
||||
PASS_EQUAL(mgr->didCreateTask, task,
|
||||
"%s didCreateTask: task is equal to returned task", prefix);
|
||||
|
||||
/* Check URLSession:task:didCompleteWithError: */
|
||||
PASS(nil == mgr->didCompleteError,
|
||||
"%s didCompleteWithError: No error occurred", prefix)
|
||||
PASS(mgr->didCompleteCount == 1,
|
||||
"%s didCompleteWithError: Count is correct", prefix);
|
||||
PASS_EQUAL(mgr->didCompleteTask, task,
|
||||
"%s didCompleteWithError: task is equal to returned task",
|
||||
prefix);
|
||||
|
||||
NSData *data = mgr->accumulatedData;
|
||||
PASS(mgr->didReceiveDataCount == 1, "%s didReceiveData: Count is correct",
|
||||
prefix);
|
||||
PASS(nil != data, "%s data in didReceiveData is not nil", prefix);
|
||||
|
||||
NSString *string = [[NSString alloc] initWithData:data
|
||||
encoding:NSASCIIStringEncoding];
|
||||
PASS(nil != string, "%s string from data is not nil", prefix);
|
||||
PASS_EQUAL(string, @"Hello World!", "%s data is correct", prefix);
|
||||
|
||||
[string release];
|
||||
|
||||
[countLock lock];
|
||||
currentCountOfCompletedTasks += 1;
|
||||
[countLock unlock];
|
||||
});
|
||||
}
|
||||
|
||||
/* Block needs to be released */
|
||||
static URLManagerCheckBlock
|
||||
dataCheckBlockFailedRequest(const char *prefix, NSURLSession *session,
|
||||
NSURLSessionTask *task)
|
||||
{
|
||||
return _Block_copy(^(URLManager *mgr) {
|
||||
PASS_EQUAL(mgr->currentSession, session,
|
||||
"%s URLManager Session is equal to session", prefix);
|
||||
|
||||
/* Check URLSession:didCreateTask: callback */
|
||||
PASS(mgr->didCreateTaskCount == 1, "%s didCreateTask: Count is correct",
|
||||
prefix);
|
||||
PASS_EQUAL(mgr->didCreateTask, task,
|
||||
"%s didCreateTask: task is equal to returned task", prefix);
|
||||
|
||||
/* Check URLSession:task:didCompleteWithError: */
|
||||
PASS(nil != mgr->didCompleteError,
|
||||
"%s didCompleteWithError: An error occurred", prefix)
|
||||
PASS(mgr->didCompleteCount == 1,
|
||||
"%s didCompleteWithError: Count is correct", prefix);
|
||||
PASS_EQUAL(mgr->didCompleteTask, task,
|
||||
"%s didCompleteWithError: task is equal to returned task",
|
||||
prefix);
|
||||
|
||||
/* Check didReceiveResponse if not a canceled redirect */
|
||||
if (!mgr->cancelRedirect)
|
||||
{
|
||||
PASS(mgr->didReceiveResponseCount == 1,
|
||||
"%s didReceiveResponse: Count is correct", prefix);
|
||||
PASS(nil != mgr->didReceiveResponse, "%s didReceiveResponse is not nil",
|
||||
prefix);
|
||||
PASS_EQUAL(mgr->didReceiveResponseTask, task,
|
||||
"%s didReceiveResponse: task is equal to returned task",
|
||||
prefix);
|
||||
}
|
||||
else
|
||||
{
|
||||
PASS_EQUAL([mgr->didCompleteError code], NSURLErrorCancelled,
|
||||
"%s didCompleteError is NSURLErrorCancelled", prefix);
|
||||
}
|
||||
|
||||
[countLock lock];
|
||||
currentCountOfCompletedTasks += 1;
|
||||
[countLock unlock];
|
||||
});
|
||||
}
|
||||
|
||||
/* Creates a downloadTaskWithURL: with the /contentOK route.
|
||||
*
|
||||
* Delegate callbacks are checked via the URLManager checkBlock.
|
||||
*/
|
||||
static URLManager *
|
||||
testSimpleDownloadTransfer(NSURL *baseURL)
|
||||
{
|
||||
NSURLSession *session;
|
||||
NSURLSessionConfiguration *configuration;
|
||||
NSURLSessionDownloadTask *task;
|
||||
URLManager *mgr;
|
||||
URLManagerCheckBlock block;
|
||||
const char *prefix = "<DownloadTransfer>";
|
||||
|
||||
NSURL *contentOKURL;
|
||||
|
||||
/* URL Delegate Setup */
|
||||
mgr = [URLManager new];
|
||||
mgr->numberOfExpectedTasksBeforeCheck = 1;
|
||||
expectedCountOfTasksToComplete += 1;
|
||||
|
||||
/* URL Setup */
|
||||
contentOKURL = [baseURL URLByAppendingPathComponent:@"contentOK"];
|
||||
|
||||
configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
|
||||
session = [NSURLSession sessionWithConfiguration:configuration
|
||||
delegate:mgr
|
||||
delegateQueue:nil];
|
||||
|
||||
task = [session downloadTaskWithURL:contentOKURL];
|
||||
PASS(nil != task, "%s Session created a valid download task", prefix);
|
||||
|
||||
/* Setup Check Block */
|
||||
block = downloadCheckBlock(prefix, session, task);
|
||||
[mgr setCheckBlock:block];
|
||||
_Block_release(block);
|
||||
|
||||
[task resume];
|
||||
|
||||
return mgr;
|
||||
}
|
||||
|
||||
static URLManager *
|
||||
testDownloadTransferWithRedirect(NSURL *baseURL)
|
||||
{
|
||||
NSURLSession *session;
|
||||
NSURLSessionConfiguration *configuration;
|
||||
NSURLSessionDownloadTask *task;
|
||||
URLManager *mgr;
|
||||
URLManagerCheckBlock block;
|
||||
const char *prefix = "<DownloadTransferWithRedirect>";
|
||||
|
||||
NSURL *contentOKURL;
|
||||
|
||||
/* URL Delegate Setup */
|
||||
mgr = [URLManager new];
|
||||
mgr->numberOfExpectedTasksBeforeCheck = 1;
|
||||
expectedCountOfTasksToComplete += 1;
|
||||
|
||||
/* URL Setup */
|
||||
contentOKURL = [baseURL URLByAppendingPathComponent:@"tmpRedirectToOK"];
|
||||
|
||||
configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
|
||||
session = [NSURLSession sessionWithConfiguration:configuration
|
||||
delegate:mgr
|
||||
delegateQueue:nil];
|
||||
|
||||
task = [session downloadTaskWithURL:contentOKURL];
|
||||
PASS(nil != task, "%s Session created a valid download task", prefix);
|
||||
|
||||
/* Setup Check Block */
|
||||
block = downloadCheckBlock(prefix, session, task);
|
||||
[mgr setCheckBlock:block];
|
||||
_Block_release(block);
|
||||
|
||||
[task resume];
|
||||
|
||||
return mgr;
|
||||
}
|
||||
|
||||
/* This should use the build in redirection system from libcurl */
|
||||
static void
|
||||
testDataTransferWithRedirectAndBlock(NSURL *baseURL)
|
||||
{
|
||||
NSURLSession *session;
|
||||
NSURLSessionDataTask *task;
|
||||
NSURL *url;
|
||||
|
||||
expectedCountOfTasksToComplete += 1;
|
||||
|
||||
session = [NSURLSession sharedSession];
|
||||
url = [baseURL URLByAppendingPathComponent:@"tmpRedirectToOK"];
|
||||
task = [session
|
||||
dataTaskWithURL:url
|
||||
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
|
||||
NSString *string;
|
||||
const char *prefix = "<DataTransferWithRedirectAndBlock>";
|
||||
|
||||
PASS(nil != data, "%s data in completion handler is not nil", prefix);
|
||||
PASS(nil != response, "%s response is not nil", prefix);
|
||||
PASS([response isKindOfClass:[NSHTTPURLResponse class]],
|
||||
"%s response is an NSHTTPURLResponse", prefix);
|
||||
PASS(nil == error, "%s error is nil", prefix);
|
||||
|
||||
string = [[NSString alloc] initWithData:data
|
||||
encoding:NSASCIIStringEncoding];
|
||||
PASS_EQUAL(string, @"Hello World!", "%s received data is correct",
|
||||
prefix);
|
||||
|
||||
[string release];
|
||||
|
||||
[countLock lock];
|
||||
currentCountOfCompletedTasks += 1;
|
||||
[countLock unlock];
|
||||
}];
|
||||
|
||||
[task resume];
|
||||
}
|
||||
|
||||
static void
|
||||
testDataTransferWithCanceledRedirect(NSURL *baseURL)
|
||||
{
|
||||
NSURLSession *session;
|
||||
NSURLSessionConfiguration *configuration;
|
||||
NSURLSessionDataTask *task;
|
||||
URLManager *mgr;
|
||||
URLManagerCheckBlock block;
|
||||
const char *prefix = "<DataTransferWithCanceledRedirect>";
|
||||
|
||||
NSURL *contentOKURL;
|
||||
|
||||
/* URL Delegate Setup */
|
||||
mgr = [URLManager new];
|
||||
mgr->numberOfExpectedTasksBeforeCheck = 1;
|
||||
mgr->cancelRedirect = YES;
|
||||
expectedCountOfTasksToComplete += 1;
|
||||
|
||||
/* URL Setup */
|
||||
contentOKURL = [baseURL URLByAppendingPathComponent:@"tmpRedirectToOK"];
|
||||
configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
|
||||
session = [NSURLSession sessionWithConfiguration:configuration
|
||||
delegate:mgr
|
||||
delegateQueue:nil];
|
||||
|
||||
task = [session dataTaskWithURL:contentOKURL];
|
||||
PASS(nil != task, "%s Session created a valid download task", prefix);
|
||||
|
||||
/* Setup Check Block */
|
||||
block = dataCheckBlockFailedRequest(prefix, session, task);
|
||||
[mgr setCheckBlock:block];
|
||||
_Block_release(block);
|
||||
|
||||
[task resume];
|
||||
}
|
||||
|
||||
static void
|
||||
testDataTransferWithRelativeRedirect(NSURL *baseURL)
|
||||
{
|
||||
NSURLSession *session;
|
||||
NSURLSessionConfiguration *configuration;
|
||||
NSURLSessionDataTask *task;
|
||||
NSURL *url;
|
||||
URLManager *mgr;
|
||||
URLManagerCheckBlock block;
|
||||
const char *prefix = "<DataTransferWithRelativeRedirect>";
|
||||
|
||||
/* URL Delegate Setup */
|
||||
mgr = [URLManager new];
|
||||
mgr->numberOfExpectedTasksBeforeCheck = 1;
|
||||
expectedCountOfTasksToComplete += 1;
|
||||
|
||||
session = [NSURLSession sharedSession];
|
||||
url = [baseURL URLByAppendingPathComponent:@"tmpRelativeRedirectToOK"];
|
||||
configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
|
||||
session = [NSURLSession sessionWithConfiguration:configuration
|
||||
delegate:mgr
|
||||
delegateQueue:nil];
|
||||
|
||||
task = [session dataTaskWithURL:url];
|
||||
PASS(nil != task, "%s Session created a valid download task", prefix);
|
||||
|
||||
/* Setup Check Block */
|
||||
block = dataCheckBlock(prefix, session, task);
|
||||
[mgr setCheckBlock:block];
|
||||
_Block_release(block);
|
||||
|
||||
[task resume];
|
||||
}
|
||||
|
||||
static void
|
||||
testDownloadTransferWithBlock(NSURL *baseURL)
|
||||
{
|
||||
NSURLSession *session;
|
||||
NSURLSessionDownloadTask *task;
|
||||
NSURL *url;
|
||||
|
||||
expectedCountOfTasksToComplete += 1;
|
||||
|
||||
session = [NSURLSession sharedSession];
|
||||
url = [baseURL URLByAppendingPathComponent:@"contentOK"];
|
||||
task = [session
|
||||
downloadTaskWithURL:url
|
||||
completionHandler:^(NSURL *location, NSURLResponse *response,
|
||||
NSError *error) {
|
||||
NSFileManager *fm;
|
||||
NSData *data;
|
||||
NSString *string;
|
||||
|
||||
const char *prefix;
|
||||
|
||||
prefix = "<DownloadTransferWithBlock>";
|
||||
fm = [NSFileManager defaultManager];
|
||||
|
||||
PASS(nil != location, "%s location is not nil", prefix);
|
||||
PASS(nil != response, "%s response is not nil", prefix);
|
||||
PASS(nil == error, "%s error is nil", prefix);
|
||||
|
||||
data = [NSData dataWithContentsOfURL:location];
|
||||
PASS(nil != data, "%s data is not nil", prefix);
|
||||
|
||||
string = [[NSString alloc] initWithData:data
|
||||
encoding:NSASCIIStringEncoding];
|
||||
PASS_EQUAL(string, @"Hello World!", "%s content is correct", prefix);
|
||||
|
||||
[fm removeItemAtURL:location error:NULL];
|
||||
|
||||
[countLock lock];
|
||||
currentCountOfCompletedTasks += 1;
|
||||
[countLock unlock];
|
||||
|
||||
[string release];
|
||||
}];
|
||||
|
||||
[task resume];
|
||||
}
|
||||
|
||||
static URLManager *
|
||||
testParallelDataTransfer(NSURL *baseURL)
|
||||
{
|
||||
NSURLSession *session;
|
||||
NSURLSessionConfiguration *configuration;
|
||||
URLManager *mgr;
|
||||
NSURL *url;
|
||||
const char *prefix = "<DataTransfer>";
|
||||
|
||||
NSInteger numberOfParallelTasks = 10;
|
||||
|
||||
/* URL Delegate Setup */
|
||||
mgr = [URLManager new];
|
||||
mgr->numberOfExpectedTasksBeforeCheck = numberOfParallelTasks;
|
||||
expectedCountOfTasksToComplete += numberOfParallelTasks;
|
||||
|
||||
url = [baseURL URLByAppendingPathComponent:@"tmpRedirectToOK"];
|
||||
configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
|
||||
[configuration setHTTPMaximumConnectionsPerHost:0]; // Unlimited
|
||||
session = [NSURLSession sessionWithConfiguration:configuration
|
||||
delegate:mgr
|
||||
delegateQueue:nil];
|
||||
|
||||
/* Setup Check Block */
|
||||
[mgr setCheckBlock:^(URLManager *mgr) {
|
||||
PASS_EQUAL(mgr->currentSession, session,
|
||||
"%s URLManager Session is equal to session", prefix);
|
||||
|
||||
/* Check URLSession:didCreateTask: callback */
|
||||
PASS(mgr->didCreateTaskCount == numberOfParallelTasks,
|
||||
"%s didCreateTask: Count is correct", prefix);
|
||||
|
||||
/* Check URLSession:task:didCompleteWithError: */
|
||||
PASS(nil == mgr->didCompleteError,
|
||||
"%s didCompleteWithError: No error occurred", prefix)
|
||||
PASS(mgr->didCompleteCount == numberOfParallelTasks,
|
||||
"%s didCompleteWithError: Count is correct", prefix);
|
||||
|
||||
[countLock lock];
|
||||
currentCountOfCompletedTasks += numberOfParallelTasks;
|
||||
[countLock unlock];
|
||||
}];
|
||||
|
||||
for (NSInteger i = 0; i < numberOfParallelTasks; i++)
|
||||
{
|
||||
NSURLSessionDataTask *task;
|
||||
|
||||
task = [session dataTaskWithURL:url];
|
||||
[task resume];
|
||||
}
|
||||
|
||||
return mgr;
|
||||
}
|
||||
|
||||
static void
|
||||
testDataTaskWithBlock(NSURL *baseURL)
|
||||
{
|
||||
NSURLSession *session;
|
||||
NSURLSessionDataTask *task;
|
||||
NSURL *url;
|
||||
|
||||
expectedCountOfTasksToComplete += 1;
|
||||
|
||||
url = [baseURL URLByAppendingPathComponent:@"contentOK"];
|
||||
session = [NSURLSession sharedSession];
|
||||
task = [session
|
||||
dataTaskWithURL:url
|
||||
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
|
||||
NSString *string;
|
||||
const char *prefix = "<DataTaskWithBlock>";
|
||||
|
||||
PASS(nil != data, "%s data in completion handler is not nil", prefix);
|
||||
PASS(nil != response, "%s response is not nil", prefix);
|
||||
PASS([response isKindOfClass:[NSHTTPURLResponse class]],
|
||||
"%s response is an NSHTTPURLResponse", prefix);
|
||||
PASS(nil == error, "%s error is nil", prefix);
|
||||
|
||||
string = [[NSString alloc] initWithData:data
|
||||
encoding:NSASCIIStringEncoding];
|
||||
PASS_EQUAL(string, @"Hello World!", "%s received data is correct",
|
||||
prefix);
|
||||
|
||||
[string release];
|
||||
|
||||
[countLock lock];
|
||||
currentCountOfCompletedTasks += 1;
|
||||
[countLock unlock];
|
||||
}];
|
||||
|
||||
[task resume];
|
||||
}
|
||||
|
||||
static void
|
||||
testDataTaskWithCookies(NSURL *baseURL)
|
||||
{
|
||||
NSURLSession *session;
|
||||
NSURLSessionConfiguration *config;
|
||||
NSURLSessionDataTask *task;
|
||||
NSURL *url;
|
||||
NSHTTPCookieStorage *cookies;
|
||||
NSHTTPCookie *requestCookie;
|
||||
|
||||
expectedCountOfTasksToComplete += 1;
|
||||
|
||||
url = [baseURL URLByAppendingPathComponent:@"setCookiesOK"];
|
||||
requestCookie = [NSHTTPCookie cookieWithProperties:requestCookieProperties];
|
||||
|
||||
cookies = [NSHTTPCookieStorage new];
|
||||
[cookies setCookie:requestCookie];
|
||||
|
||||
config = [NSURLSessionConfiguration new];
|
||||
[config setHTTPCookieAcceptPolicy:NSHTTPCookieAcceptPolicyAlways];
|
||||
[config setHTTPCookieStorage:cookies];
|
||||
[config setHTTPShouldSetCookies:YES];
|
||||
|
||||
session = [NSURLSession sessionWithConfiguration:config];
|
||||
task = [session
|
||||
dataTaskWithURL:url
|
||||
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
|
||||
NSString *string;
|
||||
NSArray<NSHTTPCookie *> *cookieArray;
|
||||
NSDate *date;
|
||||
const char *prefix = "<DataTaskWithCookies>";
|
||||
|
||||
PASS(nil != data, "%s data in completion handler is not nil", prefix);
|
||||
PASS(nil != response, "%s response is not nil", prefix);
|
||||
PASS([response isKindOfClass:[NSHTTPURLResponse class]],
|
||||
"%s response is an NSHTTPURLResponse", prefix);
|
||||
PASS(nil == error, "%s error is nil", prefix);
|
||||
|
||||
string = [[NSString alloc] initWithData:data
|
||||
encoding:NSASCIIStringEncoding];
|
||||
PASS_EQUAL(string, @"Hello, world!", "%s received data is correct",
|
||||
prefix);
|
||||
|
||||
cookieArray = [cookies cookiesForURL:url];
|
||||
|
||||
NSInteger count = 0;
|
||||
for (NSHTTPCookie *ck in cookieArray)
|
||||
{
|
||||
if ([[ck name] isEqualToString:@"RequestCookie"])
|
||||
{
|
||||
PASS_EQUAL(ck, requestCookie, "RequestCookie is correct");
|
||||
count += 1;
|
||||
}
|
||||
else if ([[ck name] isEqualToString:@"sessionId"])
|
||||
{
|
||||
date = [NSDate dateWithString:@"2100-06-09 10:18:14 +0000"];
|
||||
PASS_EQUAL([ck name], @"sessionId", "Cookie name is correct");
|
||||
PASS_EQUAL([ck value], @"abc123", "Cookie value is correct");
|
||||
PASS([ck version] == 0, "Correct cookie version");
|
||||
PASS([date isEqual:[ck expiresDate]],
|
||||
"Cookie expiresDate is correct");
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
PASS(count == 2, "Found both cookies");
|
||||
|
||||
[string release];
|
||||
|
||||
[countLock lock];
|
||||
currentCountOfCompletedTasks += 1;
|
||||
[countLock unlock];
|
||||
}];
|
||||
|
||||
[task resume];
|
||||
}
|
||||
|
||||
/* Check if NSURLSessionTask correctly unfolds folded header lines */
|
||||
static void
|
||||
foldedHeaderDataTaskTest(NSURL *baseURL)
|
||||
{
|
||||
NSURLSession *session;
|
||||
NSURLSessionDataTask *task;
|
||||
NSURL *url;
|
||||
|
||||
expectedCountOfTasksToComplete += 1;
|
||||
|
||||
url = [baseURL URLByAppendingPathComponent:@"foldedHeaders"];
|
||||
session = [NSURLSession sharedSession];
|
||||
task = [session
|
||||
dataTaskWithURL:url
|
||||
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
|
||||
NSHTTPURLResponse *urlResponse = (NSHTTPURLResponse *) response;
|
||||
NSString *string;
|
||||
NSDictionary *headerDict;
|
||||
const char *prefix = "<DataTaskWithFoldedHeaders>";
|
||||
|
||||
headerDict = [urlResponse allHeaderFields];
|
||||
|
||||
PASS(nil != data, "%s data in completion handler is not nil", prefix);
|
||||
PASS(nil != response, "%s response is not nil", prefix);
|
||||
PASS([response isKindOfClass:[NSHTTPURLResponse class]],
|
||||
"%s response is an NSHTTPURLResponse", prefix);
|
||||
PASS(nil == error, "%s error is nil", prefix);
|
||||
|
||||
string = [[NSString alloc] initWithData:data
|
||||
encoding:NSASCIIStringEncoding];
|
||||
PASS_EQUAL(string, @"Hello World!", "%s received data is correct",
|
||||
prefix);
|
||||
|
||||
PASS_EQUAL([headerDict objectForKey:@"Folded-Header-SP"], @"Testing",
|
||||
"Folded header with continuation space is parsed correctly");
|
||||
PASS_EQUAL([headerDict objectForKey:@"Folded-Header-TAB"], @"Testing",
|
||||
"Folded header with continuation tab is parsed correctly");
|
||||
|
||||
[string release];
|
||||
|
||||
[countLock lock];
|
||||
currentCountOfCompletedTasks += 1;
|
||||
[countLock unlock];
|
||||
}];
|
||||
|
||||
[task resume];
|
||||
}
|
||||
|
||||
/* The disposition handler triggers transfer cancelation */
|
||||
static void
|
||||
testAbortAfterDidReceiveResponse(NSURL *baseURL)
|
||||
{
|
||||
NSURLSession *session;
|
||||
NSURLSessionConfiguration *configuration;
|
||||
NSURLSessionDataTask *task;
|
||||
URLManager *mgr;
|
||||
URLManagerCheckBlock block;
|
||||
const char *prefix = "<AbortAfterDidReceiveResponseTest>";
|
||||
|
||||
NSURL *contentOKURL;
|
||||
|
||||
/* URL Delegate Setup */
|
||||
mgr = [URLManager new];
|
||||
mgr->numberOfExpectedTasksBeforeCheck = 1;
|
||||
mgr->responseAnswer = NSURLSessionResponseCancel;
|
||||
expectedCountOfTasksToComplete += 1;
|
||||
|
||||
/* URL Setup */
|
||||
contentOKURL = [baseURL URLByAppendingPathComponent:@"contentOK"];
|
||||
|
||||
configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
|
||||
session = [NSURLSession sessionWithConfiguration:configuration
|
||||
delegate:mgr
|
||||
delegateQueue:nil];
|
||||
|
||||
task = [session dataTaskWithURL:contentOKURL];
|
||||
PASS(nil != task, "%s Session created a valid download task", prefix);
|
||||
|
||||
/* Setup Check Block */
|
||||
block = dataCheckBlockFailedRequest(prefix, session, task);
|
||||
[mgr setCheckBlock:block];
|
||||
_Block_release(block);
|
||||
|
||||
[task resume];
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
@autoreleasepool
|
||||
{
|
||||
NSBundle *bundle;
|
||||
NSString *helperPath;
|
||||
NSURL *baseURL;
|
||||
NSFileManager *fm;
|
||||
HTTPServer *server;
|
||||
|
||||
Class httpServerClass;
|
||||
Class routeClass;
|
||||
|
||||
requestCookieProperties = @{
|
||||
NSHTTPCookieName : @"RequestCookie",
|
||||
NSHTTPCookieValue : @"1234",
|
||||
NSHTTPCookieDomain : @"127.0.0.1",
|
||||
NSHTTPCookiePath : @"/",
|
||||
NSHTTPCookieExpires :
|
||||
[NSDate dateWithString:@"2100-06-09 12:18:14 +0000"],
|
||||
NSHTTPCookieSecure : @NO,
|
||||
};
|
||||
|
||||
fm = [NSFileManager defaultManager];
|
||||
helperPath = [[fm currentDirectoryPath]
|
||||
stringByAppendingString:@"/Helpers/HTTPServer.bundle"];
|
||||
countLock = [[NSLock alloc] init];
|
||||
|
||||
bundle = [NSBundle bundleWithPath:helperPath];
|
||||
if (![bundle load])
|
||||
{
|
||||
[NSException raise:NSInternalInconsistencyException
|
||||
format:@"failed to load HTTPServer.bundle"];
|
||||
}
|
||||
|
||||
httpServerClass = [bundle principalClass];
|
||||
routeClass = [bundle classNamed:@"Route"];
|
||||
|
||||
/* Bind to dynamic port. Set routes after initialisation. */
|
||||
server = [[httpServerClass alloc] initWithPort:0 routes:nil];
|
||||
if (!server)
|
||||
{
|
||||
[NSException raise:NSInternalInconsistencyException
|
||||
format:@"failed to initialise HTTPServer"];
|
||||
}
|
||||
|
||||
baseURL =
|
||||
[NSURL URLWithString:[NSString stringWithFormat:@"http://127.0.0.1:%ld",
|
||||
[server port]]];
|
||||
|
||||
NSLog(@"Test Server: baseURL=%@", baseURL);
|
||||
|
||||
[server setRoutes:createRoutes(routeClass, baseURL)];
|
||||
[server resume];
|
||||
|
||||
// Call Test Functions here
|
||||
testSimpleDownloadTransfer(baseURL);
|
||||
testDownloadTransferWithBlock(baseURL);
|
||||
|
||||
testParallelDataTransfer(baseURL);
|
||||
testDataTaskWithBlock(baseURL);
|
||||
testDataTaskWithCookies(baseURL);
|
||||
|
||||
// Testing Header Line Unfolding
|
||||
foldedHeaderDataTaskTest(baseURL);
|
||||
|
||||
// Redirects
|
||||
testDownloadTransferWithRedirect(baseURL);
|
||||
testDataTransferWithRedirectAndBlock(baseURL);
|
||||
testDataTransferWithCanceledRedirect(baseURL);
|
||||
testDataTransferWithRelativeRedirect(baseURL);
|
||||
|
||||
/* Abort in Delegate */
|
||||
testAbortAfterDidReceiveResponse(baseURL);
|
||||
|
||||
[[NSRunLoop currentRunLoop]
|
||||
runForSeconds:testTimeOut
|
||||
conditionBlock:^BOOL(void) {
|
||||
return expectedCountOfTasksToComplete != currentCountOfCompletedTasks;
|
||||
}];
|
||||
|
||||
[server suspend];
|
||||
PASS(expectedCountOfTasksToComplete == currentCountOfCompletedTasks,
|
||||
"All transfers were completed before a timeout occurred");
|
||||
|
||||
[server release];
|
||||
[countLock release];
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* GS_HAVE_NSURLSESSION */
|
141
Tests/base/NSURLSession/test01.m
Normal file
141
Tests/base/NSURLSession/test01.m
Normal file
|
@ -0,0 +1,141 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
#import "Testing.h"
|
||||
#import "ObjectTesting.h"
|
||||
|
||||
#if GS_HAVE_NSURLSESSION
|
||||
@interface MyDelegate : NSObject <NSURLSessionDelegate>
|
||||
{
|
||||
@public
|
||||
BOOL responseCompletion;
|
||||
BOOL didComplete;
|
||||
NSString *taskText;
|
||||
NSError *taskError;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation MyDelegate
|
||||
- (void) dealloc
|
||||
{
|
||||
RELEASE(taskText);
|
||||
RELEASE(taskError);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void) URLSession: (NSURLSession*)session
|
||||
dataTask: (NSURLSessionDataTask*)dataTask
|
||||
didReceiveResponse: (NSURLResponse*)response
|
||||
completionHandler: (void (^)(NSURLSessionResponseDisposition disposition))completionHandler
|
||||
{
|
||||
responseCompletion = YES;
|
||||
if (NO == didComplete)
|
||||
{
|
||||
NSLog(@"### handler 1 before didComplete...");
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog(@"### handler 1 after didComplete...");
|
||||
}
|
||||
completionHandler(NSURLSessionResponseAllow);
|
||||
}
|
||||
|
||||
- (void) URLSession: (NSURLSession*)session
|
||||
dataTask: (NSURLSessionDataTask*)dataTask
|
||||
didReceiveData: (NSData*)data
|
||||
{
|
||||
NSString *text;
|
||||
|
||||
text = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
|
||||
if (nil == text)
|
||||
{
|
||||
NSLog(@"Received non-utf8 %@", data);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSIGN(taskText, text);
|
||||
NSLog(@"Received String %@", text);
|
||||
}
|
||||
RELEASE(text);
|
||||
}
|
||||
- (void) URLSession: (NSURLSession*)session
|
||||
task: (NSURLSessionTask*)task
|
||||
didCompleteWithError: (NSError*)error
|
||||
{
|
||||
if (error == nil)
|
||||
{
|
||||
NSLog(@"Download is Succesfull");
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog(@"Error %@", [error userInfo]);
|
||||
}
|
||||
didComplete = YES;
|
||||
ASSIGN(taskError, error);
|
||||
}
|
||||
@end
|
||||
#endif
|
||||
|
||||
int main()
|
||||
{
|
||||
START_SET("NSURLSession test01")
|
||||
|
||||
#if !GS_HAVE_NSURLSESSION
|
||||
SKIP("library built without NSURLSession support")
|
||||
#else
|
||||
NSURLSessionConfiguration *defaultConfigObject;
|
||||
NSURLSession *defaultSession;
|
||||
NSURLSessionDataTask *dataTask;
|
||||
NSMutableURLRequest *urlRequest;
|
||||
NSURL *url;
|
||||
NSOperationQueue *mainQueue;
|
||||
NSString *params;
|
||||
MyDelegate *object;
|
||||
|
||||
#if defined(_WIN32)
|
||||
NSLog(@"Marking nonexistant host test as hopeful on Windows as it seems to be broken");
|
||||
testHopeful = YES;
|
||||
#endif
|
||||
|
||||
object = AUTORELEASE([MyDelegate new]);
|
||||
mainQueue = [NSOperationQueue mainQueue];
|
||||
defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
|
||||
defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject
|
||||
delegate: object
|
||||
delegateQueue: mainQueue];
|
||||
url = [NSURL URLWithString:
|
||||
@"http://localhost:12345/not-here"];
|
||||
urlRequest = [NSMutableURLRequest requestWithURL: url];
|
||||
[urlRequest setHTTPMethod: @"POST"];
|
||||
params = @"name=Ravi&loc=India&age=31&submit=true";
|
||||
[urlRequest setHTTPBody: [params dataUsingEncoding: NSUTF8StringEncoding]];
|
||||
if ([urlRequest respondsToSelector: @selector(setDebug:)])
|
||||
{
|
||||
[urlRequest setDebug: YES];
|
||||
}
|
||||
|
||||
dataTask = [defaultSession dataTaskWithRequest: urlRequest];
|
||||
[dataTask resume];
|
||||
|
||||
NSDate *limit = [NSDate dateWithTimeIntervalSinceNow: 60.0];
|
||||
while (object->didComplete == NO
|
||||
&& [limit timeIntervalSinceNow] > 0.0)
|
||||
{
|
||||
ENTER_POOL
|
||||
NSDate *when = [NSDate dateWithTimeIntervalSinceNow: 0.1];
|
||||
|
||||
[[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode
|
||||
beforeDate: when];
|
||||
LEAVE_POOL
|
||||
}
|
||||
|
||||
PASS(YES == object->didComplete, "request completed")
|
||||
PASS([object->taskError code] == NSURLErrorCannotConnectToHost,
|
||||
"unable to connect to host")
|
||||
|
||||
#if defined(_WIN32)
|
||||
testHopeful = NO;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
END_SET("NSURLSession test01")
|
||||
return 0;
|
||||
}
|
100
Tests/base/NSURLSession/test02.m
Normal file
100
Tests/base/NSURLSession/test02.m
Normal file
|
@ -0,0 +1,100 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
#import "Testing.h"
|
||||
#import "ObjectTesting.h"
|
||||
#import "../NSURLConnection/Helpers/TestWebServer.h"
|
||||
|
||||
#if GS_HAVE_NSURLSESSION
|
||||
#import "delegate.g"
|
||||
#endif
|
||||
|
||||
int main()
|
||||
{
|
||||
START_SET("NSURLSession http")
|
||||
|
||||
#if !GS_HAVE_NSURLSESSION
|
||||
SKIP("library built without NSURLSession support")
|
||||
#else
|
||||
NSFileManager *fm;
|
||||
NSBundle *bundle;
|
||||
NSString *helperPath;
|
||||
|
||||
// load the test suite's classes
|
||||
fm = [NSFileManager defaultManager];
|
||||
helperPath = [[fm currentDirectoryPath] stringByAppendingPathComponent:
|
||||
@"../NSURLConnection/Helpers/TestConnection.bundle"];
|
||||
bundle = [NSBundle bundleWithPath: helperPath];
|
||||
NSCAssert([bundle load], NSInternalInconsistencyException);
|
||||
|
||||
TestWebServer *server;
|
||||
Class c;
|
||||
BOOL debug = YES;
|
||||
|
||||
// create a shared TestWebServer instance for performance
|
||||
c = [bundle principalClass];
|
||||
server = [[c testWebServerClass] new];
|
||||
NSCAssert(server != nil, NSInternalInconsistencyException);
|
||||
[server setDebug: debug];
|
||||
[server start: nil]; // localhost:1234 HTTP
|
||||
|
||||
|
||||
NSURLSessionConfiguration *configuration;
|
||||
NSURLSession *defaultSession;
|
||||
NSURLSessionDataTask *dataTask;
|
||||
NSMutableURLRequest *urlRequest;
|
||||
NSURL *url;
|
||||
NSOperationQueue *mainQueue;
|
||||
NSString *params;
|
||||
MyDelegate *object;
|
||||
|
||||
configuration = [[NSURLSessionConfiguration alloc] init];
|
||||
[configuration setHTTPShouldUsePipelining: YES];
|
||||
|
||||
testHopeful=YES;
|
||||
PASS_RUNS([configuration setHTTPMaximumConnectionLifetime: 42];,
|
||||
"-setHTTPMaximumConnectionLifetime: support available in CURL")
|
||||
testHopeful=NO;
|
||||
|
||||
[configuration setHTTPMaximumConnectionsPerHost: 1];
|
||||
[configuration setRequestCachePolicy: NSURLCacheStorageNotAllowed];
|
||||
|
||||
object = AUTORELEASE([MyDelegate new]);
|
||||
mainQueue = [NSOperationQueue mainQueue];
|
||||
defaultSession = [NSURLSession sessionWithConfiguration: configuration
|
||||
delegate: object
|
||||
delegateQueue: mainQueue];
|
||||
RELEASE(configuration);
|
||||
url = [NSURL URLWithString: @"http://localhost:1234/xxx"];
|
||||
params = @"dummy=true";
|
||||
urlRequest = [NSMutableURLRequest requestWithURL: url];
|
||||
[urlRequest setHTTPMethod: @"POST"];
|
||||
[urlRequest setHTTPBody: [params dataUsingEncoding: NSUTF8StringEncoding]];
|
||||
if ([urlRequest respondsToSelector: @selector(setDebug:)])
|
||||
{
|
||||
[urlRequest setDebug: YES];
|
||||
}
|
||||
|
||||
dataTask = [defaultSession dataTaskWithRequest: urlRequest];
|
||||
[dataTask resume];
|
||||
|
||||
NSDate *limit = [NSDate dateWithTimeIntervalSinceNow: 60.0];
|
||||
while ([object finished] == NO
|
||||
&& [limit timeIntervalSinceNow] > 0.0)
|
||||
{
|
||||
ENTER_POOL
|
||||
NSDate *when = [NSDate dateWithTimeIntervalSinceNow: 0.1];
|
||||
|
||||
[[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode
|
||||
beforeDate: when];
|
||||
LEAVE_POOL
|
||||
}
|
||||
|
||||
PASS(YES == [object finished], "request completed")
|
||||
PASS_EQUAL([object taskError], nil, "request did not error")
|
||||
|
||||
NSString *expect = @"Please give login and password";
|
||||
PASS_EQUAL([object taskText], expect, "request returned text")
|
||||
|
||||
#endif
|
||||
END_SET("NSURLSession http")
|
||||
return 0;
|
||||
}
|
94
Tests/base/NSURLSession/test03.m
Normal file
94
Tests/base/NSURLSession/test03.m
Normal file
|
@ -0,0 +1,94 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
#import "Testing.h"
|
||||
#import "ObjectTesting.h"
|
||||
#import "../NSURLConnection/Helpers/TestWebServer.h"
|
||||
|
||||
#if GS_HAVE_NSURLSESSION
|
||||
#import "delegate.g"
|
||||
#endif
|
||||
|
||||
int main()
|
||||
{
|
||||
START_SET("NSURLSession test03")
|
||||
|
||||
#if !GS_HAVE_NSURLSESSION
|
||||
SKIP("library built without NSURLSession support")
|
||||
#else
|
||||
NSFileManager *fm;
|
||||
NSBundle *bundle;
|
||||
NSString *helperPath;
|
||||
|
||||
// load the test suite's classes
|
||||
fm = [NSFileManager defaultManager];
|
||||
helperPath = [[fm currentDirectoryPath] stringByAppendingPathComponent:
|
||||
@"../NSURLConnection/Helpers/TestConnection.bundle"];
|
||||
bundle = [NSBundle bundleWithPath: helperPath];
|
||||
NSCAssert([bundle load], NSInternalInconsistencyException);
|
||||
|
||||
TestWebServer *server;
|
||||
Class c;
|
||||
BOOL debug = YES;
|
||||
|
||||
// create a shared TestWebServer instance for performance
|
||||
c = [bundle principalClass];
|
||||
server = [[c testWebServerClass] new];
|
||||
NSCAssert(server != nil, NSInternalInconsistencyException);
|
||||
[server setDebug: debug];
|
||||
[server start: nil]; // localhost:1234 HTTP
|
||||
|
||||
|
||||
NSURLSessionConfiguration *configuration;
|
||||
NSURLSession *defaultSession;
|
||||
NSURLSessionDownloadTask *downloadTask;
|
||||
NSMutableURLRequest *urlRequest;
|
||||
NSURL *url;
|
||||
NSOperationQueue *mainQueue;
|
||||
MyDelegate *object;
|
||||
NSString *content;
|
||||
|
||||
configuration = [[NSURLSessionConfiguration alloc] init];
|
||||
|
||||
object = AUTORELEASE([MyDelegate new]);
|
||||
mainQueue = [NSOperationQueue mainQueue];
|
||||
defaultSession = [NSURLSession sessionWithConfiguration: configuration
|
||||
delegate: object
|
||||
delegateQueue: mainQueue];
|
||||
RELEASE(configuration);
|
||||
url = [NSURL URLWithString: @"http://localhost:1234/index"];
|
||||
urlRequest = [NSMutableURLRequest requestWithURL: url];
|
||||
if ([urlRequest respondsToSelector: @selector(setDebug:)])
|
||||
{
|
||||
[urlRequest setDebug: YES];
|
||||
}
|
||||
|
||||
downloadTask = [defaultSession downloadTaskWithRequest: urlRequest];
|
||||
[downloadTask resume];
|
||||
|
||||
NSDate *limit = [NSDate dateWithTimeIntervalSinceNow: 60.0];
|
||||
while ([object finished] == NO
|
||||
&& [limit timeIntervalSinceNow] > 0.0)
|
||||
{
|
||||
ENTER_POOL
|
||||
NSDate *when = [NSDate dateWithTimeIntervalSinceNow: 0.1];
|
||||
|
||||
[[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode
|
||||
beforeDate: when];
|
||||
LEAVE_POOL
|
||||
}
|
||||
|
||||
PASS(YES == [object finished], "request completed")
|
||||
PASS_EQUAL([object taskError], nil, "request did not error")
|
||||
|
||||
/* Get content from file */
|
||||
content = [NSString stringWithContentsOfFile: [[object taskLocation] path]
|
||||
encoding: NSUTF8StringEncoding
|
||||
error:nil];
|
||||
|
||||
|
||||
NSString *expect = @"Please give login and password";
|
||||
PASS_EQUAL(content, expect, "request returned text")
|
||||
|
||||
#endif
|
||||
END_SET("NSURLSession test03")
|
||||
return 0;
|
||||
}
|
|
@ -1,204 +0,0 @@
|
|||
#include "Foundation/NSDate.h"
|
||||
#import <Foundation/Foundation.h>
|
||||
#include <Foundation/NSProgress.h>
|
||||
#include <Foundation/NSString.h>
|
||||
|
||||
#if GS_HAVE_NSURLSESSION
|
||||
|
||||
#import "Helpers/HTTPServer.h"
|
||||
#import "NSRunLoop+TimeOutAdditions.h"
|
||||
#import "URLManager.h"
|
||||
#import "Testing.h"
|
||||
|
||||
typedef void (^dataCompletionHandler)(NSData *data, NSURLResponse *response,
|
||||
NSError *error);
|
||||
|
||||
/* Timeout in Seconds */
|
||||
static NSInteger testTimeOut = 60;
|
||||
static NSTimeInterval expectedCountOfTasksToComplete = 0;
|
||||
|
||||
/* Accessed in delegate on different thread.
|
||||
*/
|
||||
static _Atomic(NSInteger) currentCountOfCompletedTasks = 0;
|
||||
static NSLock *countLock;
|
||||
|
||||
/* Expected Content */
|
||||
static NSString *largeBodyPath;
|
||||
static NSData *largeBodyContent;
|
||||
|
||||
static NSArray<Route *> *
|
||||
createRoutes(Class routeClass)
|
||||
{
|
||||
Route *routeOKWithContent;
|
||||
Route *routeLargeUpload;
|
||||
NSURL *routeOKWithContentURL;
|
||||
NSURL *routeLargeUploadURL;
|
||||
|
||||
routeOKWithContentURL = [NSURL URLWithString:@"/smallUploadOK"];
|
||||
routeLargeUploadURL = [NSURL URLWithString:@"/largeUploadOK"];
|
||||
|
||||
routeOKWithContent = [routeClass
|
||||
routeWithURL:routeOKWithContentURL
|
||||
method:@"POST"
|
||||
handler:^NSData *(NSURLRequest *req) {
|
||||
NSData *response;
|
||||
|
||||
response =
|
||||
[@"HTTP/1.1 200 OK\r\nContent-Length: 0\r\nHeader-Key: "
|
||||
@"Header-Value\r\n\r\n" dataUsingEncoding:NSASCIIStringEncoding];
|
||||
return response;
|
||||
}];
|
||||
|
||||
routeLargeUpload = [routeClass
|
||||
routeWithURL:routeLargeUploadURL
|
||||
method:@"POST"
|
||||
handler:^NSData *(NSURLRequest *req) {
|
||||
NSData *response;
|
||||
|
||||
PASS_EQUAL([req valueForHTTPHeaderField:@"Request-Key"],
|
||||
@"Request-Value",
|
||||
"Request contains user-specific header line");
|
||||
PASS_EQUAL([req valueForHTTPHeaderField:@"Content-Type"],
|
||||
@"text/plain",
|
||||
"Request contains the correct Content-Type");
|
||||
PASS_EQUAL([req HTTPBody], largeBodyContent, "HTTPBody is correct");
|
||||
|
||||
response =
|
||||
[@"HTTP/1.1 200 OK\r\nContent-Length: 0\r\nHeader-Key: "
|
||||
@"Header-Value\r\n\r\n" dataUsingEncoding:NSASCIIStringEncoding];
|
||||
|
||||
return response;
|
||||
}];
|
||||
|
||||
return @[ routeOKWithContent, routeLargeUpload ];
|
||||
}
|
||||
|
||||
static void
|
||||
testLargeUploadWithBlock(NSURL *baseURL)
|
||||
{
|
||||
NSURLSession *session;
|
||||
NSURLSessionDataTask *dataTask;
|
||||
NSURLSessionUploadTask *uploadTask;
|
||||
NSMutableURLRequest *request;
|
||||
NSURL *url;
|
||||
dataCompletionHandler handler;
|
||||
|
||||
expectedCountOfTasksToComplete += 2;
|
||||
|
||||
url = [baseURL URLByAppendingPathComponent:@"largeUploadOK"];
|
||||
session = [NSURLSession sharedSession];
|
||||
request = [NSMutableURLRequest requestWithURL:url];
|
||||
|
||||
[request setHTTPBody:largeBodyContent];
|
||||
[request setHTTPMethod:@"POST"];
|
||||
[request setValue:@"Request-Value" forHTTPHeaderField:@"Request-Key"];
|
||||
[request setValue:@"text/plain" forHTTPHeaderField:@"Content-Type"];
|
||||
|
||||
/* The completion handler for the two requests */
|
||||
handler = ^(NSData *data, NSURLResponse *response, NSError *error) {
|
||||
NSHTTPURLResponse *httpResponse = response;
|
||||
|
||||
PASS([data length] == 0, "Received empty data object");
|
||||
PASS(nil != response, "Response is not nil");
|
||||
PASS([response isKindOfClass:[NSHTTPURLResponse class]],
|
||||
"Response is a NSHTTPURLResponse");
|
||||
PASS(nil == error, "Error is nil");
|
||||
|
||||
PASS_EQUAL([[httpResponse allHeaderFields] objectForKey:@"Header-Key"],
|
||||
@"Header-Value", "Response contains custom header line");
|
||||
|
||||
[countLock lock];
|
||||
currentCountOfCompletedTasks += 1;
|
||||
[countLock unlock];
|
||||
};
|
||||
|
||||
dataTask = [session dataTaskWithRequest:request completionHandler:handler];
|
||||
uploadTask = [session uploadTaskWithRequest:request
|
||||
fromData:largeBodyContent
|
||||
completionHandler:handler];
|
||||
|
||||
[dataTask resume];
|
||||
[uploadTask resume];
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
@autoreleasepool
|
||||
{
|
||||
NSBundle *bundle;
|
||||
NSString *helperPath;
|
||||
NSString *currentDirectory;
|
||||
NSURL *baseURL;
|
||||
NSFileManager *fm;
|
||||
NSArray<Route *> *routes;
|
||||
HTTPServer *server;
|
||||
|
||||
Class httpServerClass;
|
||||
Class routeClass;
|
||||
|
||||
fm = [NSFileManager defaultManager];
|
||||
currentDirectory = [fm currentDirectoryPath];
|
||||
helperPath =
|
||||
[currentDirectory stringByAppendingString:@"/Helpers/HTTPServer.bundle"];
|
||||
countLock = [[NSLock alloc] init];
|
||||
|
||||
bundle = [NSBundle bundleWithPath:helperPath];
|
||||
if (![bundle load])
|
||||
{
|
||||
[NSException raise:NSInternalInconsistencyException
|
||||
format:@"failed to load HTTPServer.bundle"];
|
||||
}
|
||||
|
||||
/* Load Test Data */
|
||||
largeBodyPath =
|
||||
[currentDirectory stringByAppendingString:@"/Resources/largeBody.txt"];
|
||||
largeBodyContent = [NSData dataWithContentsOfFile:largeBodyPath];
|
||||
PASS(nil != largeBodyContent, "can load %s", [largeBodyPath UTF8String]);
|
||||
|
||||
httpServerClass = [bundle principalClass];
|
||||
routeClass = [bundle classNamed:@"Route"];
|
||||
routes = createRoutes(routeClass);
|
||||
server = [[httpServerClass alloc] initWithPort:0 routes:routes];
|
||||
if (!server)
|
||||
{
|
||||
[NSException raise:NSInternalInconsistencyException
|
||||
format:@"failed to create HTTPServer"];
|
||||
}
|
||||
|
||||
baseURL =
|
||||
[NSURL URLWithString:[NSString stringWithFormat:@"http://127.0.0.1:%ld",
|
||||
[server port]]];
|
||||
|
||||
NSLog(@"Server started with baseURL: %@", baseURL);
|
||||
|
||||
[server resume];
|
||||
|
||||
/* Call Test Functions here! */
|
||||
testLargeUploadWithBlock(baseURL);
|
||||
|
||||
[[NSRunLoop currentRunLoop]
|
||||
runForSeconds:testTimeOut
|
||||
conditionBlock:^BOOL(void) {
|
||||
return expectedCountOfTasksToComplete != currentCountOfCompletedTasks;
|
||||
}];
|
||||
|
||||
[server suspend];
|
||||
PASS(expectedCountOfTasksToComplete == currentCountOfCompletedTasks,
|
||||
"All transfers were completed before a timeout occurred");
|
||||
|
||||
[server release];
|
||||
[countLock release];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue