Roll src/third_party/WebKit be75a8c:e354095 (svn 202106:202107)
[chromium-blink-merge.git] / components / search_provider_logos / google_logo_api.cc
blob5010e2c7d07aba53f898dcbeebacc263a7efec17
1 // Copyright 2014 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.
5 #include "components/search_provider_logos/google_logo_api.h"
7 #include "base/base64.h"
8 #include "base/json/json_reader.h"
9 #include "base/memory/ref_counted_memory.h"
10 #include "base/strings/string_util.h"
11 #include "base/values.h"
13 namespace search_provider_logos {
15 namespace {
16 const char kResponsePreamble[] = ")]}'";
19 GURL GoogleAppendQueryparamsToLogoURL(const GURL& logo_url,
20 const std::string& fingerprint,
21 bool wants_cta) {
22 // Note: we can't just use net::AppendQueryParameter() because it escapes
23 // ":" to "%3A", but the server requires the colon not to be escaped.
24 // See: http://crbug.com/413845
26 // TODO(newt): Switch to using net::AppendQueryParameter once it no longer
27 // escapes ":"
28 if (!fingerprint.empty() || wants_cta) {
29 std::string query(logo_url.query());
30 if (!query.empty())
31 query += "&";
33 query += "async=";
34 if (!fingerprint.empty()) {
35 query += "es_dfp:" + fingerprint;
36 if (wants_cta)
37 query += ",";
39 if (wants_cta) {
40 query += "cta:1";
42 GURL::Replacements replacements;
43 replacements.SetQueryStr(query);
44 return logo_url.ReplaceComponents(replacements);
47 return logo_url;
50 scoped_ptr<EncodedLogo> GoogleParseLogoResponse(
51 const scoped_ptr<std::string>& response,
52 base::Time response_time) {
53 // Google doodles are sent as JSON with a prefix. Example:
54 // )]}' {"update":{"logo":{
55 // "data": "/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/...",
56 // "mime_type": "image/png",
57 // "fingerprint": "db063e32",
58 // "target": "http://www.google.com.au/search?q=Wilbur+Christiansen",
59 // "url": "http://www.google.com/logos/doodle.png",
60 // "alt": "Wilbur Christiansen's Birthday"
61 // "time_to_live": 1389304799
62 // }}}
64 // The response may start with )]}'. Ignore this.
65 base::StringPiece response_sp(*response);
66 if (response_sp.starts_with(kResponsePreamble))
67 response_sp.remove_prefix(strlen(kResponsePreamble));
69 scoped_ptr<base::Value> value = base::JSONReader::Read(response_sp);
70 if (!value.get())
71 return scoped_ptr<EncodedLogo>();
73 // The important data lives inside several nested dictionaries:
74 // {"update": {"logo": { "mime_type": ..., etc } } }
75 const base::DictionaryValue* outer_dict;
76 if (!value->GetAsDictionary(&outer_dict))
77 return scoped_ptr<EncodedLogo>();
78 const base::DictionaryValue* update_dict;
79 if (!outer_dict->GetDictionary("update", &update_dict))
80 return scoped_ptr<EncodedLogo>();
81 const base::DictionaryValue* logo_dict;
82 if (!update_dict->GetDictionary("logo", &logo_dict))
83 return scoped_ptr<EncodedLogo>();
85 scoped_ptr<EncodedLogo> logo(new EncodedLogo());
87 std::string encoded_image_base64;
88 if (logo_dict->GetString("data", &encoded_image_base64)) {
89 // Data is optional, since we may be revalidating a cached logo.
90 base::RefCountedString* encoded_image_string = new base::RefCountedString();
91 if (!base::Base64Decode(encoded_image_base64,
92 &encoded_image_string->data()))
93 return scoped_ptr<EncodedLogo>();
94 logo->encoded_image = encoded_image_string;
95 if (!logo_dict->GetString("mime_type", &logo->metadata.mime_type))
96 return scoped_ptr<EncodedLogo>();
99 // Don't check return values since these fields are optional.
100 logo_dict->GetString("target", &logo->metadata.on_click_url);
101 logo_dict->GetString("fingerprint", &logo->metadata.fingerprint);
102 logo_dict->GetString("alt", &logo->metadata.alt_text);
104 // Existance of url indicates |data| is a call to action image for an
105 // animated doodle. |url| points to that animated doodle.
106 logo_dict->GetString("url", &logo->metadata.animated_url);
108 base::TimeDelta time_to_live;
109 int time_to_live_ms;
110 if (logo_dict->GetInteger("time_to_live", &time_to_live_ms)) {
111 time_to_live = base::TimeDelta::FromMilliseconds(
112 std::min(static_cast<int64>(time_to_live_ms), kMaxTimeToLiveMS));
113 logo->metadata.can_show_after_expiration = false;
114 } else {
115 time_to_live = base::TimeDelta::FromMilliseconds(kMaxTimeToLiveMS);
116 logo->metadata.can_show_after_expiration = true;
118 logo->metadata.expiration_time = response_time + time_to_live;
120 return logo.Pass();
123 } // namespace search_provider_logos