I need to modify response headers in an NSURLResponse. Is this possible?
I was just talking about this with a friend. My suggestion would be to write a subclass of NSURLResponse. Something along these lines:
@interface MyHTTPURLResponse : NSURLResponse { NSDictionary *myDict; }
- (void)setAllHeaderFields:(NSDictionary *)dictionary;
@end
@implementation MyHTTPURLResponse
- (NSDictionary *)allHeaderFields { return myDict ?: [super allHeaderFields]; }
- (void)setAllHeaderFields:(NSDictionary *)dict { if (myDict != dict) { [myDict release]; myDict = [dict retain]; } }
@end
If you're dealing with an object you didn't make, you can try using object_setClass
to swizzle the class out. However I don't know if that will add the necessary instance variable. You could also use objc_setAssociatedObject
and stuff this all in a category instead, if you can support a new enough SDK.
I had a similar problem. I wanted to modify the header fileds of http url response. I needed it because wanted to provide cached url response to UIWebView and want to fool the web view that the response is not expired (i.e. I wanted to change "Cache-Control" property of the header but to keep the rest of the headers). My solution was to use NSKeyedArchiver to encode the original http response and to intercept the serialization with delegate. In
-(id) archiver:(NSKeyedArchiver*) archiver willEncodeObject:(id) object
I check if the object is NSDictionary and if so, I returned modified dictionary (i.e with updated "Cache-Control" header). Afterwards I just deserialized the serialized response using NSKeyedUnarchiver. Of course you may hook to the unarchiver and modify the headers in its delegate.
Note that in iOS 5 Apple has added
-(id)initWithURL:(NSURL*) url statusCode:(NSInteger) statusCode HTTPVersion:(NSString*) HTTPVersion headerFields:(NSDictionary*) headerFields
which is not in the documentation (documentation bug), but it is in the public API of NSHTTPURLResponse
You can do that, and you'd need NSHTTPURLResponse
not NSURLResponse
, because, in Swift, NSURLResponse
can be used with many protocols rather than just http
, such as ftp
, data:
, or https
. As a result, you can call it to get the meta data info, such as expected content type, mime type and text encoding, while NSHTTURLResponse
is the one responsible of handling HTTP protocol responses. Thus, it is the one to manipulate the headers.
This is a small code that manipulates the header key Server
from the response, and prints the value before and after the change.
let url = "https://www.google.com"
let request = NSMutableURLRequest(URL: NSURL(string: url)!)
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(request, completionHandler: {(data, response, error) in
if let response = response {
let nsHTTPURLResponse = response as! NSHTTPURLResponse
var headers = nsHTTPURLResponse.allHeaderFields
print ("The value of the Server header before is: \(headers["Server"]!)")
headers["Server"] = "whatever goes here"
print ("The value of the Server header after is: \(headers["Server"]!)")
}
})
task.resume()
You can read them into a NSDictionary using the allHeaderFields
method.
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
NSDictionary *httpResponseHeaderFields = [httpResponse
allHeaderFields];
To be 100% safe you'd want to wrap it with
if ([response respondsToSelector:@selector(allHeaderFields)]) {... }