Accessing HTTP Headers From An NSURLRequest
Rudi Farkas left this comment on my tutorial demonstrating how to use JSON over HTTP on the iPhone:
I would like to get to the HTTP headers that accompanied the response to a query sent via NSURLRequest.
This falls under the easy, but not obvious class of iPhone programming problems. Worthy of a quick post:
The headers for an HTTP connection are included in the NSHTTPURLResponse
class. If you have an NSHTTPURLResponse
variable you can easily get the headers out as a NSDictionary
by sending the allHeaderFields message.
For synchronous requests — not recommended, because they block — it’s easy to populate an NSHTTPURLResponse:
NSURL *url = [NSURL URLWithString:@"https://www.mobileorchard.com"]; NSURLRequest *request = [NSURLRequest requestWithURL: url]; NSHTTPURLResponse *response; [NSURLConnection sendSynchronousRequest: request returningResponse: &response error: nil]; if ([response respondsToSelector:@selector(allHeaderFields)]) { NSDictionary *dictionary = [response allHeaderFields]; NSLog([dictionary description]); }
With an asynchronous request you have to do a little more work. When the callback connection:didReceiveResponse:
is called, it is passed an NSURLResponse
as the second parameter. You can cast it to an NSHTTPURLResponse
like so:
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response; if ([response respondsToSelector:@selector(allHeaderFields)]) { NSDictionary *dictionary = [httpResponse allHeaderFields]; NSLog([dictionary description]); } }
Updated based on Ben’s comment. See below for details.
In both cases you are performing a blind cast: you are assuming that the NSURLResponse is really a NSHTTPURLResponse but if the API returned something else, you’d generate an exception when you try to call allHeaderFields.
Objective-C is not Java. When you write &response you are just passing a memory address with no type information. NSURLConnection does not know that you declared it a NSHTTPURLResponse, and in theory it could return a pointer to any other type of NSURLResponse.
If you want to be really safe, in both cases you need to either check the class of the object or test if it responds to the allHeaderFields selector. For example:
if ([response isKindOfClass:[NSHTTPURLResponse class]]) { ...
or
if ([response respondsToSelector:@selector(allHeaderFields)]) { ...
Most of the time you’ll get by without the test because you are hard coding HTTP URLs, but if you are accepting URLs from outside sources and/or want your code to be bulletproof, you should always check types before casting.
Ben: good input. Updated the post.
Dan & Ben
After I posted my question, I searched some more, and I found the (easy, but not obvious) solution along these lines.
Thank you for the detailed discussion of the subject, for all interested developers to see.
Hi,
While you’re on the subject of HTTP header hacking, I am in my own personal hell trying to specific the byte-range in the header of an NSMutableURLRequest. I was wondering if anyone would be willing to tell me what I’m doing wrong. I should say at the outset that I have confirmed – via curl – that my server does indeed support requesting a byte range.
The code:
NSMutableURLRequest *request =
[NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:@”GET”];
// set a byte-range of 2048 bytes.
[request addValue:@”bytes=0-2047″ forHTTPHeaderField:@”Range”];
// Confirm the header information
NSLog([[request allHTTPHeaderFields] description]);
No joy at all. When I send this off to my server the entire data payload is returned. Again, and again, and again. I have scoured all the Apple docs. I have pestered the Apple dev. list and StackOverflow. Nuthin’.
Can anyone suggest what I have missed here?
Cheers,
Doug
@dugla
I want to suggest this free http testing tool using this tool you can send different http headers and view the Response header from any URL.
Sorry the url is:
https://soft-net.net/SendHTTPTool.aspx