summaryrefslogtreecommitdiffstats
path: root/chrome/browser/prerender
diff options
context:
space:
mode:
authortburkard@chromium.org <tburkard@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-05-13 08:19:59 +0000
committertburkard@chromium.org <tburkard@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-05-13 08:19:59 +0000
commit28c5d0b7a83b11685698c5cd2ffb04c91d75a0c6 (patch)
tree949ca1fb18b48a01675ce6f62ecb0943a15bb292 /chrome/browser/prerender
parentf73e1ca075924a6ca1125d5d7f96e374532852c3 (diff)
downloadchromium_src-28c5d0b7a83b11685698c5cd2ffb04c91d75a0c6.zip
chromium_src-28c5d0b7a83b11685698c5cd2ffb04c91d75a0c6.tar.gz
chromium_src-28c5d0b7a83b11685698c5cd2ffb04c91d75a0c6.tar.bz2
Only commit cookie changes in prerenders after a prerender is shown
Will create a PrerenderCookieStore for each prerender, retaining all cookie operations of a prerender until the prerender is shown to the user. Forces prerenders to be in a new render process by themselves for this to work. This is a resubmission of https://codereview.chromium.org/233353003, which had to be reverted due to build breaks. See LGTM's there. BUG=371003 TBR=jam@chromium.org Review URL: https://codereview.chromium.org/280403002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@270049 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/prerender')
-rw-r--r--chrome/browser/prerender/external_prerender_handler_android.cc11
-rw-r--r--chrome/browser/prerender/external_prerender_handler_android.h3
-rw-r--r--chrome/browser/prerender/prerender_browsertest.cc135
-rw-r--r--chrome/browser/prerender/prerender_contents.cc27
-rw-r--r--chrome/browser/prerender/prerender_contents.h10
-rw-r--r--chrome/browser/prerender/prerender_cookie_store.cc241
-rw-r--r--chrome/browser/prerender/prerender_cookie_store.h164
-rw-r--r--chrome/browser/prerender/prerender_final_status.cc2
-rw-r--r--chrome/browser/prerender/prerender_final_status.h2
-rw-r--r--chrome/browser/prerender/prerender_manager.cc76
-rw-r--r--chrome/browser/prerender/prerender_manager.h37
-rw-r--r--chrome/browser/prerender/prerender_tracker.cc87
-rw-r--r--chrome/browser/prerender/prerender_tracker.h37
-rw-r--r--chrome/browser/prerender/prerender_unittest.cc12
14 files changed, 832 insertions, 12 deletions
diff --git a/chrome/browser/prerender/external_prerender_handler_android.cc b/chrome/browser/prerender/external_prerender_handler_android.cc
index 013873b..0be6463 100644
--- a/chrome/browser/prerender/external_prerender_handler_android.cc
+++ b/chrome/browser/prerender/external_prerender_handler_android.cc
@@ -89,6 +89,17 @@ static jboolean HasPrerenderedUrl(JNIEnv* env,
return prerender_manager->HasPrerenderedUrl(url, web_contents);
}
+static jboolean HasCookieStoreLoaded(JNIEnv* env,
+ jclass clazz,
+ jobject jprofile) {
+ Profile* profile = ProfileAndroid::FromProfileAndroid(jprofile);
+ prerender::PrerenderManager* prerender_manager =
+ prerender::PrerenderManagerFactory::GetForProfile(profile);
+ if (!prerender_manager)
+ return false;
+ return prerender_manager->cookie_store_loaded();
+}
+
ExternalPrerenderHandlerAndroid::ExternalPrerenderHandlerAndroid() {}
ExternalPrerenderHandlerAndroid::~ExternalPrerenderHandlerAndroid() {}
diff --git a/chrome/browser/prerender/external_prerender_handler_android.h b/chrome/browser/prerender/external_prerender_handler_android.h
index 111181c..6009ddf 100644
--- a/chrome/browser/prerender/external_prerender_handler_android.h
+++ b/chrome/browser/prerender/external_prerender_handler_android.h
@@ -45,6 +45,9 @@ class ExternalPrerenderHandlerAndroid {
GURL url,
content::WebContents* web_contents);
+ // Whether the cookie store associated with this profile has been loaded.
+ static bool HasCookieStoreLoaded(Profile* profile);
+
static bool RegisterExternalPrerenderHandlerAndroid(JNIEnv* env);
private:
diff --git a/chrome/browser/prerender/prerender_browsertest.cc b/chrome/browser/prerender/prerender_browsertest.cc
index bbfba0d..20b9df5 100644
--- a/chrome/browser/prerender/prerender_browsertest.cc
+++ b/chrome/browser/prerender/prerender_browsertest.cc
@@ -1124,6 +1124,12 @@ class PrerenderBrowserTest : virtual public InProcessBrowserTest {
return scoped_ptr<TestPrerender>(prerenders[0]);
}
+ // Navigates to a URL, unrelated to prerendering
+ void NavigateStraightToURL(const std::string dest_html_file) {
+ ui_test_utils::NavigateToURL(current_browser(),
+ test_server()->GetURL(dest_html_file));
+ }
+
void NavigateToDestURL() const {
NavigateToDestURLWithDisposition(CURRENT_TAB, true);
}
@@ -1484,6 +1490,22 @@ class PrerenderBrowserTest : virtual public InProcessBrowserTest {
base::ASCIIToUTF16(page_title));
}
+ void RunJSReturningString(const char* js, std::string* result) {
+ ASSERT_TRUE(
+ content::ExecuteScriptAndExtractString(
+ GetActiveWebContents(),
+ base::StringPrintf("window.domAutomationController.send(%s)",
+ js).c_str(),
+ result));
+ }
+
+ void RunJS(const char* js) {
+ ASSERT_TRUE(content::ExecuteScript(
+ GetActiveWebContents(),
+ base::StringPrintf("window.domAutomationController.send(%s)",
+ js).c_str()));
+ }
+
protected:
bool autostart_test_server_;
@@ -4153,6 +4175,103 @@ IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderPPLTNormalNavigation) {
histograms.ExpectTotalCount("Prerender.none_PerceivedPLTMatchedComplete", 0);
}
+IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest,
+ PrerenderCookieChangeConflictTest) {
+ NavigateStraightToURL(
+ "files/prerender/prerender_cookie.html?set=1&key=c&value=1");
+
+ GURL url = test_server()->GetURL(
+ "files/prerender/prerender_cookie.html?set=1&key=c&value=2");
+
+ scoped_ptr<TestPrerender> prerender =
+ ExpectPrerender(FINAL_STATUS_COOKIE_CONFLICT);
+ AddPrerender(url, 1);
+ prerender->WaitForStart();
+ prerender->WaitForLoads(1);
+ // Ensure that in the prerendered page, querying the cookie again
+ // via javascript yields the same value that was set during load.
+ EXPECT_TRUE(DidPrerenderPass(prerender->contents()->prerender_contents()));
+
+ // The prerender has loaded. Ensure that the change is not visible
+ // to visible tabs.
+ std::string value;
+ RunJSReturningString("GetCookie('c')", &value);
+ ASSERT_EQ(value, "1");
+
+ // Make a conflicting cookie change, which should cancel the prerender.
+ RunJS("SetCookie('c', '3')");
+ prerender->WaitForStop();
+}
+
+IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderCookieChangeUseTest) {
+ // Permit 2 concurrent prerenders.
+ GetPrerenderManager()->mutable_config().max_link_concurrency = 2;
+ GetPrerenderManager()->mutable_config().max_link_concurrency_per_launcher = 2;
+
+ // Go to a first URL setting the cookie to value "1".
+ NavigateStraightToURL(
+ "files/prerender/prerender_cookie.html?set=1&key=c&value=1");
+
+ // Prerender a URL setting the cookie to value "2".
+ GURL url = test_server()->GetURL(
+ "files/prerender/prerender_cookie.html?set=1&key=c&value=2");
+
+ scoped_ptr<TestPrerender> prerender1 = ExpectPrerender(FINAL_STATUS_USED);
+ AddPrerender(url, 1);
+ prerender1->WaitForStart();
+ prerender1->WaitForLoads(1);
+
+ // Launch a second prerender, setting the cookie to value "3".
+ scoped_ptr<TestPrerender> prerender2 =
+ ExpectPrerender(FINAL_STATUS_COOKIE_CONFLICT);
+ AddPrerender(test_server()->GetURL(
+ "files/prerender/prerender_cookie.html?set=1&key=c&value=3"), 1);
+ prerender2->WaitForStart();
+ prerender2->WaitForLoads(1);
+
+ // Both prerenders have loaded. Ensure that the visible tab is still
+ // unchanged and cannot see their changes.
+ // to visible tabs.
+ std::string value;
+ RunJSReturningString("GetCookie('c')", &value);
+ ASSERT_EQ(value, "1");
+
+ // Navigate to the prerendered URL. The first prerender should be swapped in,
+ // and the changes should now be visible. The second prerender should
+ // be cancelled due to the conflict.
+ ui_test_utils::NavigateToURLWithDisposition(
+ current_browser(),
+ url,
+ CURRENT_TAB,
+ ui_test_utils::BROWSER_TEST_NONE);
+ RunJSReturningString("GetCookie('c')", &value);
+ ASSERT_EQ(value, "2");
+ prerender2->WaitForStop();
+}
+
+IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest,
+ PrerenderCookieChangeConflictHTTPHeaderTest) {
+ NavigateStraightToURL(
+ "files/prerender/prerender_cookie.html?set=1&key=c&value=1");
+
+ GURL url = test_server()->GetURL("set-cookie?c=2");
+ scoped_ptr<TestPrerender> prerender =
+ ExpectPrerender(FINAL_STATUS_COOKIE_CONFLICT);
+ AddPrerender(url, 1);
+ prerender->WaitForStart();
+ prerender->WaitForLoads(1);
+
+ // The prerender has loaded. Ensure that the change is not visible
+ // to visible tabs.
+ std::string value;
+ RunJSReturningString("GetCookie('c')", &value);
+ ASSERT_EQ(value, "1");
+
+ // Make a conflicting cookie change, which should cancel the prerender.
+ RunJS("SetCookie('c', '3')");
+ prerender->WaitForStop();
+}
+
// Checks that a prerender which calls window.close() on itself is aborted.
IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderWindowClose) {
DisableLoadEventCheck();
@@ -4230,6 +4349,14 @@ class PrerenderOmniboxBrowserTest : public PrerenderBrowserTest {
// Checks that closing the omnibox popup cancels an omnibox prerender.
IN_PROC_BROWSER_TEST_F(PrerenderOmniboxBrowserTest, PrerenderOmniboxCancel) {
+ // Ensure the cookie store has been loaded.
+ if (!GetPrerenderManager()->cookie_store_loaded()) {
+ base::RunLoop loop;
+ GetPrerenderManager()->set_on_cookie_store_loaded_cb_for_testing(
+ loop.QuitClosure());
+ loop.Run();
+ }
+
// Fake an omnibox prerender.
scoped_ptr<TestPrerender> prerender = StartOmniboxPrerender(
test_server()->GetURL("files/empty.html"),
@@ -4247,6 +4374,14 @@ IN_PROC_BROWSER_TEST_F(PrerenderOmniboxBrowserTest, PrerenderOmniboxAbandon) {
GetPrerenderManager()->mutable_config().abandon_time_to_live =
base::TimeDelta::FromDays(999);
+ // Ensure the cookie store has been loaded.
+ if (!GetPrerenderManager()->cookie_store_loaded()) {
+ base::RunLoop loop;
+ GetPrerenderManager()->set_on_cookie_store_loaded_cb_for_testing(
+ loop.QuitClosure());
+ loop.Run();
+ }
+
// Enter a URL into the Omnibox.
OmniboxView* omnibox_view = GetOmniboxView();
omnibox_view->OnBeforePossibleChange();
diff --git a/chrome/browser/prerender/prerender_contents.cc b/chrome/browser/prerender/prerender_contents.cc
index 35f45a4..8e209e1 100644
--- a/chrome/browser/prerender/prerender_contents.cc
+++ b/chrome/browser/prerender/prerender_contents.cc
@@ -39,8 +39,10 @@
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/common/frame_navigate_params.h"
#include "content/public/common/page_transition_types.h"
+#include "net/url_request/url_request_context_getter.h"
#include "ui/gfx/rect.h"
+using content::BrowserThread;
using content::DownloadItem;
using content::OpenURLParams;
using content::RenderViewHost;
@@ -291,7 +293,8 @@ PrerenderContents* PrerenderContents::FromWebContents(
void PrerenderContents::StartPrerendering(
int creator_child_id,
const gfx::Size& size,
- SessionStorageNamespace* session_storage_namespace) {
+ SessionStorageNamespace* session_storage_namespace,
+ net::URLRequestContextGetter* request_context) {
DCHECK(profile_ != NULL);
DCHECK(!size.IsEmpty());
DCHECK(!prerendering_has_started_);
@@ -339,6 +342,24 @@ void PrerenderContents::StartPrerendering(
// the event of a mismatch.
alias_session_storage_namespace->AddTransactionLogProcessId(child_id_);
+ // Add the RenderProcessHost to the Prerender Manager.
+ prerender_manager()->AddPrerenderProcessHost(
+ GetRenderViewHost()->GetProcess());
+
+ // In the prerender tracker, create a Prerender Cookie Store to keep track of
+ // cookie changes performed by the prerender. Once the prerender is shown,
+ // the cookie changes will be committed to the actual cookie store,
+ // otherwise, they will be discarded.
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&PrerenderTracker::AddPrerenderCookieStoreOnIOThread,
+ base::Unretained(prerender_manager()->prerender_tracker()),
+ GetRenderViewHost()->GetProcess()->GetID(),
+ make_scoped_refptr(request_context),
+ base::Bind(&PrerenderContents::Destroy,
+ AsWeakPtr(),
+ FINAL_STATUS_COOKIE_CONFLICT)));
+
NotifyPrerenderStart();
// Close ourselves when the application is shutting down.
@@ -796,8 +817,8 @@ void PrerenderContents::PrepareForUse() {
NotifyPrerenderStop();
- content::BrowserThread::PostTask(
- content::BrowserThread::IO,
+ BrowserThread::PostTask(
+ BrowserThread::IO,
FROM_HERE,
base::Bind(&ResumeThrottles, resource_throttles_));
resource_throttles_.clear();
diff --git a/chrome/browser/prerender/prerender_contents.h b/chrome/browser/prerender/prerender_contents.h
index d60602f..3b8ba1d 100644
--- a/chrome/browser/prerender/prerender_contents.h
+++ b/chrome/browser/prerender/prerender_contents.h
@@ -39,6 +39,10 @@ namespace history {
struct HistoryAddPageArgs;
}
+namespace net {
+class URLRequestContextGetter;
+}
+
namespace prerender {
class PrerenderHandle;
@@ -46,7 +50,8 @@ class PrerenderManager;
class PrerenderResourceThrottle;
class PrerenderContents : public content::NotificationObserver,
- public content::WebContentsObserver {
+ public content::WebContentsObserver,
+ public base::SupportsWeakPtr<PrerenderContents> {
public:
// PrerenderContents::Create uses the currently registered Factory to create
// the PrerenderContents. Factory is intended for testing.
@@ -151,7 +156,8 @@ class PrerenderContents : public content::NotificationObserver,
virtual void StartPrerendering(
int creator_child_id,
const gfx::Size& size,
- content::SessionStorageNamespace* session_storage_namespace);
+ content::SessionStorageNamespace* session_storage_namespace,
+ net::URLRequestContextGetter* request_context);
// Verifies that the prerendering is not using too many resources, and kills
// it if not.
diff --git a/chrome/browser/prerender/prerender_cookie_store.cc b/chrome/browser/prerender/prerender_cookie_store.cc
new file mode 100644
index 0000000..078c941
--- /dev/null
+++ b/chrome/browser/prerender/prerender_cookie_store.cc
@@ -0,0 +1,241 @@
+// Copyright 2014 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_cookie_store.h"
+
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "content/public/browser/browser_thread.h"
+
+using content::BrowserThread;
+
+namespace prerender {
+
+PrerenderCookieStore::PrerenderCookieStore(
+ scoped_refptr<net::CookieMonster> default_cookie_monster,
+ const base::Closure& cookie_conflict_cb)
+ : in_forwarding_mode_(false),
+ default_cookie_monster_(default_cookie_monster),
+ changes_cookie_monster_(new net::CookieMonster(NULL, NULL)),
+ cookie_conflict_cb_(cookie_conflict_cb),
+ cookie_conflict_(false) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK(default_cookie_monster_ != NULL);
+ DCHECK(default_cookie_monster_->loaded());
+}
+
+PrerenderCookieStore::~PrerenderCookieStore() {
+}
+
+void PrerenderCookieStore::SetCookieWithOptionsAsync(
+ const GURL& url,
+ const std::string& cookie_line,
+ const net::CookieOptions& options,
+ const SetCookiesCallback& callback) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ CookieOperation op;
+ op.op = COOKIE_OP_SET_COOKIE_WITH_OPTIONS_ASYNC;
+ op.url = url;
+ op.cookie_line = cookie_line;
+ op.options = options;
+
+ GetCookieStoreForCookieOpAndLog(op)->
+ SetCookieWithOptionsAsync(url, cookie_line, options, callback);
+}
+
+void PrerenderCookieStore::GetCookiesWithOptionsAsync(
+ const GURL& url,
+ const net::CookieOptions& options,
+ const GetCookiesCallback& callback) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ CookieOperation op;
+ op.op = COOKIE_OP_GET_COOKIES_WITH_OPTIONS_ASYNC;
+ op.url = url;
+ op.options = options;
+
+ GetCookieStoreForCookieOpAndLog(op)->
+ GetCookiesWithOptionsAsync(url, options, callback);
+}
+
+void PrerenderCookieStore::GetAllCookiesForURLAsync(
+ const GURL& url,
+ const GetCookieListCallback& callback) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ CookieOperation op;
+ op.op = COOKIE_OP_GET_ALL_COOKIES_FOR_URL_ASYNC;
+ op.url = url;
+
+ GetCookieStoreForCookieOpAndLog(op)->GetAllCookiesForURLAsync(url, callback);
+}
+
+
+void PrerenderCookieStore::DeleteCookieAsync(const GURL& url,
+ const std::string& cookie_name,
+ const base::Closure& callback) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ CookieOperation op;
+ op.op = COOKIE_OP_DELETE_COOKIE_ASYNC;
+ op.url = url;
+ op.cookie_name = cookie_name;
+
+ GetCookieStoreForCookieOpAndLog(op)->DeleteCookieAsync(url, cookie_name,
+ callback);
+}
+
+void PrerenderCookieStore::DeleteAllCreatedBetweenAsync(
+ const base::Time& delete_begin,
+ const base::Time& delete_end,
+ const DeleteCallback& callback) {
+ NOTREACHED();
+}
+
+void PrerenderCookieStore::DeleteAllCreatedBetweenForHostAsync(
+ const base::Time delete_begin,
+ const base::Time delete_end,
+ const GURL& url,
+ const DeleteCallback& callback) {
+ NOTREACHED();
+}
+
+void PrerenderCookieStore::DeleteSessionCookiesAsync(const DeleteCallback&) {
+ NOTREACHED();
+}
+
+net::CookieMonster* PrerenderCookieStore::GetCookieMonster() {
+ NOTREACHED();
+ return NULL;
+}
+
+net::CookieStore* PrerenderCookieStore::GetCookieStoreForCookieOpAndLog(
+ const CookieOperation& op) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ std::string key = default_cookie_monster_->GetKey(op.url.host());
+ bool is_read_only = (op.op == COOKIE_OP_GET_COOKIES_WITH_OPTIONS_ASYNC ||
+ op.op == COOKIE_OP_GET_ALL_COOKIES_FOR_URL_ASYNC);
+
+ if (in_forwarding_mode_)
+ return default_cookie_monster_;
+
+ DCHECK(changes_cookie_monster_ != NULL);
+
+ cookie_ops_.push_back(op);
+
+ bool key_copied = ContainsKey(copied_keys_, key);
+
+ if (key_copied)
+ return changes_cookie_monster_;
+
+ if (is_read_only) {
+ // Insert this key into the set of read keys, if it doesn't exist yet.
+ if (!ContainsKey(read_keys_, key))
+ read_keys_.insert(key);
+ return default_cookie_monster_;
+ }
+
+ // If this method hasn't returned yet, the key has not been copied yet,
+ // and we must copy it due to the requested write operation.
+
+ bool copy_success = default_cookie_monster_->
+ CopyCookiesForKeyToOtherCookieMonster(key, changes_cookie_monster_);
+
+ // The copy must succeed.
+ DCHECK(copy_success);
+
+ copied_keys_.insert(key);
+
+ return changes_cookie_monster_;
+}
+
+void PrerenderCookieStore::ApplyChanges(std::vector<GURL>* cookie_change_urls) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ if (in_forwarding_mode_)
+ return;
+
+ // Apply all changes to the underlying cookie store.
+ for (std::vector<CookieOperation>::const_iterator it = cookie_ops_.begin();
+ it != cookie_ops_.end();
+ ++it) {
+ switch (it->op) {
+ case COOKIE_OP_SET_COOKIE_WITH_OPTIONS_ASYNC:
+ cookie_change_urls->push_back(it->url);
+ default_cookie_monster_->SetCookieWithOptionsAsync(
+ it->url, it->cookie_line, it->options, SetCookiesCallback());
+ break;
+ case COOKIE_OP_GET_COOKIES_WITH_OPTIONS_ASYNC:
+ default_cookie_monster_->GetCookiesWithOptionsAsync(
+ it->url, it->options, GetCookiesCallback());
+ break;
+ case COOKIE_OP_GET_ALL_COOKIES_FOR_URL_ASYNC:
+ default_cookie_monster_->GetAllCookiesForURLAsync(
+ it->url, GetCookieListCallback());
+ break;
+ case COOKIE_OP_DELETE_COOKIE_ASYNC:
+ cookie_change_urls->push_back(it->url);
+ default_cookie_monster_->DeleteCookieAsync(
+ it->url, it->cookie_name, base::Closure());
+ break;
+ case COOKIE_OP_MAX:
+ NOTREACHED();
+ }
+ }
+
+ in_forwarding_mode_ = true;
+ copied_keys_.clear();
+ cookie_ops_.clear();
+ changes_cookie_monster_ = NULL;
+}
+
+void PrerenderCookieStore::OnCookieChangedForURL(
+ net::CookieMonster* cookie_monster,
+ const GURL& url) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ // If the cookie was changed in a different cookie monster than the one
+ // being decorated, there is nothing to do).
+ if (cookie_monster != default_cookie_monster_)
+ return;
+
+ if (in_forwarding_mode_)
+ return;
+
+ // If we have encountered a conflict before, it has already been recorded
+ // and the cb has been issued, so nothing to do.
+ if (cookie_conflict_)
+ return;
+
+ std::string key = default_cookie_monster_->GetKey(url.host());
+
+ // If the key for the cookie which was modified was neither read nor written,
+ // nothing to do.
+ if ((!ContainsKey(read_keys_, key)) && (!ContainsKey(copied_keys_, key)))
+ return;
+
+ // There was a conflict in cookies. Call the conflict callback, which should
+ // cancel the prerender if necessary (i.e. if it hasn't already been
+ // cancelled for some other reason).
+ // Notice that there is a race here with swapping in the prerender, but this
+ // is the same issue that occurs when two tabs modify cookies for the
+ // same domain concurrently. Therefore, there is no need to do anything
+ // special to prevent this race condition.
+ cookie_conflict_ = true;
+ if (!cookie_conflict_cb_.is_null()) {
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ cookie_conflict_cb_);
+ }
+}
+
+PrerenderCookieStore::CookieOperation::CookieOperation() {
+}
+
+PrerenderCookieStore::CookieOperation::~CookieOperation() {
+}
+
+} // namespace prerender
diff --git a/chrome/browser/prerender/prerender_cookie_store.h b/chrome/browser/prerender/prerender_cookie_store.h
new file mode 100644
index 0000000..b42ef45
--- /dev/null
+++ b/chrome/browser/prerender/prerender_cookie_store.h
@@ -0,0 +1,164 @@
+// Copyright 2014 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.
+
+#ifndef CHROME_BROWSER_PRERENDER_PRERENDER_COOKIE_STORE_H_
+#define CHROME_BROWSER_PRERENDER_PRERENDER_COOKIE_STORE_H_
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "net/cookies/cookie_monster.h"
+#include "net/cookies/cookie_store.h"
+#include "url/gurl.h"
+
+namespace prerender {
+
+// A cookie store which keeps track of provisional changes to the cookie monster
+// of an underlying request context (called the default cookie monster).
+// Initially, it will proxy read requests to the default cookie monster, and
+// copy on write keys that are being modified into a private cookie monster.
+// Reads for these will then happen from the private cookie monster.
+// Should keys be modified in the default cookie store, the corresponding
+// prerender should be aborted.
+// This class also keeps a log of all cookie transactions. Once ApplyChanges
+// is called, the changes will be applied to the default cookie monster,
+// and any future requests to this object will simply be forwarded to the
+// default cookie monster. After ApplyChanges is called, the prerender tracker,
+// which "owns" the PrerenderCookieStore reference, will remove its entry for
+// the PrerenderCookieStore. Therefore, after ApplyChanges is called, the
+// object will only stick around (and exhibit forwarding mode) as long as
+// eg pending requests hold on to its reference.
+class PrerenderCookieStore : public net::CookieStore {
+ public:
+ // Creates a PrerenderCookieStore using the default cookie monster provided
+ // by the URLRequestContext. The underlying cookie store must be loaded,
+ // ie it's call to loaded() must return true.
+ // Otherwise, copying cookie data between the prerender cookie store
+ // (used to only commit cookie changes once a prerender is shown) would
+ // not work synchronously, which would complicate the code.
+ // |cookie_conflict_cb| will be called when a cookie conflict is detected.
+ // The callback will be run on the UI thread.
+ PrerenderCookieStore(scoped_refptr<net::CookieMonster> default_cookie_store_,
+ const base::Closure& cookie_conflict_cb);
+
+ // CookieStore implementation
+ virtual void SetCookieWithOptionsAsync(
+ const GURL& url,
+ const std::string& cookie_line,
+ const net::CookieOptions& options,
+ const SetCookiesCallback& callback) OVERRIDE;
+
+ virtual void GetCookiesWithOptionsAsync(
+ const GURL& url,
+ const net::CookieOptions& options,
+ const GetCookiesCallback& callback) OVERRIDE;
+
+ virtual void GetAllCookiesForURLAsync(
+ const GURL& url,
+ const GetCookieListCallback& callback) OVERRIDE;
+
+ virtual void DeleteCookieAsync(const GURL& url,
+ const std::string& cookie_name,
+ const base::Closure& callback) OVERRIDE;
+
+ // All the following methods should not be used in the scenarios where
+ // a PrerenderCookieStore is used. This will be checked via NOTREACHED().
+ // Should PrerenderCookieStore used in contexts requiring these, they will
+ // need to be implemented first. They are only intended to be called on the
+ // IO thread.
+
+ virtual void DeleteAllCreatedBetweenAsync(
+ const base::Time& delete_begin,
+ const base::Time& delete_end,
+ const DeleteCallback& callback) OVERRIDE;
+
+ virtual void DeleteAllCreatedBetweenForHostAsync(
+ const base::Time delete_begin,
+ const base::Time delete_end,
+ const GURL& url,
+ const DeleteCallback& callback) OVERRIDE;
+
+ virtual void DeleteSessionCookiesAsync(const DeleteCallback&) OVERRIDE;
+
+ virtual net::CookieMonster* GetCookieMonster() OVERRIDE;
+
+ // Commits the changes made to the underlying cookie store, and switches
+ // into forwarding mode. To be called on the IO thread.
+ // |cookie_change_urls| will be populated with all URLs for which cookies
+ // were updated.
+ void ApplyChanges(std::vector<GURL>* cookie_change_urls);
+
+ // Called when a cookie for a URL is changed in the underlying default cookie
+ // store. To be called on the IO thread. If the key corresponding to the URL
+ // was copied or read, the prerender will be cancelled.
+ void OnCookieChangedForURL(net::CookieMonster* cookie_monster,
+ const GURL& url);
+
+ net::CookieMonster* default_cookie_monster() {
+ return default_cookie_monster_;
+ }
+
+ private:
+ enum CookieOperationType {
+ COOKIE_OP_SET_COOKIE_WITH_OPTIONS_ASYNC,
+ COOKIE_OP_GET_COOKIES_WITH_OPTIONS_ASYNC,
+ COOKIE_OP_GET_ALL_COOKIES_FOR_URL_ASYNC,
+ COOKIE_OP_DELETE_COOKIE_ASYNC,
+ COOKIE_OP_MAX
+ };
+
+ struct CookieOperation {
+ CookieOperationType op;
+ GURL url;
+ net::CookieOptions options;
+ std::string cookie_line;
+ std::string cookie_name;
+ CookieOperation();
+ ~CookieOperation();
+ };
+
+ virtual ~PrerenderCookieStore();
+
+ // Gets the appropriate cookie store for the operation provided, and pushes
+ // it back on the log of cookie operations performed.
+ net::CookieStore* GetCookieStoreForCookieOpAndLog(const CookieOperation& op);
+
+ // Indicates whether the changes have already been applied (ie the prerender
+ // has been shown), and we are merely in forwarding mode;
+ bool in_forwarding_mode_;
+
+ // The default cookie monster.
+ scoped_refptr<net::CookieMonster> default_cookie_monster_;
+
+ // A cookie monster storing changes made by the prerender.
+ // Entire keys are copied from default_cookie_monster_ on change, and then
+ // modified.
+ scoped_refptr<net::CookieMonster> changes_cookie_monster_;
+
+ // Log of cookie operations performed
+ std::vector<CookieOperation> cookie_ops_;
+
+ // The keys which have been copied on write to |changes_cookie_monster_|.
+ std::set<std::string> copied_keys_;
+
+ // Keys which have been read (but not necessarily been modified).
+ std::set<std::string> read_keys_;
+
+ // Callback when a cookie conflict was detected
+ base::Closure cookie_conflict_cb_;
+
+ // Indicates whether a cookie conflict has been detected yet.
+ bool cookie_conflict_;
+
+ DISALLOW_COPY_AND_ASSIGN(PrerenderCookieStore);
+};
+
+} // namespace prerender
+
+#endif // CHROME_BROWSER_PRERENDER_PRERENDER_COOKIE_STORE_H_
diff --git a/chrome/browser/prerender/prerender_final_status.cc b/chrome/browser/prerender/prerender_final_status.cc
index ac0526d..adeaf49 100644
--- a/chrome/browser/prerender/prerender_final_status.cc
+++ b/chrome/browser/prerender/prerender_final_status.cc
@@ -59,6 +59,8 @@ const char* kFinalStatusNames[] = {
"Bad Deferred Redirect",
"Navigation Uncommitted",
"New Navigation Entry",
+ "Cookie Store Not Loaded",
+ "Cookie Conflict",
"Max",
};
COMPILE_ASSERT(arraysize(kFinalStatusNames) == FINAL_STATUS_MAX + 1,
diff --git a/chrome/browser/prerender/prerender_final_status.h b/chrome/browser/prerender/prerender_final_status.h
index 8551c10..412be21 100644
--- a/chrome/browser/prerender/prerender_final_status.h
+++ b/chrome/browser/prerender/prerender_final_status.h
@@ -60,6 +60,8 @@ enum FinalStatus {
FINAL_STATUS_BAD_DEFERRED_REDIRECT = 45,
FINAL_STATUS_NAVIGATION_UNCOMMITTED = 46,
FINAL_STATUS_NEW_NAVIGATION_ENTRY = 47,
+ FINAL_STATUS_COOKIE_STORE_NOT_LOADED = 48,
+ FINAL_STATUS_COOKIE_CONFLICT = 49,
FINAL_STATUS_MAX,
};
diff --git a/chrome/browser/prerender/prerender_manager.cc b/chrome/browser/prerender/prerender_manager.cc
index 4f0c083..141afe7 100644
--- a/chrome/browser/prerender/prerender_manager.cc
+++ b/chrome/browser/prerender/prerender_manager.cc
@@ -58,6 +58,7 @@
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/session_storage_namespace.h"
+#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/common/url_constants.h"
@@ -245,7 +246,8 @@ PrerenderManager::PrerenderManager(Profile* profile,
prerender_history_(new PrerenderHistory(kHistoryLength)),
histograms_(new PrerenderHistograms()),
profile_network_bytes_(0),
- last_recorded_profile_network_bytes_(0) {
+ last_recorded_profile_network_bytes_(0),
+ cookie_store_loaded_(false) {
// There are some assumptions that the PrerenderManager is on the UI thread.
// Any other checks simply make sure that the PrerenderManager is accessed on
// the same thread that it was created on.
@@ -303,6 +305,13 @@ PrerenderManager::~PrerenderManager() {
// emptied these vectors already.
DCHECK(active_prerenders_.empty());
DCHECK(to_delete_prerenders_.empty());
+
+ for (PrerenderProcessSet::const_iterator it =
+ prerender_process_hosts_.begin();
+ it != prerender_process_hosts_.end();
+ ++it) {
+ (*it)->RemoveObserver(this);
+ }
}
void PrerenderManager::Shutdown() {
@@ -577,6 +586,14 @@ WebContents* PrerenderManager::SwapInternal(
}
// At this point, we've determined that we will use the prerender.
+ content::RenderProcessHost* process_host =
+ prerender_data->contents()->GetRenderViewHost()->GetProcess();
+ prerender_process_hosts_.erase(process_host);
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&PrerenderTracker::RemovePrerenderCookieStoreOnIOThread,
+ base::Unretained(prerender_tracker()), process_host->GetID(),
+ true));
if (!prerender_data->contents()->load_start_time().is_null()) {
histograms_->RecordTimeUntilUsed(
prerender_data->contents()->origin(),
@@ -748,7 +765,7 @@ const char* PrerenderManager::GetModeString() {
default:
NOTREACHED() << "Invalid PrerenderManager mode.";
break;
- };
+ }
return "";
}
@@ -1216,6 +1233,12 @@ void PrerenderManager::SourceNavigatedAway(PrerenderData* prerender_data) {
SortActivePrerenders();
}
+net::URLRequestContextGetter* PrerenderManager::GetURLRequestContext() {
+ return content::BrowserContext::GetDefaultStoragePartition(profile_)->
+ GetURLRequestContext();
+}
+
+
// private
PrerenderHandle* PrerenderManager::AddPrerender(
Origin origin,
@@ -1283,6 +1306,14 @@ PrerenderHandle* PrerenderManager::AddPrerender(
return NULL;
}
+ if (!cookie_store_loaded()) {
+ // Only prerender if the cookie store for this profile has been loaded.
+ // This is required by PrerenderCookieMonster.
+ RecordFinalStatusWithoutCreatingPrerenderContents(
+ url, origin, experiment, FINAL_STATUS_COOKIE_STORE_NOT_LOADED);
+ return NULL;
+ }
+
PrerenderContents* prerender_contents = CreatePrerenderContents(
url, referrer, origin, experiment);
DCHECK(prerender_contents);
@@ -1307,11 +1338,16 @@ PrerenderHandle* PrerenderManager::AddPrerender(
gfx::Size contents_size =
size.IsEmpty() ? config_.default_tab_bounds.size() : size;
+ net::URLRequestContextGetter* request_context = GetURLRequestContext();
+
prerender_contents->StartPrerendering(process_id, contents_size,
- session_storage_namespace);
+ session_storage_namespace,
+ request_context);
DCHECK(IsControlGroup(experiment) ||
- prerender_contents->prerendering_has_started());
+ prerender_contents->prerendering_has_started() ||
+ (origin == ORIGIN_LOCAL_PREDICTOR &&
+ IsLocalPredictorPrerenderAlwaysControlEnabled()));
if (GetMode() == PRERENDER_MODE_EXPERIMENT_MULTI_PRERENDER_GROUP)
histograms_->RecordConcurrency(active_prerenders_.size());
@@ -1831,4 +1867,36 @@ void PrerenderManager::AddProfileNetworkBytesIfEnabled(int64 bytes) {
profile_network_bytes_ += bytes;
}
+void PrerenderManager::OnCookieStoreLoaded() {
+ cookie_store_loaded_ = true;
+ if (!on_cookie_store_loaded_cb_for_testing_.is_null())
+ on_cookie_store_loaded_cb_for_testing_.Run();
+}
+
+void PrerenderManager::AddPrerenderProcessHost(
+ content::RenderProcessHost* process_host) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(prerender_process_hosts_.find(process_host) ==
+ prerender_process_hosts_.end());
+ prerender_process_hosts_.insert(process_host);
+ process_host->AddObserver(this);
+}
+
+bool PrerenderManager::IsProcessPrerendering(
+ content::RenderProcessHost* process_host) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ return (prerender_process_hosts_.find(process_host) !=
+ prerender_process_hosts_.end());
+}
+
+void PrerenderManager::RenderProcessHostDestroyed(
+ content::RenderProcessHost* host) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ prerender_process_hosts_.erase(host);
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&PrerenderTracker::RemovePrerenderCookieStoreOnIOThread,
+ base::Unretained(prerender_tracker()), host->GetID(), false));
+}
+
} // namespace prerender
diff --git a/chrome/browser/prerender/prerender_manager.h b/chrome/browser/prerender/prerender_manager.h
index aad510e..95d78d5 100644
--- a/chrome/browser/prerender/prerender_manager.h
+++ b/chrome/browser/prerender/prerender_manager.h
@@ -31,6 +31,7 @@
#include "components/keyed_service/core/keyed_service.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
+#include "content/public/browser/render_process_host_observer.h"
#include "content/public/browser/session_storage_namespace.h"
#include "content/public/browser/web_contents_observer.h"
#include "net/cookies/canonical_cookie.h"
@@ -74,6 +75,7 @@ class PrerenderLocalPredictor;
class PrerenderManager : public base::SupportsWeakPtr<PrerenderManager>,
public base::NonThreadSafe,
public content::NotificationObserver,
+ public content::RenderProcessHostObserver,
public KeyedService,
public MediaCaptureDevicesDispatcher::Observer {
public:
@@ -295,6 +297,8 @@ class PrerenderManager : public base::SupportsWeakPtr<PrerenderManager>,
PrerenderTracker* prerender_tracker() { return prerender_tracker_; }
+ bool cookie_store_loaded() { return cookie_store_loaded_; }
+
// Adds a condition. This is owned by the PrerenderManager.
void AddCondition(const PrerenderCondition* condition);
@@ -360,6 +364,25 @@ class PrerenderManager : public base::SupportsWeakPtr<PrerenderManager>,
// profile if prerendering is currently enabled.
void AddProfileNetworkBytesIfEnabled(int64 bytes);
+ // Registers a new ProcessHost performing a prerender. Called by
+ // PrerenderContents.
+ void AddPrerenderProcessHost(content::RenderProcessHost* process_host);
+
+ bool IsProcessPrerendering(content::RenderProcessHost* process_host);
+
+ // content::RenderProcessHostObserver implementation.
+ virtual void RenderProcessHostDestroyed(
+ content::RenderProcessHost* host) OVERRIDE;
+
+ // To be called once the cookie store for this profile has been loaded.
+ void OnCookieStoreLoaded();
+
+ // For testing purposes. Issues a callback once the cookie store has been
+ // loaded.
+ void set_on_cookie_store_loaded_cb_for_testing(base::Closure cb) {
+ on_cookie_store_loaded_cb_for_testing_ = cb;
+ }
+
protected:
class PendingSwap;
class PrerenderData : public base::SupportsWeakPtr<PrerenderData> {
@@ -510,6 +533,11 @@ class PrerenderManager : public base::SupportsWeakPtr<PrerenderManager>,
// shorten the TTL of the prerendered page.
void SourceNavigatedAway(PrerenderData* prerender_data);
+ // Gets the request context for the profile.
+ // For unit tests, this will be overriden to return NULL, since it is not
+ // needed.
+ virtual net::URLRequestContextGetter* GetURLRequestContext();
+
private:
friend class ::InstantSearchPrerendererTest;
friend class PrerenderBrowserTest;
@@ -720,6 +748,15 @@ class PrerenderManager : public base::SupportsWeakPtr<PrerenderManager>,
// The value of profile_network_bytes_ that was last recorded.
int64 last_recorded_profile_network_bytes_;
+ // Set of process hosts being prerendered.
+ typedef std::set<content::RenderProcessHost*> PrerenderProcessSet;
+ PrerenderProcessSet prerender_process_hosts_;
+
+ // Indicates whether the cookie store for this profile has fully loaded yet.
+ bool cookie_store_loaded_;
+
+ base::Closure on_cookie_store_loaded_cb_for_testing_;
+
DISALLOW_COPY_AND_ASSIGN(PrerenderManager);
};
diff --git a/chrome/browser/prerender/prerender_tracker.cc b/chrome/browser/prerender/prerender_tracker.cc
index b44c8d3..cabb35b 100644
--- a/chrome/browser/prerender/prerender_tracker.cc
+++ b/chrome/browser/prerender/prerender_tracker.cc
@@ -8,6 +8,9 @@
#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;
@@ -103,4 +106,88 @@ PrerenderTracker::PendingSwapThrottleData::PendingSwapThrottleData(
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
diff --git a/chrome/browser/prerender/prerender_tracker.h b/chrome/browser/prerender/prerender_tracker.h
index f9dd17b..6020658 100644
--- a/chrome/browser/prerender/prerender_tracker.h
+++ b/chrome/browser/prerender/prerender_tracker.h
@@ -6,16 +6,26 @@
#define CHROME_BROWSER_PRERENDER_PRERENDER_TRACKER_H_
#include <map>
+#include <set>
#include <utility>
+#include "base/containers/hash_tables.h"
+#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
+#include "base/synchronization/lock.h"
+#include "chrome/browser/prerender/prerender_cookie_store.h"
+#include "content/public/browser/render_process_host_observer.h"
#include "url/gurl.h"
+namespace net {
+class URLRequestContextGetter;
+}
+
namespace prerender {
class PrerenderPendingSwapThrottle;
-// Global object for maintaining prerender state on the IO thread.
+// Global object for maintaining various prerender state on the IO thread.
class PrerenderTracker {
public:
typedef std::pair<int, int> ChildRouteIdPair;
@@ -46,6 +56,25 @@ class PrerenderTracker {
const ChildRouteIdPair& render_frame_route_id_pair,
bool swap_successful);
+ // Gets the Prerender Cookie Store for a specific render process, if it
+ // is a prerender. Only to be called from the IO thread.
+ scoped_refptr<PrerenderCookieStore> GetPrerenderCookieStoreForRenderProcess(
+ int process_id);
+
+ // Called when a given render process has changed a cookie for |url|,
+ // in |cookie_monster|.
+ // Only to be called from the IO thread.
+ void OnCookieChangedForURL(int process_id,
+ net::CookieMonster* cookie_monster,
+ const GURL& url);
+
+ void AddPrerenderCookieStoreOnIOThread(
+ int process_id,
+ scoped_refptr<net::URLRequestContextGetter> request_context,
+ const base::Closure& cookie_conflict_cb);
+
+ void RemovePrerenderCookieStoreOnIOThread(int process_id, bool was_swapped);
+
private:
// Add/remove prerenders pending swap on the IO Thread.
void AddPrerenderPendingSwapOnIOThread(
@@ -68,6 +97,12 @@ class PrerenderTracker {
PendingSwapThrottleMap;
PendingSwapThrottleMap pending_swap_throttle_map_;
+ // Map of prerendering render process ids to PrerenderCookieStore used for
+ // the prerender. Only to be used on the IO thread.
+ typedef base::hash_map<int, scoped_refptr<PrerenderCookieStore> >
+ PrerenderCookieStoreMap;
+ PrerenderCookieStoreMap prerender_cookie_store_map_;
+
DISALLOW_COPY_AND_ASSIGN(PrerenderTracker);
};
diff --git a/chrome/browser/prerender/prerender_unittest.cc b/chrome/browser/prerender/prerender_unittest.cc
index 1af24ea..6a8a16d 100644
--- a/chrome/browser/prerender/prerender_unittest.cc
+++ b/chrome/browser/prerender/prerender_unittest.cc
@@ -52,7 +52,8 @@ class DummyPrerenderContents : public PrerenderContents {
virtual void StartPrerendering(
int ALLOW_UNUSED creator_child_id,
const gfx::Size& ALLOW_UNUSED size,
- content::SessionStorageNamespace* ALLOW_UNUSED session_storage_namespace)
+ content::SessionStorageNamespace* ALLOW_UNUSED session_storage_namespace,
+ net::URLRequestContextGetter* ALLOW_UNUSED request_context)
OVERRIDE;
virtual bool GetChildId(int* child_id) const OVERRIDE {
@@ -101,6 +102,7 @@ class UnitTestPrerenderManager : public PrerenderManager {
time_ticks_(TimeTicks::Now()),
prerender_tracker_(prerender_tracker) {
set_rate_limit_enabled(false);
+ OnCookieStoreLoaded();
}
virtual ~UnitTestPrerenderManager() {
@@ -229,6 +231,11 @@ class UnitTestPrerenderManager : public PrerenderManager {
prerender_contents_map_.erase(std::make_pair(child_id, route_id));
}
+ protected:
+ virtual net::URLRequestContextGetter* GetURLRequestContext() OVERRIDE {
+ return NULL;
+ }
+
private:
void SetNextPrerenderContents(DummyPrerenderContents* prerender_contents) {
CHECK(!next_prerender_contents_.get());
@@ -296,7 +303,8 @@ DummyPrerenderContents::~DummyPrerenderContents() {
void DummyPrerenderContents::StartPrerendering(
int ALLOW_UNUSED creator_child_id,
const gfx::Size& ALLOW_UNUSED size,
- content::SessionStorageNamespace* ALLOW_UNUSED session_storage_namespace) {
+ content::SessionStorageNamespace* ALLOW_UNUSED session_storage_namespace,
+ net::URLRequestContextGetter* ALLOW_UNUSED request_context) {
// In the base PrerenderContents implementation, StartPrerendering will
// be called even when the PrerenderManager is part of the control group,
// but it will early exit before actually creating a new RenderView if