2

My application uses custom NSURLProtocol subclass. I need to substitute NSHTTPURLResponse with my copy, modifying some of the headers fields. So, I create new NSHTTPURLResponse instance, like that:

@implementation NSHTTPURLResponse (CocoaFix)

- (instancetype)HTTPResponseByRemovingValueForHeaderFields:(NSArray *)fields {
    NSMutableDictionary *mutableHeaderFields = [self.allHeaderFields mutableCopy];
    [mutableHeaderFields removeObjectsForKeys:fields];
    return [[[self class] alloc] initWithURL:self.URL
                                  statusCode:self.statusCode
                                 HTTPVersion:@"HTTP/1.1" // What should I pass here?
                                headerFields:mutableHeaderFields];
}

@end

Problem occurs with HTTPVersion parameter. I didn't find any way to obtain this value from original response.

Documentation says:

This is typically represented as "HTTP/1.1".

But providing hardcoded value not looks like a solution, that will work correctly all the time.

Please, help me with this one.

Borys Verebskyi
  • 4,160
  • 6
  • 28
  • 42

3 Answers3

0

Per this answer: NSURLRequest http protocol version, you probably need to at least bridge to the CFNetwork APIs to do this.

Community
  • 1
  • 1
fullofsquirrels
  • 1,828
  • 11
  • 16
  • Thanks for your efforts. As far as I understand, there is no way to convert `NSURLRequest` or `NSHTTPURLResponse` to `CFHTTPMessageRef` (http://stackoverflow.com/questions/2861740/core-foundation-equivalents-for-nsurlrequest-and-nsurlconnection). So, unfortunately, I can't use CFNetworking API with `NSURLProtocol`. – Borys Verebskyi Mar 23 '16 at 15:05
  • 1
    Thinking about this a bit more closely, the only viable solution I can come up with would be to swizzle the initializer in your category and have the swizzled method "capture" the HTTP version into associated object storage and invoke the original initializer. You'd also need a custom getter/accessor to get the value back out (the custom part would be reading it back out of associated object storage), but it could then be as simple as `self.httpVersion`. I can provide more details if you like, but it should be pretty straightforward if you've done swizzling before. – fullofsquirrels Mar 28 '16 at 19:20
  • 1
    Just to close the loop on this one, I attempted what I described in my previous comment, and the swizzled constructor is never called, which leads me to believe that either `NSHTTPURLResponse` is actually part of a class cluster, or there's a hidden constructor used by the NSURLSessionTasks and their like. So, never mind the inadvisability of swizzling a framework class method, I don't think it actually *could* work because of this. – fullofsquirrels Apr 06 '16 at 17:52
  • thanks for your efforts. I will also try to play with swizzling, this idea is great. Maybe I will find corresponding private constructor using runtime generated headers. Anyway, I will do that after my vacation end. – Borys Verebskyi Apr 06 '16 at 18:05
0

Per the CFNetwork team, at least as of a year ago, there was no practical way to obtain that information. In fact, from looking at the runtime analysis of the headers, I doubt that it even gets stored anymore.

If I'm right, then it also has no effect on the networking stack's behavior from that point onwards, so you could say it was "HTTP/999.99" and it wouldn't matter.

dgatwood
  • 10,129
  • 1
  • 28
  • 49
0

The NSURLSessionTaskTransactionMetrics class has property named networkProtocolName. This class instance is one of the elements of the array which is also a property named transactionMetrics, which is member of the NSURLSessionTaskMetrics which is input param named metrics in the callback method named ..didFinishCollectingMetrics:.. which is part of the NSURLSessionTaskDelegate protocol.

e.g:

- (void)URLSession:(NSURLSession *)session
              task:(NSURLSessionTask *)task
didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0)) {
    self.redirectCount = metrics.redirectCount;
    self.networkProtocolName = metrics.transactionMetrics.lastObject.networkProtocolName;
}
Nikita
  • 1,811
  • 1
  • 20
  • 41