1// Copyright 2013 The Chromium Authors. All rights reserved.
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 "chrome/common/favicon/favicon_url_parser.h"
6
7#include "base/strings/string_number_conversions.h"
8#include "components/favicon_base/favicon_types.h"
9#include "net/url_request/url_request.h"
10#include "ui/base/webui/web_ui_util.h"
11#include "ui/gfx/favicon_size.h"
12
13namespace {
14
15// Parameters which can be used in chrome://favicon path. See file
16// "chrome/browser/ui/webui/favicon_source.h" for a description of
17// what each does.
18const char kIconURLParameter[] = "iconurl/";
19const char kLargestParameter[] = "largest/";
20const char kOriginParameter[] = "origin/";
21const char kSizeParameter[] = "size/";
22
23// Returns true if |search| is a substring of |path| which starts at
24// |start_index|.
25bool HasSubstringAt(const std::string& path,
26                    size_t start_index,
27                    const std::string& search) {
28  return path.compare(start_index, search.length(), search) == 0;
29}
30
31}  // namespace
32
33namespace chrome {
34
35bool ParseFaviconPath(const std::string& path,
36                      int icon_types,
37                      ParsedFaviconPath* parsed) {
38  parsed->is_icon_url = false;
39  parsed->url = "";
40  parsed->size_in_dip = gfx::kFaviconSize;
41  parsed->device_scale_factor = 1.0f;
42  parsed->path_index = std::string::npos;
43
44  if (path.empty())
45    return false;
46
47  size_t parsed_index = 0;
48  if (HasSubstringAt(path, parsed_index, kLargestParameter)) {
49    parsed_index += strlen(kLargestParameter);
50    parsed->size_in_dip = 0;
51  } else if (HasSubstringAt(path, parsed_index, kSizeParameter)) {
52    parsed_index += strlen(kSizeParameter);
53
54    size_t slash = path.find("/", parsed_index);
55    if (slash == std::string::npos)
56      return false;
57
58    size_t scale_delimiter = path.find("@", parsed_index);
59    std::string size_str;
60    std::string scale_str;
61    if (scale_delimiter == std::string::npos) {
62      // Support the legacy size format of 'size/aa/' where 'aa' is the desired
63      // size in DIP for the sake of not regressing the extensions which use it.
64      size_str = path.substr(parsed_index, slash - parsed_index);
65    } else {
66      size_str = path.substr(parsed_index, scale_delimiter - parsed_index);
67      scale_str = path.substr(scale_delimiter + 1,
68                              slash - scale_delimiter - 1);
69    }
70
71    if (!base::StringToInt(size_str, &parsed->size_in_dip))
72      return false;
73
74    if (parsed->size_in_dip != (gfx::kFaviconSize * 4) &&
75        parsed->size_in_dip != (gfx::kFaviconSize * 2)) {
76      // Only 64x64, 32x32 and 16x16 icons are supported.
77      parsed->size_in_dip = gfx::kFaviconSize;
78    }
79    if (!scale_str.empty())
80      webui::ParseScaleFactor(scale_str, &parsed->device_scale_factor);
81
82    // Return the default favicon (as opposed to a resized favicon) for
83    // favicon sizes which are not cached by the favicon service.
84    // Currently the favicon service caches:
85    // - favicons of sizes "gfx::kFaviconSize * scale factor" px of type FAVICON
86    //   where scale factor is one of FaviconUtil::GetFaviconScales().
87    // - the largest TOUCH_ICON / TOUCH_PRECOMPOSED_ICON
88    if (parsed->size_in_dip != gfx::kFaviconSize &&
89        icon_types == favicon_base::FAVICON)
90      return false;
91
92    parsed_index = slash + 1;
93  }
94
95  if (HasSubstringAt(path, parsed_index, kIconURLParameter)) {
96    parsed_index += strlen(kIconURLParameter);
97    parsed->is_icon_url = true;
98    parsed->url = path.substr(parsed_index);
99  } else {
100    // URL requests prefixed with "origin/" are converted to a form with an
101    // empty path and a valid scheme. (e.g., example.com -->
102    // http://example.com/ or http://example.com/a --> http://example.com/)
103    if (HasSubstringAt(path, parsed_index, kOriginParameter)) {
104      parsed_index += strlen(kOriginParameter);
105      std::string possibly_invalid_url = path.substr(parsed_index);
106
107      // If the URL does not specify a scheme (e.g., example.com instead of
108      // http://example.com), add "http://" as a default.
109      if (!GURL(possibly_invalid_url).has_scheme())
110        possibly_invalid_url = "http://" + possibly_invalid_url;
111
112      // Strip the path beyond the top-level domain.
113      parsed->url = GURL(possibly_invalid_url).GetOrigin().spec();
114    } else {
115      parsed->url = path.substr(parsed_index);
116    }
117  }
118
119  // The parsed index needs to be returned in order to allow Instant Extended
120  // to translate favicon URLs using advanced parameters.
121  // Example:
122  //   "chrome-search://favicon/size/16@2x/<renderer-id>/<most-visited-id>"
123  // would be translated to:
124  //   "chrome-search://favicon/size/16@2x/<most-visited-item-with-given-id>".
125  parsed->path_index = parsed_index;
126  return true;
127}
128
129}  // namespace chrome
130