summaryrefslogtreecommitdiffstats
path: root/chrome/common/favicon/favicon_url_parser.cc
blob: ef6999eeda87e9a4b38a71d82f767fbd167748bd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/common/favicon/favicon_url_parser.h"

#include "base/strings/string_number_conversions.h"
#include "chrome/common/favicon/favicon_types.h"
#include "net/url_request/url_request.h"
#include "ui/base/layout.h"
#include "ui/base/webui/web_ui_util.h"
#include "ui/gfx/favicon_size.h"

namespace {

// Parameters which can be used in chrome://favicon path. See file
// "chrome/browser/ui/webui/favicon_source.h" for a description of
// what each does.
const char kIconURLParameter[] = "iconurl/";
const char kLargestParameter[] = "largest/";
const char kOriginParameter[] = "origin/";
const char kSizeParameter[] = "size/";

// Returns true if |search| is a substring of |path| which starts at
// |start_index|.
bool HasSubstringAt(const std::string& path,
                    size_t start_index,
                    const std::string& search) {
  return path.compare(start_index, search.length(), search) == 0;
}

}  // namespace

namespace chrome {

bool ParseFaviconPath(const std::string& path,
                      int icon_types,
                      ParsedFaviconPath* parsed) {
  parsed->is_icon_url = false;
  parsed->url = "";
  parsed->size_in_dip = gfx::kFaviconSize;
  parsed->scale_factor = ui::SCALE_FACTOR_100P;
  parsed->path_index = -1;

  if (path.empty())
    return false;

  size_t parsed_index = 0;
  if (HasSubstringAt(path, parsed_index, kLargestParameter)) {
    parsed_index += strlen(kLargestParameter);
    parsed->size_in_dip = 0;
  } else if (HasSubstringAt(path, parsed_index, kSizeParameter)) {
    parsed_index += strlen(kSizeParameter);

    size_t slash = path.find("/", parsed_index);
    if (slash == std::string::npos)
      return false;

    size_t scale_delimiter = path.find("@", parsed_index);
    std::string size_str;
    std::string scale_str;
    if (scale_delimiter == std::string::npos) {
      // Support the legacy size format of 'size/aa/' where 'aa' is the desired
      // size in DIP for the sake of not regressing the extensions which use it.
      size_str = path.substr(parsed_index, slash - parsed_index);
    } else {
      size_str = path.substr(parsed_index, scale_delimiter - parsed_index);
      scale_str = path.substr(scale_delimiter + 1,
                              slash - scale_delimiter - 1);
    }

    if (!base::StringToInt(size_str, &parsed->size_in_dip))
      return false;

    if (parsed->size_in_dip != (gfx::kFaviconSize * 4) &&
        parsed->size_in_dip != (gfx::kFaviconSize * 2)) {
      // Only 64x64, 32x32 and 16x16 icons are supported.
      parsed->size_in_dip = gfx::kFaviconSize;
    }

    if (!scale_str.empty())
      webui::ParseScaleFactor(scale_str, &parsed->scale_factor);

    // Return the default favicon (as opposed to a resized favicon) for
    // favicon sizes which are not cached by the favicon service.
    // Currently the favicon service caches:
    // - favicons of sizes "gfx::kFaviconSize * scale factor" px of type FAVICON
    //   where scale factor is one of FaviconUtil::GetFaviconScaleFactors().
    // - the largest TOUCH_ICON / TOUCH_PRECOMPOSED_ICON
    if (parsed->size_in_dip != gfx::kFaviconSize &&
        icon_types == chrome::FAVICON)
      return false;

    parsed_index = slash + 1;
  }

  if (HasSubstringAt(path, parsed_index, kIconURLParameter)) {
    parsed_index += strlen(kIconURLParameter);
    parsed->is_icon_url = true;
    parsed->url = path.substr(parsed_index);
  } else {
    // URL requests prefixed with "origin/" are converted to a form with an
    // empty path and a valid scheme. (e.g., example.com -->
    // http://example.com/ or http://example.com/a --> http://example.com/)
    if (HasSubstringAt(path, parsed_index, kOriginParameter)) {
      parsed_index += strlen(kOriginParameter);
      std::string possibly_invalid_url = path.substr(parsed_index);

      // If the URL does not specify a scheme (e.g., example.com instead of
      // http://example.com), add "http://" as a default.
      if (!GURL(possibly_invalid_url).has_scheme())
        possibly_invalid_url = "http://" + possibly_invalid_url;

      // Strip the path beyond the top-level domain.
      parsed->url = GURL(possibly_invalid_url).GetOrigin().spec();
    } else {
      parsed->url = path.substr(parsed_index);
    }
  }

  // The parsed index needs to be returned in order to allow Instant Extended
  // to translate favicon URLs using advanced parameters.
  // Example:
  //   "chrome-search://favicon/size/16@2x/<renderer-id>/<most-visited-id>"
  // would be translated to:
  //   "chrome-search://favicon/size/16@2x/<most-visited-item-with-given-id>".
  parsed->path_index = parsed_index;
  return true;
}

}  // namespace chrome