13

In my app, I allow the user to open up an external page in an embedded UIWebView. Is it possible for me to set the referer header that's sent with that request? I'd like for my app to get the 'cred' when the user opens up these external pages.

Edward Dale
  • 29,597
  • 13
  • 90
  • 129

2 Answers2

20

Set the referer using - setValue:forHTTPHeaderField:

NSMutableURLRequest* request = ...;
[request setValue:@"https://myapp.com" forHTTPHeaderField: @"Referer"];

But note that according to the HTTP RFC you shouldn't, because your app is not addressable using a URI:

The Referer field MUST NOT be sent if the Request-URI was obtained from a source that does not have its own URI, such as input from the user keyboard.

... unless you are using a custom protocol binded to your app (myapp://blah.com/blah).

You can create one and call loadRequest: manually or intercepting a normal request made by the user.

- (BOOL) webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType) navigationType 
{
    NSDictionary *headers = [request allHTTPHeaderFields];
    BOOL hasReferer = [headers objectForKey:@"Referer"]!=nil;
    if (hasReferer) {
        // .. is this my referer?
        return YES;
    } else {
        // relaunch with a modified request
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            dispatch_async(dispatch_get_main_queue(), ^{
                NSURL *url = [request URL];
                NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
                [request setHTTPMethod:@"GET"];
                [request setValue:@"https://whatever.com" forHTTPHeaderField: @"Referer"];
                [self.webView loadRequest:request];
            });
        });
        return NO;
    }
}
Jano
  • 62,815
  • 21
  • 164
  • 192
  • Thanks for the note from the RFC. I wasn't aware of that. The screen that my user is on when they open up the external link in the browser has its own URI, so I don't that applies to me. – Edward Dale Oct 27 '11 at 08:36
  • Where do I get the NSMutableURLRequest instance from? The UIWebViewDelegate doesn't give me the Mutable version. I found some references saying I could reliably cast it, but I'm wondering if there's a nicer way. – Edward Dale Oct 27 '11 at 08:38
  • I don't know if that is kosher, but you can intercept and relaunch the request. – Jano Oct 27 '11 at 08:56
  • Thanks for the answer. I've updated the question to only ask about sending headers with a UIWebView and will accept your answer. I'll open up another question for sending headers with Mobile Safari. – Edward Dale Oct 27 '11 at 13:46
  • 3
    It turns out that I can reliably cast the request from `UIWebViewDelegate` to a `NSMutableURLRequest`. The request replacement solution suggested above was breaking iframes in the page by re-opening them in the full browser. – Edward Dale Dec 04 '11 at 18:47
  • @scompt.com your suggestion is not working for me. Can you provide lines of code? – Wédney Yuri Jul 28 '15 at 16:17
  • @scompt.com It seems not all requests are actually NSMutableURLRequests (I have not found a pattern yet), so the cast does not work reliably – thomers Feb 12 '16 at 09:12
0

I haven't used this myself, but it looks like NSURLProtocol is the approved way to intercept and modify URL requests. Here's a tutorial: http://www.raywenderlich.com/59982/nsurlprotocol-tutorial

I'm using your solution of casting the request to NSMutableURLRequest, but since it's not documented that this is a mutable request, there's some risk that Apple might use an immutable object in the future.

bugloaf
  • 2,890
  • 3
  • 30
  • 49