Shobhit Puri
Shobhit Puri

Reputation: 26007

Unable to receive the URL for the last redirect for a GET request ios

What I want to do:

When I make a GET request to a URL, the response is a 302 HTTP response, which means its a redirect. I know that there are multiple redirects(3 to 4) after my initial GET request. I want to get the very last URL after multiple redirects happen. I am only able to receive the first redirect URL.

What I've tried, is answers on:

My code sniplet taken from the answers:

AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSString *URLString = @"URL";
NSDictionary *parameters = @{@"k1": @"v1", @"k2": @"v2"};
NSMutableURLRequest *request_orig = [manager.requestSerializer requestWithMethod:@"GET" URLString:[[NSURL URLWithString:URLString relativeToURL:manager.baseURL] absoluteString] parameters:parameters error:nil];

AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request_orig];

[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
     //This is the first Redirect URL that I receive 
     NSLog(@"New redirect URL: %@",[[[operation response] URL] absoluteString]);
} failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
     NSLog(@"Failure: err: %@", error);
}];


[operation setRedirectResponseBlock:^NSURLRequest *(NSURLConnection *connection, NSURLRequest *request, NSURLResponse *redirectResponse) {

    if (redirectResponse) {
        NSMutableURLRequest *r = [request_orig mutableCopy]; // original request
        [r setURL: [request URL]];
        return r;
    } else {
        NSLog(@"redirecting to : %@", [request URL]);
        return request;
    }        
}];

[manager.operationQueue addOperation:operation];

I am able to receive the first redirected URL but there is no 2nd or 3rd redirect after that. What should I do in order to let the redirects continue and only receive the URL for the last redirect that is made. I am novice in iOS dev. I'll appreciate your help. Thanks.

Upvotes: 0

Views: 1057

Answers (1)

mvanallen
mvanallen

Reputation: 744

If you just want to follow all redirects, it is sufficient to keep returning the provided request and abort when data is starting to come through the connection.

I wrote this some time ago for OSX, but it should work on iOS (w/ ARC) without changes:

- (NSURL *)resolvedURLRedirectionsForURL:(NSURL *)aURL {
    NSLog(@"Started w/ initial URL: '%@'", aURL);
    NSURL           *originalURL    = aURL;
    NSURL __block   *resolvedURL    = nil;

    if (aURL) {
        dispatch_semaphore_t __communicationLock = dispatch_semaphore_create(0);

        NSURLRequest *resolveRequest = [NSURLRequest requestWithURL:originalURL
                                                        cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData
                                                    timeoutInterval:5.  ];
        AFHTTPRequestOperation *request = [[AFHTTPRequestOperation alloc] initWithRequest:resolveRequest];

        [request setRedirectResponseBlock:^NSURLRequest *(NSURLConnection *connection, NSURLRequest *request, NSURLResponse *redirectResponse) {

            NSLog(@"..request encountered redirection to: '%@'",request.URL);

            if (redirectResponse)
                resolvedURL = [request.URL copy];

            return request;
        }];

        AFHTTPRequestOperation __weak *weakRequest = request;
        [request setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
            [weakRequest cancel];
        }];

        [request setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {

            NSLog(@"..request successful! (result: %@)",responseObject);
            dispatch_semaphore_signal(__communicationLock);

        } failure:^(AFHTTPRequestOperation *operation, NSError *error) {

            if (operation.response.statusCode == 200)
                NSLog(@"..request successful! (aborted)");
            else
                NSLog(@"..request failed! (error: %@)",error);

            dispatch_semaphore_signal(__communicationLock);
        }];

        [request start];

        dispatch_semaphore_wait(__communicationLock, DISPATCH_TIME_FOREVER);
    }

    NSLog(@"Resolved URL '%@' to '%@'",originalURL,resolvedURL);

    return resolvedURL;
}

Note: Because of the semaphore it's not a good idea to run it on the main thread unaltered as it'll block the main runloop (and NSURLConnections hate that). Therefore it is better to dispatch the method call to a global queue.

Upvotes: 1

Related Questions