Handle HTTP redirection, including preventing circular redirects

CQTexperiment
Christopher Snowhill 2020-03-08 20:13:46 -07:00
parent 25a030a46c
commit 18acc7fdd2
2 changed files with 58 additions and 15 deletions

View File

@ -20,8 +20,8 @@
NSURLSession * session; NSURLSession * session;
NSURLSessionDataTask * task; NSURLSessionDataTask * task;
Boolean cancelled; Boolean redirected;
Boolean errorOccurred; NSMutableArray * redirectURLs;
NSMutableArray * bufferedData; NSMutableArray * bufferedData;

View File

@ -31,7 +31,7 @@
dataTask:(NSURLSessionDataTask *)dataTask dataTask:(NSURLSessionDataTask *)dataTask
didReceiveData:(NSData *)data{ didReceiveData:(NSData *)data{
long bytesBuffered = 0; long bytesBuffered = 0;
if (cancelled) return; if (!task) return;
@synchronized(bufferedData) { @synchronized(bufferedData) {
[bufferedData addObject:data]; [bufferedData addObject:data];
_bytesBuffered += [data length]; _bytesBuffered += [data length];
@ -42,6 +42,38 @@
} }
} }
- (void)URLSession:(NSURLSession *)session
task:(NSURLSessionTask *)task
willPerformHTTPRedirection:(NSHTTPURLResponse *)response
newRequest:(NSURLRequest *)request
completionHandler:(void (^)(NSURLRequest *))completionHandler {
NSURL * url = [request URL];
if ([redirectURLs containsObject:url]) {
@synchronized(self->task) {
self->task = nil;
}
}
else {
[redirectURLs addObject:url];
redirected = YES;
@synchronized(bufferedData) {
[bufferedData removeAllObjects];
_bytesBuffered = 0;
}
@synchronized(self->task) {
self->task = [session dataTaskWithRequest:request];
[self->task resume];
}
}
}
- (void)URLSession:(NSURLSession *)session
didBecomeInvalidWithError:(NSError *)error {
@synchronized(task) {
task = nil;
}
}
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
willCacheResponse:(NSCachedURLResponse *)proposedResponse willCacheResponse:(NSCachedURLResponse *)proposedResponse
completionHandler:(void (^)(NSCachedURLResponse *cachedResponse))completionHandler{ completionHandler:(void (^)(NSCachedURLResponse *cachedResponse))completionHandler{
@ -50,18 +82,21 @@
- (void)URLSession:(NSURLSession *)session - (void)URLSession:(NSURLSession *)session
task:(NSURLSessionTask *)task task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error{ didCompleteWithError:(NSError *)error{
cancelled = YES; @synchronized(self->task) {
errorOccurred = YES; self->task = nil;
}
} }
- (BOOL)open:(NSURL *)url - (BOOL)open:(NSURL *)url
{ {
cancelled = NO; redirected = NO;
errorOccurred = NO;
redirectURLs = [[NSMutableArray alloc] init];
bufferedData = [[NSMutableArray alloc] init]; bufferedData = [[NSMutableArray alloc] init];
URL = url; URL = url;
[redirectURLs addObject:URL];
NSURLRequest * request = [NSURLRequest requestWithURL:url]; NSURLRequest * request = [NSURLRequest requestWithURL:url];
session = [self createSession]; session = [self createSession];
task = [session dataTaskWithRequest:request]; task = [session dataTaskWithRequest:request];
@ -69,12 +104,21 @@ didCompleteWithError:(NSError *)error{
NSURLResponse * response = nil; NSURLResponse * response = nil;
while (!response) { while (!response) {
@synchronized(task) {
if (!task) return NO;
redirected = NO;
response = [task response]; response = [task response];
if (response) break; }
if (errorOccurred) return NO; if (response && !redirected) break;
if (redirected) continue;
usleep(100); usleep(100);
} }
if (response) { if (response) {
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode];
if (statusCode != 200)
return NO;
}
_mimeType = [response MIMEType]; _mimeType = [response MIMEType];
} }
@ -114,8 +158,9 @@ didCompleteWithError:(NSError *)error{
dataBlock = [bufferedData objectAtIndex:0]; dataBlock = [bufferedData objectAtIndex:0];
} }
if (!dataBlock) { if (!dataBlock) {
if (errorOccurred) return totalRead; @synchronized(task) {
if (cancelled) return 0; if (!task) return totalRead;
}
usleep(1000); usleep(1000);
continue; continue;
} }
@ -163,9 +208,7 @@ didCompleteWithError:(NSError *)error{
- (void)close - (void)close
{ {
cancelled = YES; if (task) [task cancel];
[task cancel];
task = nil; task = nil;
_mimeType = nil; _mimeType = nil;