18bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
28bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
38bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// found in the LICENSE file.
48bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
58bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "components/precache/core/precache_fetcher.h"
68bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
78bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include <string>
88bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
98bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "base/bind.h"
108bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "base/callback.h"
118bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "base/command_line.h"
128bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "base/compiler_specific.h"
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/containers/hash_tables.h"
148bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "components/precache/core/precache_switches.h"
158bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "components/precache/core/proto/precache.pb.h"
168bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "net/base/escape.h"
178bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "net/base/load_flags.h"
188bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "net/url_request/url_fetcher.h"
198bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "net/url_request/url_fetcher_delegate.h"
208bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "net/url_request/url_request_context_getter.h"
218bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "net/url_request/url_request_status.h"
228bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
238bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)using net::URLFetcher;
248bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
258bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)namespace precache {
268bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
278bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)namespace {
288bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
298bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)GURL GetConfigURL() {
308bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
318bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (command_line.HasSwitch(switches::kPrecacheConfigSettingsURL)) {
328bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return GURL(
338bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        command_line.GetSwitchValueASCII(switches::kPrecacheConfigSettingsURL));
348bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
358bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
368bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#if defined(PRECACHE_CONFIG_SETTINGS_URL)
378bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  return GURL(PRECACHE_CONFIG_SETTINGS_URL);
388bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#else
398bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // The precache config settings URL could not be determined, so return an
408bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // empty, invalid GURL.
418bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  return GURL();
428bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#endif
438bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
448bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
458bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)std::string GetManifestURLPrefix() {
468bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
478bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (command_line.HasSwitch(switches::kPrecacheManifestURLPrefix)) {
488bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return command_line.GetSwitchValueASCII(
498bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        switches::kPrecacheManifestURLPrefix);
508bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
518bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
528bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#if defined(PRECACHE_MANIFEST_URL_PREFIX)
538bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  return PRECACHE_MANIFEST_URL_PREFIX;
548bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#else
558bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // The precache manifest URL prefix could not be determined, so return an
568bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // empty string.
578bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  return std::string();
588bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#endif
598bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
608bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
618bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// Construct the URL of the precache manifest for the given starting URL.
628bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// The server is expecting a request for a URL consisting of the manifest URL
638bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// prefix followed by the doubly escaped starting URL.
648bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)GURL ConstructManifestURL(const GURL& starting_url) {
658bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  return GURL(
668bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      GetManifestURLPrefix() +
678bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      net::EscapeQueryParamValue(
688bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)          net::EscapeQueryParamValue(starting_url.spec(), false), false));
698bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
708bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
718bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// Attempts to parse a protobuf message from the response string of a
728bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// URLFetcher. If parsing is successful, the message parameter will contain the
738bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// parsed protobuf and this function will return true. Otherwise, returns false.
748bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)bool ParseProtoFromFetchResponse(const URLFetcher& source,
758bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                 ::google::protobuf::MessageLite* message) {
768bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  std::string response_string;
778bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
788bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (!source.GetStatus().is_success()) {
798bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    DLOG(WARNING) << "Fetch failed: " << source.GetOriginalURL().spec();
808bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return false;
818bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
828bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (!source.GetResponseAsString(&response_string)) {
838bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    DLOG(WARNING) << "No response string present: "
848bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                  << source.GetOriginalURL().spec();
858bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return false;
868bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
878bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (!message->ParseFromString(response_string)) {
888bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    DLOG(WARNING) << "Unable to parse proto served from "
898bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                  << source.GetOriginalURL().spec();
908bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return false;
918bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
928bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  return true;
938bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
948bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
958bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}  // namespace
968bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
978bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// Class that fetches a URL, and runs the specified callback when the fetch is
988bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// complete. This class exists so that a different method can be run in
998bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// response to different kinds of fetches, e.g. OnConfigFetchComplete when
1008bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// configuration settings are fetched, OnManifestFetchComplete when a manifest
1018bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// is fetched, etc.
1028bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)class PrecacheFetcher::Fetcher : public net::URLFetcherDelegate {
1038bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) public:
1048bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // Construct a new Fetcher. This will create and start a new URLFetcher for
1058bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // the specified URL using the specified request context.
1068bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  Fetcher(net::URLRequestContextGetter* request_context, const GURL& url,
1078bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)          const base::Callback<void(const URLFetcher&)>& callback);
1088bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  virtual ~Fetcher() {}
1098bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  virtual void OnURLFetchComplete(const URLFetcher* source) OVERRIDE;
1108bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
1118bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) private:
1128bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  const base::Callback<void(const URLFetcher&)> callback_;
1138bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  scoped_ptr<URLFetcher> url_fetcher_;
1148bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
1158bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(Fetcher);
1168bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)};
1178bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
1188bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)PrecacheFetcher::Fetcher::Fetcher(
1198bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    net::URLRequestContextGetter* request_context, const GURL& url,
1208bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    const base::Callback<void(const URLFetcher&)>& callback)
1218bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    : callback_(callback) {
1228bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  url_fetcher_.reset(URLFetcher::Create(url, URLFetcher::GET, this));
1238bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  url_fetcher_->SetRequestContext(request_context);
1248bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  url_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_PROMPT_FOR_LOGIN);
1258bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  url_fetcher_->Start();
1268bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
1278bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
1288bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void PrecacheFetcher::Fetcher::OnURLFetchComplete(const URLFetcher* source) {
1298bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  callback_.Run(*source);
1308bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
1318bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
1328bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)PrecacheFetcher::PrecacheFetcher(
1338bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    const std::list<GURL>& starting_urls,
1348bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    net::URLRequestContextGetter* request_context,
1358bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    PrecacheFetcher::PrecacheDelegate* precache_delegate)
1368bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    : starting_urls_(starting_urls),
1378bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      request_context_(request_context),
1388bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      precache_delegate_(precache_delegate) {
1391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(request_context_.get());  // Request context must be non-NULL.
1408bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  DCHECK(precache_delegate_);  // Precache delegate must be non-NULL.
1418bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
1428bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  DCHECK_NE(GURL(), GetConfigURL())
1438bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      << "Could not determine the precache config settings URL.";
1448bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  DCHECK_NE(std::string(), GetManifestURLPrefix())
1458bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      << "Could not determine the precache manifest URL prefix.";
1468bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
1478bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
1488bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)PrecacheFetcher::~PrecacheFetcher() {
1498bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
1508bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
1518bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void PrecacheFetcher::Start() {
1528bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  DCHECK(!fetcher_);  // Start shouldn't be called repeatedly.
1538bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
1548bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  GURL config_url = GetConfigURL();
1558bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  DCHECK(config_url.is_valid());
1568bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
1578bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // Fetch the precache configuration settings from the server.
1581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  fetcher_.reset(new Fetcher(request_context_.get(),
1591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                             config_url,
1608bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                             base::Bind(&PrecacheFetcher::OnConfigFetchComplete,
1618bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                        base::Unretained(this))));
1628bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
1638bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
1648bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void PrecacheFetcher::StartNextFetch() {
1658bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (!resource_urls_to_fetch_.empty()) {
1668bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    // Fetch the next resource URL.
1678bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    fetcher_.reset(
1681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        new Fetcher(request_context_.get(),
1691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                    resource_urls_to_fetch_.front(),
1708bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                    base::Bind(&PrecacheFetcher::OnResourceFetchComplete,
1718bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                               base::Unretained(this))));
1728bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
1738bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    resource_urls_to_fetch_.pop_front();
1748bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return;
1758bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
1768bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
1778bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (!manifest_urls_to_fetch_.empty()) {
1788bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    // Fetch the next manifest URL.
1798bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    fetcher_.reset(
1801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        new Fetcher(request_context_.get(),
1811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                    manifest_urls_to_fetch_.front(),
1828bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                    base::Bind(&PrecacheFetcher::OnManifestFetchComplete,
1838bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                               base::Unretained(this))));
1848bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
1858bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    manifest_urls_to_fetch_.pop_front();
1868bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return;
1878bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
1888bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
1898bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // There are no more URLs to fetch, so end the precache cycle.
1908bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  precache_delegate_->OnDone();
1918bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // OnDone may have deleted this PrecacheFetcher, so don't do anything after it
1928bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // is called.
1938bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
1948bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
1958bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void PrecacheFetcher::OnConfigFetchComplete(const URLFetcher& source) {
1968bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  PrecacheConfigurationSettings config;
1978bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
1988bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (ParseProtoFromFetchResponse(source, &config)) {
1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Keep track of starting URLs that manifests are being fetched for, in
2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // order to remove duplicates. This is a hash set on strings, and not GURLs,
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // because there is no hash function defined for GURL.
2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::hash_set<std::string> unique_starting_urls;
2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
204a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // Attempt to fetch manifests for starting URLs up to the maximum top sites
205a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // count. If a manifest does not exist for a particular starting URL, then
206a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // the fetch will fail, and that starting URL will be ignored.
2078bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    int64 rank = 0;
2088bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    for (std::list<GURL>::const_iterator it = starting_urls_.begin();
209a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         it != starting_urls_.end() && rank < config.top_sites_count();
2108bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)         ++it, ++rank) {
2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (unique_starting_urls.find(it->spec()) == unique_starting_urls.end()) {
2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        // Only add a fetch for the manifest URL if this manifest isn't already
2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        // going to be fetched.
2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        manifest_urls_to_fetch_.push_back(ConstructManifestURL(*it));
2155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        unique_starting_urls.insert(it->spec());
2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for (int i = 0; i < config.forced_starting_url_size(); ++i) {
2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // Convert the string URL into a GURL and take the spec() of it so that
2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // the URL string gets canonicalized.
2225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      GURL url(config.forced_starting_url(i));
2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (unique_starting_urls.find(url.spec()) == unique_starting_urls.end()) {
2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        // Only add a fetch for the manifest URL if this manifest isn't already
2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        // going to be fetched.
2265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        manifest_urls_to_fetch_.push_back(ConstructManifestURL(url));
2275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        unique_starting_urls.insert(url.spec());
2285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
2298bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    }
2308bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
2318bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
2328bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  StartNextFetch();
2338bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
2348bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
2358bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void PrecacheFetcher::OnManifestFetchComplete(const URLFetcher& source) {
2368bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  PrecacheManifest manifest;
2378bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
2388bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (ParseProtoFromFetchResponse(source, &manifest)) {
2398bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    for (int i = 0; i < manifest.resource_size(); ++i) {
2408bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      if (manifest.resource(i).has_url()) {
2418bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        resource_urls_to_fetch_.push_back(GURL(manifest.resource(i).url()));
2428bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      }
2438bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    }
2448bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
2458bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
2468bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  StartNextFetch();
2478bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
2488bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
2498bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void PrecacheFetcher::OnResourceFetchComplete(const URLFetcher& source) {
2508bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // The resource has already been put in the cache during the fetch process, so
2518bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // nothing more needs to be done for the resource.
2528bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  StartNextFetch();
2538bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
2548bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
2558bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}  // namespace precache
256