16e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 51320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "extensions/browser/updater/manifest_fetch_data.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h" 112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h" 12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h" 131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/strings/stringprintf.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/escape.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Maximum length of an extension manifest update check url, since it is a GET 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// request. We want to stay under 2K because of proxies, etc. 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kExtensionsManifestMaxURLSize = 2000; 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace extensions { 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciManifestFetchData::ManifestFetchData(const GURL& update_url, 271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci int request_id, 281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const std::string& brand_code, 291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const std::string& base_query_params, 301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci PingMode ping_mode) 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : base_url_(update_url), 321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci full_url_(update_url), 331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci brand_code_(brand_code), 341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ping_mode_(ping_mode) { 351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci std::string query = 361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci full_url_.has_query() ? full_url_.query() + "&" : std::string(); 371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci query += base_query_params; 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GURL::Replacements replacements; 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) replacements.SetQueryStr(query); 402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) full_url_ = full_url_.ReplaceComponents(replacements); 412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) request_ids_.insert(request_id); 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciManifestFetchData::~ManifestFetchData() { 461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The format for request parameters in update checks is: 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ?x=EXT1_INFO&x=EXT2_INFO 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// where EXT1_INFO and EXT2_INFO are url-encoded strings of the form: 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// id=EXTENSION_ID&v=VERSION&uc 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Provide ping data with the parameter ping=PING_DATA where PING_DATA 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// looks like r=DAYS or a=DAYS for extensions in the Chrome extensions gallery. 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ('r' refers to 'roll call' ie installation, and 'a' refers to 'active'). 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// These values will each be present at most once every 24 hours, and indicate 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the number of days since the last time it was present in an update check. 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// So for two extensions like: 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Extension 1- id:aaaa version:1.1 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Extension 2- id:bbbb version:2.0 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the full update url would be: 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// http://somehost/path?x=id%3Daaaa%26v%3D1.1%26uc&x=id%3Dbbbb%26v%3D2.0%26uc 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// (Note that '=' is %3D and '&' is %26 when urlencoded.) 705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liubool ManifestFetchData::AddExtension(const std::string& id, 715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const std::string& version, 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const PingData* ping_data, 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& update_url_data, 741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const std::string& install_source, 751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci bool force_update) { 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (extension_ids_.find(id) != extension_ids_.end()) { 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED() << "Duplicate extension id " << id; 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (force_update) 821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci forced_updates_.insert(id); 831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // If we want to force an update, we send 0.0.0.0 as the installed version 851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // number. 861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const std::string installed_version = force_update ? "0.0.0.0" : version; 871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Compute the string we'd append onto the full_url_, and see if it fits. 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<std::string> parts; 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parts.push_back("id=" + id); 911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci parts.push_back("v=" + installed_version); 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!install_source.empty()) 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parts.push_back("installsource=" + install_source); 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parts.push_back("uc"); 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!update_url_data.empty()) { 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Make sure the update_url_data string is escaped before using it so that 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // there is no chance of overriding the id or v other parameter value 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // we place into the x= value. 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parts.push_back("ap=" + net::EscapeQueryParamValue(update_url_data, true)); 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Append brand code, rollcall and active ping parameters. 1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (ping_mode_ != NO_PING) { 1051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!brand_code_.empty()) 1061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci parts.push_back(base::StringPrintf("brand=%s", brand_code_.c_str())); 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string ping_value; 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pings_[id] = PingData(0, 0, false); 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ping_data) { 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ping_data->rollcall_days == kNeverPinged || 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ping_data->rollcall_days > 0) { 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ping_value += "r=" + base::IntToString(ping_data->rollcall_days); 1141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (ping_mode_ == PING_WITH_METRICS) { 1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ping_value += "&e=" + std::string(ping_data->is_enabled ? "1" : "0"); 1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pings_[id].rollcall_days = ping_data->rollcall_days; 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pings_[id].is_enabled = ping_data->is_enabled; 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ping_data->active_days == kNeverPinged || 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ping_data->active_days > 0) { 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!ping_value.empty()) 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ping_value += "&"; 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ping_value += "a=" + base::IntToString(ping_data->active_days); 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pings_[id].active_days = ping_data->active_days; 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!ping_value.empty()) 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parts.push_back("ping=" + net::EscapeQueryParamValue(ping_value, true)); 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string extra = full_url_.has_query() ? "&" : "?"; 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extra += "x=" + net::EscapeQueryParamValue(JoinString(parts, '&'), true); 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check against our max url size, exempting the first extension added. 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int new_size = full_url_.possibly_invalid_spec().size() + extra.size(); 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!extension_ids_.empty() && new_size > kExtensionsManifestMaxURLSize) { 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UMA_HISTOGRAM_PERCENTAGE("Extensions.UpdateCheckHitUrlSizeLimit", 1); 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UMA_HISTOGRAM_PERCENTAGE("Extensions.UpdateCheckHitUrlSizeLimit", 0); 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We have room so go ahead and add the extension. 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_ids_.insert(id); 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) full_url_ = GURL(full_url_.possibly_invalid_spec() + extra); 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ManifestFetchData::Includes(const std::string& extension_id) const { 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return extension_ids_.find(extension_id) != extension_ids_.end(); 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liubool ManifestFetchData::DidPing(const std::string& extension_id, 1545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu PingType type) const { 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::map<std::string, PingData>::const_iterator i = pings_.find(extension_id); 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (i == pings_.end()) 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int value = 0; 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (type == ROLLCALL) 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value = i->second.rollcall_days; 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else if (type == ACTIVE) 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value = i->second.active_days; 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return value == kNeverPinged || value > 0; 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ManifestFetchData::Merge(const ManifestFetchData& other) { 1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(full_url() == other.full_url()); 1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) request_ids_.insert(other.request_ids_.begin(), other.request_ids_.end()); 1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool ManifestFetchData::DidForceUpdate(const std::string& extension_id) const { 1741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return forced_updates_.find(extension_id) != forced_updates_.end(); 1751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 1761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace extensions 178