1// Copyright 2015 The Chromium Authors 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "net/base/apple/http_response_headers_util.h" 6 7#import <Foundation/Foundation.h> 8 9#include "base/check.h" 10#include "base/format_macros.h" 11#include "base/strings/stringprintf.h" 12#include "base/strings/sys_string_conversions.h" 13#include "net/http/http_util.h" 14 15namespace { 16 17// String format used to create the http status line from the status code and 18// its localized description. 19char const kHttpStatusLineFormat[] = "HTTP %" PRIdNS " DummyStatusDescription"; 20 21} // anonymous namespace 22 23namespace net { 24 25NSString* FixNSStringIncorrectlyDecodedAsLatin1(NSString* string) { 26 // Check if the string contains any character above '\u007f'. If not, 27 // then the "latin1" and "utf-8" representation are identical, and there 28 // is no need to allocate memory for the conversion. 29 static NSCharacterSet* non_ascii_characters = [NSCharacterSet 30 characterSetWithRange:NSMakeRange(0x0080, 0x10ffff - 0x0080)]; 31 32 NSRange range = [string rangeOfCharacterFromSet:non_ascii_characters]; 33 if (range.location == NSNotFound && range.length == 0) 34 return string; 35 36 // Try to save the string as "latin1". Will fail if it does contains 37 // characters that falls out of the "latin1" range (i.e. after '\u00ff'). 38 NSData* data = [string dataUsingEncoding:NSISOLatin1StringEncoding 39 allowLossyConversion:NO]; 40 if (!data) 41 return string; 42 43 // Try to load the saved data as "utf-8". Will fail if the string is 44 // not encoded in "utf-8". In that case, it was probably not garbled 45 // and the original string needs to be used. This will be the case for 46 // strings that are genuinely encoded in "latin1". 47 NSString* decoded = [[NSString alloc] initWithData:data 48 encoding:NSUTF8StringEncoding]; 49 if (!decoded) 50 return string; 51 52 return decoded; 53} 54 55scoped_refptr<HttpResponseHeaders> CreateHeadersFromNSHTTPURLResponse( 56 NSHTTPURLResponse* response) { 57 DCHECK(response); 58 // Initialize the header with a generated status line. 59 scoped_refptr<HttpResponseHeaders> http_headers(new HttpResponseHeaders( 60 base::StringPrintf(kHttpStatusLineFormat, response.statusCode))); 61 62 // Iterate through |response|'s headers and add them to |http_headers|. 63 [response.allHeaderFields enumerateKeysAndObjectsUsingBlock:^( 64 NSString* name, NSString* value, BOOL*) { 65 const std::string header_name = base::SysNSStringToUTF8(name); 66 if (!HttpUtil::IsValidHeaderName(header_name)) 67 return; 68 69 const std::string header_value = 70 base::SysNSStringToUTF8(FixNSStringIncorrectlyDecodedAsLatin1(value)); 71 if (!HttpUtil::IsValidHeaderValue(header_value)) 72 return; 73 74 http_headers->AddHeader(header_name, header_value); 75 }]; 76 return http_headers; 77} 78 79} // namespace net 80