Handle HTTP redirection, including preventing circular redirects
parent
25a030a46c
commit
18acc7fdd2
|
@ -20,8 +20,8 @@
|
||||||
NSURLSession * session;
|
NSURLSession * session;
|
||||||
NSURLSessionDataTask * task;
|
NSURLSessionDataTask * task;
|
||||||
|
|
||||||
Boolean cancelled;
|
Boolean redirected;
|
||||||
Boolean errorOccurred;
|
NSMutableArray * redirectURLs;
|
||||||
|
|
||||||
NSMutableArray * bufferedData;
|
NSMutableArray * bufferedData;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue