普通文本  |  194行  |  6.64 KB

// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/prerender/prerender_tracker.h"

#include "base/bind.h"
#include "base/logging.h"
#include "chrome/browser/prerender/prerender_pending_swap_throttle.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_process_host.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"

using content::BrowserThread;

namespace prerender {

PrerenderTracker::PrerenderTracker() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
}

PrerenderTracker::~PrerenderTracker() {
}

bool PrerenderTracker::IsPendingSwapRequestOnIOThread(
    int render_process_id, int render_frame_id, const GURL& url) const {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  ChildRouteIdPair render_frame_route_id_pair(
      render_process_id, render_frame_id);
  PendingSwapThrottleMap::const_iterator it =
      pending_swap_throttle_map_.find(render_frame_route_id_pair);
  return (it != pending_swap_throttle_map_.end() && it->second.url == url);
}

void PrerenderTracker::AddPendingSwapThrottleOnIOThread(
    int render_process_id,
    int render_frame_id,
    const GURL& url,
    const base::WeakPtr<PrerenderPendingSwapThrottle>& throttle) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  ChildRouteIdPair render_frame_route_id_pair(
      render_process_id, render_frame_id);
  PendingSwapThrottleMap::iterator it =
      pending_swap_throttle_map_.find(render_frame_route_id_pair);
  DCHECK(it != pending_swap_throttle_map_.end());
  if (it == pending_swap_throttle_map_.end())
    return;
  CHECK(!it->second.throttle);
  it->second.throttle = throttle;
}

void PrerenderTracker::AddPrerenderPendingSwapOnIOThread(
    const ChildRouteIdPair& render_frame_route_id_pair,
    const GURL& url) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  std::pair<PendingSwapThrottleMap::iterator, bool> insert_result =
      pending_swap_throttle_map_.insert(std::make_pair(
          render_frame_route_id_pair, PendingSwapThrottleData(url)));
  DCHECK(insert_result.second);
}

void PrerenderTracker::RemovePrerenderPendingSwapOnIOThread(
    const ChildRouteIdPair& render_frame_route_id_pair,
    bool swap_successful) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  PendingSwapThrottleMap::iterator it =
      pending_swap_throttle_map_.find(render_frame_route_id_pair);
  DCHECK(it != pending_swap_throttle_map_.end());
  // Cancel or resume all throttled resources.
  if (it->second.throttle) {
    if (swap_successful)
      it->second.throttle->Cancel();
    else
      it->second.throttle->Resume();
  }
  pending_swap_throttle_map_.erase(render_frame_route_id_pair);
}

void PrerenderTracker::AddPrerenderPendingSwap(
    const ChildRouteIdPair& render_frame_route_id_pair,
    const GURL& url) {
  BrowserThread::PostTask(
      BrowserThread::IO, FROM_HERE,
      base::Bind(&PrerenderTracker::AddPrerenderPendingSwapOnIOThread,
                 base::Unretained(this), render_frame_route_id_pair, url));
}

void PrerenderTracker::RemovePrerenderPendingSwap(
    const ChildRouteIdPair& render_frame_route_id_pair,
    bool swap_successful) {
  BrowserThread::PostTask(
      BrowserThread::IO, FROM_HERE,
      base::Bind(&PrerenderTracker::RemovePrerenderPendingSwapOnIOThread,
                 base::Unretained(this), render_frame_route_id_pair,
                 swap_successful));
}

PrerenderTracker::PendingSwapThrottleData::PendingSwapThrottleData(
    const GURL& swap_url)
    : url(swap_url) {
}

PrerenderTracker::PendingSwapThrottleData::~PendingSwapThrottleData() {
}

scoped_refptr<PrerenderCookieStore>
PrerenderTracker::GetPrerenderCookieStoreForRenderProcess(
    int process_id) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  PrerenderCookieStoreMap::const_iterator it =
      prerender_cookie_store_map_.find(process_id);

  if (it == prerender_cookie_store_map_.end())
    return NULL;

  return it->second;
}

void PrerenderTracker::OnCookieChangedForURL(
    int process_id,
    net::CookieMonster* cookie_monster,
    const GURL& url) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  // We only care about cookie changes by non-prerender tabs, since only those
  // get applied to the underlying cookie store. Therefore, if a cookie change
  // originated from a prerender, there is nothing to do.
  if (ContainsKey(prerender_cookie_store_map_, process_id))
    return;

  // Since the cookie change did not come from a prerender, broadcast it too
  // all prerenders so that they can be cancelled if there is a conflict.
  for (PrerenderCookieStoreMap::iterator it =
           prerender_cookie_store_map_.begin();
       it != prerender_cookie_store_map_.end();
       ++it) {
    it->second->OnCookieChangedForURL(cookie_monster, url);
  }
}

void PrerenderTracker::RemovePrerenderCookieStoreOnIOThread(int process_id,
                                                            bool was_swapped) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  PrerenderCookieStoreMap::iterator it =
      prerender_cookie_store_map_.find(process_id);

  if (it == prerender_cookie_store_map_.end())
    return;

  std::vector<GURL> cookie_change_urls;
  if (was_swapped)
    it->second->ApplyChanges(&cookie_change_urls);

  scoped_refptr<net::CookieMonster> cookie_monster(
      it->second->default_cookie_monster());

  prerender_cookie_store_map_.erase(it);

  // For each cookie updated by ApplyChanges, we need to call
  // OnCookieChangedForURL so that any potentially conflicting prerenders
  // will be aborted.
  for (std::vector<GURL>::const_iterator url_it = cookie_change_urls.begin();
       url_it != cookie_change_urls.end();
       ++url_it) {
    OnCookieChangedForURL(process_id, cookie_monster, *url_it);
  }
}

void PrerenderTracker::AddPrerenderCookieStoreOnIOThread(
    int process_id,
    scoped_refptr<net::URLRequestContextGetter> request_context,
    const base::Closure& cookie_conflict_cb) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  DCHECK(request_context != NULL);
  net::CookieMonster* cookie_monster =
      request_context->GetURLRequestContext()->cookie_store()->
      GetCookieMonster();
  DCHECK(cookie_monster != NULL);
  bool exists = (prerender_cookie_store_map_.find(process_id) !=
                 prerender_cookie_store_map_.end());
  DCHECK(!exists);
  if (exists)
    return;
  prerender_cookie_store_map_[process_id] =
      new PrerenderCookieStore(make_scoped_refptr(cookie_monster),
                               cookie_conflict_cb);
}

}  // namespace prerender