1227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks// Copyright 2014 The Chromium Authors. All rights reserved.
2227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks// Use of this source code is governed by a BSD-style license that can be
3227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks// found in the LICENSE file.
4227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
5227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks#include "components/search_provider_logos/google_logo_api.h"
6227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
7227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks#include "base/base64.h"
8227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks#include "base/json/json_reader.h"
9227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks#include "base/memory/ref_counted_memory.h"
10227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks#include "base/strings/string_util.h"
11227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks#include "base/values.h"
12227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
13227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksnamespace search_provider_logos {
14227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
15227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksnamespace {
16227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksconst char kResponsePreamble[] = ")]}'";
17227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks}
18227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
19227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin HendricksGURL GoogleAppendFingerprintToLogoURL(const GURL& logo_url,
20227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                                      const std::string& fingerprint) {
21227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  // Note: we can't just use net::AppendQueryParameter() because it escapes
22227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  // ":" to "%3A", but the server requires the colon not to be escaped.
23227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  // See: http://crbug.com/413845
24227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
25227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  // TODO(newt): Switch to using net::AppendQueryParameter once it no longer
26227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  // escapes ":"
27227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
28227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  std::string query(logo_url.query());
29227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  if (!query.empty())
30227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    query += "&";
31227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
32227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  query += "async=es_dfp:";
33227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  query += fingerprint;
34227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  GURL::Replacements replacements;
35227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  replacements.SetQueryStr(query);
36227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  return logo_url.ReplaceComponents(replacements);
37227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks}
38227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
39227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksscoped_ptr<EncodedLogo> GoogleParseLogoResponse(
40227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    const scoped_ptr<std::string>& response,
41227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    base::Time response_time) {
42227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  // Google doodles are sent as JSON with a prefix. Example:
43227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  //   )]}' {"update":{"logo":{
44227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  //     "data": "/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/...",
45227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  //     "mime_type": "image/png",
46227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  //     "fingerprint": "db063e32",
47227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  //     "target": "http://www.google.com.au/search?q=Wilbur+Christiansen",
48227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  //     "alt": "Wilbur Christiansen's Birthday"
49227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  //     "time_to_live": 1389304799
50227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  //   }}}
51227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
52227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  // The response may start with )]}'. Ignore this.
53227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  base::StringPiece response_sp(*response);
54227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  if (response_sp.starts_with(kResponsePreamble))
55227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    response_sp.remove_prefix(strlen(kResponsePreamble));
56227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
57227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  scoped_ptr<base::Value> value(base::JSONReader::Read(response_sp));
58227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  if (!value.get())
59227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    return scoped_ptr<EncodedLogo>();
60227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
61227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  // The important data lives inside several nested dictionaries:
62227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  // {"update": {"logo": { "mime_type": ..., etc } } }
63227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  const base::DictionaryValue* outer_dict;
64227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  if (!value->GetAsDictionary(&outer_dict))
65227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    return scoped_ptr<EncodedLogo>();
66227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  const base::DictionaryValue* update_dict;
67  if (!outer_dict->GetDictionary("update", &update_dict))
68    return scoped_ptr<EncodedLogo>();
69  const base::DictionaryValue* logo_dict;
70  if (!update_dict->GetDictionary("logo", &logo_dict))
71    return scoped_ptr<EncodedLogo>();
72
73  scoped_ptr<EncodedLogo> logo(new EncodedLogo());
74
75  std::string encoded_image_base64;
76  if (logo_dict->GetString("data", &encoded_image_base64)) {
77    // Data is optional, since we may be revalidating a cached logo.
78    base::RefCountedString* encoded_image_string = new base::RefCountedString();
79    if (!base::Base64Decode(encoded_image_base64,
80                            &encoded_image_string->data()))
81      return scoped_ptr<EncodedLogo>();
82    logo->encoded_image = encoded_image_string;
83    if (!logo_dict->GetString("mime_type", &logo->metadata.mime_type))
84      return scoped_ptr<EncodedLogo>();
85  }
86
87  // Don't check return values since these fields are optional.
88  logo_dict->GetString("target", &logo->metadata.on_click_url);
89  logo_dict->GetString("fingerprint", &logo->metadata.fingerprint);
90  logo_dict->GetString("alt", &logo->metadata.alt_text);
91
92  base::TimeDelta time_to_live;
93  int time_to_live_ms;
94  if (logo_dict->GetInteger("time_to_live", &time_to_live_ms)) {
95    time_to_live = base::TimeDelta::FromMilliseconds(
96        std::min(static_cast<int64>(time_to_live_ms), kMaxTimeToLiveMS));
97    logo->metadata.can_show_after_expiration = false;
98  } else {
99    time_to_live = base::TimeDelta::FromMilliseconds(kMaxTimeToLiveMS);
100    logo->metadata.can_show_after_expiration = true;
101  }
102  logo->metadata.expiration_time = response_time + time_to_live;
103
104  return logo.Pass();
105}
106
107}  // namespace search_provider_logos
108