• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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