Home | History | Annotate | Download | only in search_provider_logos
      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.
      4 
      5 #include "components/search_provider_logos/google_logo_api.h"
      6 
      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"
     12 #include "net/base/url_util.h"
     13 
     14 namespace search_provider_logos {
     15 
     16 namespace {
     17 const char kResponsePreamble[] = ")]}'";
     18 }
     19 
     20 GURL GoogleAppendFingerprintToLogoURL(const GURL& logo_url,
     21                                       const std::string& fingerprint) {
     22   return net::AppendQueryParameter(logo_url, "async", "es_dfp:" + fingerprint);
     23 }
     24 
     25 scoped_ptr<EncodedLogo> GoogleParseLogoResponse(
     26     const scoped_ptr<std::string>& response,
     27     base::Time response_time) {
     28   // Google doodles are sent as JSON with a prefix. Example:
     29   //   )]}' {"update":{"logo":{
     30   //     "data": "/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/...",
     31   //     "mime_type": "image/png",
     32   //     "fingerprint": "db063e32",
     33   //     "target": "http://www.google.com.au/search?q=Wilbur+Christiansen",
     34   //     "alt": "Wilbur Christiansen's Birthday"
     35   //     "time_to_live": 1389304799
     36   //   }}}
     37 
     38   // The response may start with )]}'. Ignore this.
     39   base::StringPiece response_sp(*response);
     40   if (response_sp.starts_with(kResponsePreamble))
     41     response_sp.remove_prefix(strlen(kResponsePreamble));
     42 
     43   scoped_ptr<base::Value> value(base::JSONReader::Read(response_sp));
     44   if (!value.get())
     45     return scoped_ptr<EncodedLogo>();
     46 
     47   // The important data lives inside several nested dictionaries:
     48   // {"update": {"logo": { "mime_type": ..., etc } } }
     49   const base::DictionaryValue* outer_dict;
     50   if (!value->GetAsDictionary(&outer_dict))
     51     return scoped_ptr<EncodedLogo>();
     52   const base::DictionaryValue* update_dict;
     53   if (!outer_dict->GetDictionary("update", &update_dict))
     54     return scoped_ptr<EncodedLogo>();
     55   const base::DictionaryValue* logo_dict;
     56   if (!update_dict->GetDictionary("logo", &logo_dict))
     57     return scoped_ptr<EncodedLogo>();
     58 
     59   scoped_ptr<EncodedLogo> logo(new EncodedLogo());
     60 
     61   std::string encoded_image_base64;
     62   if (logo_dict->GetString("data", &encoded_image_base64)) {
     63     // Data is optional, since we may be revalidating a cached logo.
     64     base::RefCountedString* encoded_image_string = new base::RefCountedString();
     65     if (!base::Base64Decode(encoded_image_base64,
     66                             &encoded_image_string->data()))
     67       return scoped_ptr<EncodedLogo>();
     68     logo->encoded_image = encoded_image_string;
     69     if (!logo_dict->GetString("mime_type", &logo->metadata.mime_type))
     70       return scoped_ptr<EncodedLogo>();
     71   }
     72 
     73   // Don't check return values since these fields are optional.
     74   logo_dict->GetString("target", &logo->metadata.on_click_url);
     75   logo_dict->GetString("fingerprint", &logo->metadata.fingerprint);
     76   logo_dict->GetString("alt", &logo->metadata.alt_text);
     77 
     78   base::TimeDelta time_to_live;
     79   int time_to_live_ms;
     80   if (logo_dict->GetInteger("time_to_live", &time_to_live_ms)) {
     81     time_to_live = base::TimeDelta::FromMilliseconds(
     82         std::min(static_cast<int64>(time_to_live_ms), kMaxTimeToLiveMS));
     83     logo->metadata.can_show_after_expiration = false;
     84   } else {
     85     time_to_live = base::TimeDelta::FromMilliseconds(kMaxTimeToLiveMS);
     86     logo->metadata.can_show_after_expiration = true;
     87   }
     88   logo->metadata.expiration_time = response_time + time_to_live;
     89 
     90   return logo.Pass();
     91 }
     92 
     93 }  // namespace search_provider_logos
     94