summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/automation/automation_util.cc248
-rw-r--r--chrome/browser/automation/automation_util.h72
-rw-r--r--chrome/browser/automation/testing_automation_provider.cc195
-rw-r--r--chrome/browser/chrome_content_browser_client.cc5
-rw-r--r--chrome/browser/extensions/extension_host.cc6
-rw-r--r--chrome/browser/extensions/extension_service.cc18
-rw-r--r--chrome/browser/extensions/extension_service.h3
-rw-r--r--chrome/browser/extensions/isolated_app_apitest.cc141
-rw-r--r--chrome/browser/net/chrome_url_request_context.cc69
-rw-r--r--chrome/browser/net/chrome_url_request_context.h27
-rw-r--r--chrome/browser/net/sqlite_persistent_cookie_store.cc12
-rw-r--r--chrome/browser/notifications/balloon_host.cc7
-rw-r--r--chrome/browser/profiles/off_the_record_profile_io_data.cc78
-rw-r--r--chrome/browser/profiles/off_the_record_profile_io_data.h23
-rw-r--r--chrome/browser/profiles/profile.cc17
-rw-r--r--chrome/browser/profiles/profile.h13
-rw-r--r--chrome/browser/profiles/profile_impl.cc21
-rw-r--r--chrome/browser/profiles/profile_impl.h4
-rw-r--r--chrome/browser/profiles/profile_impl_io_data.cc123
-rw-r--r--chrome/browser/profiles/profile_impl_io_data.h29
-rw-r--r--chrome/browser/profiles/profile_io_data.cc11
-rw-r--r--chrome/browser/profiles/profile_io_data.h19
-rw-r--r--chrome/browser/renderer_host/browser_render_process_host.cc10
-rw-r--r--chrome/browser/renderer_host/browser_render_process_host.h12
-rw-r--r--chrome/browser/sidebar/sidebar_container.cc7
-rw-r--r--chrome/chrome_browser.gypi2
-rw-r--r--chrome/chrome_tests.gypi1
-rw-r--r--chrome/common/chrome_constants.cc1
-rw-r--r--chrome/common/chrome_constants.h1
-rw-r--r--chrome/common/chrome_switches.cc4
-rw-r--r--chrome/common/chrome_switches.h1
-rw-r--r--chrome/common/extensions/extension.cc41
-rw-r--r--chrome/common/extensions/extension.h5
-rw-r--r--chrome/common/extensions/extension_constants.cc6
-rw-r--r--chrome/common/extensions/extension_constants.h4
-rw-r--r--chrome/common/extensions/extension_manifests_unittest.cc15
-rw-r--r--chrome/test/data/extensions/api_test/app_process/manifest.json2
-rw-r--r--chrome/test/data/extensions/api_test/isolated_apps/app1/main.html15
-rw-r--r--chrome/test/data/extensions/api_test/isolated_apps/app1/manifest.json16
-rw-r--r--chrome/test/data/extensions/api_test/isolated_apps/app2/main.html12
-rw-r--r--chrome/test/data/extensions/api_test/isolated_apps/app2/manifest.json16
-rw-r--r--chrome/test/data/extensions/api_test/isolated_apps/non_app/main.html12
-rw-r--r--chrome/test/data/extensions/api_test/isolated_apps/non_app/subframe.html12
-rw-r--r--chrome/test/data/extensions/manifest_tests/isolated_app_valid.json15
-rw-r--r--chrome/test/testing_profile.cc15
-rw-r--r--chrome/test/testing_profile.h4
-rw-r--r--content/browser/renderer_host/render_message_filter.cc3
-rw-r--r--content/browser/renderer_host/render_message_filter.h1
-rw-r--r--net/url_request/url_request_context.cc23
-rw-r--r--net/url_request/url_request_context.h13
50 files changed, 1208 insertions, 202 deletions
diff --git a/chrome/browser/automation/automation_util.cc b/chrome/browser/automation/automation_util.cc
new file mode 100644
index 0000000..10f5da4
--- /dev/null
+++ b/chrome/browser/automation/automation_util.cc
@@ -0,0 +1,248 @@
+// Copyright (c) 2011 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/automation/automation_util.h"
+
+#include <string>
+
+#include "base/values.h"
+#include "chrome/browser/automation/automation_provider_json.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/renderer_host/browser_render_process_host.h"
+#include "chrome/common/net/url_request_context_getter.h"
+#include "chrome/browser/ui/browser.h"
+#include "content/browser/browser_thread.h"
+#include "content/browser/renderer_host/render_view_host.h"
+#include "net/base/cookie_store.h"
+#include "net/url_request/url_request_context.h"
+
+namespace {
+
+void GetCookiesOnIOThread(
+ const GURL& url,
+ const scoped_refptr<URLRequestContextGetter>& context_getter,
+ base::WaitableEvent* event,
+ std::string* cookies) {
+ *cookies = context_getter->GetCookieStore()->GetCookies(url);
+ event->Signal();
+}
+
+void SetCookieOnIOThread(
+ const GURL& url,
+ const std::string& value,
+ const scoped_refptr<URLRequestContextGetter>& context_getter,
+ base::WaitableEvent* event,
+ bool* success) {
+ *success = context_getter->GetCookieStore()->SetCookie(url, value);
+ event->Signal();
+}
+
+void DeleteCookieOnIOThread(
+ const GURL& url,
+ const std::string& name,
+ const scoped_refptr<URLRequestContextGetter>& context_getter,
+ base::WaitableEvent* event) {
+ context_getter->GetCookieStore()->DeleteCookie(url, name);
+ event->Signal();
+}
+
+} // namespace
+
+namespace automation_util {
+
+void GetCookies(const GURL& url,
+ TabContents* contents,
+ int* value_size,
+ std::string* value) {
+ *value_size = -1;
+ if (url.is_valid() && contents) {
+ // Since we may be on the UI thread don't call GetURLRequestContext().
+ // Get the request context specific to the current TabContents and app.
+ const Extension* installed_app = static_cast<BrowserRenderProcessHost*>(
+ contents->render_view_host()->process())->installed_app();
+ scoped_refptr<URLRequestContextGetter> context_getter =
+ contents->profile()->GetRequestContextForPossibleApp(installed_app);
+
+ base::WaitableEvent event(true /* manual reset */,
+ false /* not initially signaled */);
+ CHECK(BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableFunction(&GetCookiesOnIOThread,
+ url, context_getter, &event, value)));
+ event.Wait();
+
+ *value_size = static_cast<int>(value->size());
+ }
+}
+
+void SetCookie(const GURL& url,
+ const std::string value,
+ TabContents* contents,
+ int* response_value) {
+ *response_value = -1;
+
+ if (url.is_valid() && contents) {
+ // Since we may be on the UI thread don't call GetURLRequestContext().
+ // Get the request context specific to the current TabContents and app.
+ const Extension* installed_app = static_cast<BrowserRenderProcessHost*>(
+ contents->render_view_host()->process())->installed_app();
+ scoped_refptr<URLRequestContextGetter> context_getter =
+ contents->profile()->GetRequestContextForPossibleApp(installed_app);
+
+ base::WaitableEvent event(true /* manual reset */,
+ false /* not initially signaled */);
+ bool success = false;
+ CHECK(BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableFunction(&SetCookieOnIOThread,
+ url, value, context_getter, &event,
+ &success)));
+ event.Wait();
+ if (success)
+ *response_value = 1;
+ }
+}
+
+void DeleteCookie(const GURL& url,
+ const std::string& cookie_name,
+ TabContents* contents,
+ bool* success) {
+ *success = false;
+ if (url.is_valid() && contents) {
+ // Since we may be on the UI thread don't call GetURLRequestContext().
+ // Get the request context specific to the current TabContents and app.
+ const Extension* installed_app = static_cast<BrowserRenderProcessHost*>(
+ contents->render_view_host()->process())->installed_app();
+ scoped_refptr<URLRequestContextGetter> context_getter =
+ contents->profile()->GetRequestContextForPossibleApp(installed_app);
+
+ base::WaitableEvent event(true /* manual reset */,
+ false /* not initially signaled */);
+ CHECK(BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableFunction(&DeleteCookieOnIOThread,
+ url, cookie_name, context_getter, &event)));
+ event.Wait();
+ *success = true;
+ }
+}
+
+void GetCookiesJSON(AutomationProvider* provider,
+ DictionaryValue* args,
+ IPC::Message* reply_message) {
+ AutomationJSONReply reply(provider, reply_message);
+ Browser* browser;
+ std::string error;
+ if (!GetBrowserFromJSONArgs(args, &browser, &error)) {
+ reply.SendError(error);
+ return;
+ }
+ std::string url;
+ if (!args->GetString("url", &url)) {
+ reply.SendError("'url' missing or invalid");
+ return;
+ }
+
+ // Since we may be on the UI thread don't call GetURLRequestContext().
+ scoped_refptr<URLRequestContextGetter> context_getter =
+ browser->profile()->GetRequestContext();
+
+ std::string cookies;
+ base::WaitableEvent event(true /* manual reset */,
+ false /* not initially signaled */);
+ Task* task = NewRunnableFunction(
+ &GetCookiesOnIOThread,
+ GURL(url), context_getter, &event, &cookies);
+ if (!BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, task)) {
+ reply.SendError("Couldn't post task to get the cookies");
+ return;
+ }
+ event.Wait();
+
+ DictionaryValue dict;
+ dict.SetString("cookies", cookies);
+ reply.SendSuccess(&dict);
+}
+
+void DeleteCookieJSON(AutomationProvider* provider,
+ DictionaryValue* args,
+ IPC::Message* reply_message) {
+ AutomationJSONReply reply(provider, reply_message);
+ Browser* browser;
+ std::string error;
+ if (!GetBrowserFromJSONArgs(args, &browser, &error)) {
+ reply.SendError(error);
+ return;
+ }
+ std::string url, name;
+ if (!args->GetString("url", &url)) {
+ reply.SendError("'url' missing or invalid");
+ return;
+ }
+ if (!args->GetString("name", &name)) {
+ reply.SendError("'name' missing or invalid");
+ return;
+ }
+
+ // Since we may be on the UI thread don't call GetURLRequestContext().
+ scoped_refptr<URLRequestContextGetter> context_getter =
+ browser->profile()->GetRequestContext();
+
+ base::WaitableEvent event(true /* manual reset */,
+ false /* not initially signaled */);
+ Task* task = NewRunnableFunction(
+ &DeleteCookieOnIOThread,
+ GURL(url), name, context_getter, &event);
+ if (!BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, task)) {
+ reply.SendError("Couldn't post task to delete the cookie");
+ return;
+ }
+ event.Wait();
+ reply.SendSuccess(NULL);
+}
+
+void SetCookieJSON(AutomationProvider* provider,
+ DictionaryValue* args,
+ IPC::Message* reply_message) {
+ AutomationJSONReply reply(provider, reply_message);
+ Browser* browser;
+ std::string error;
+ if (!GetBrowserFromJSONArgs(args, &browser, &error)) {
+ reply.SendError(error);
+ return;
+ }
+ std::string url, cookie;
+ if (!args->GetString("url", &url)) {
+ reply.SendError("'url' missing or invalid");
+ return;
+ }
+ if (!args->GetString("cookie", &cookie)) {
+ reply.SendError("'cookie' missing or invalid");
+ return;
+ }
+
+ // Since we may be on the UI thread don't call GetURLRequestContext().
+ scoped_refptr<URLRequestContextGetter> context_getter =
+ browser->profile()->GetRequestContext();
+
+ base::WaitableEvent event(true /* manual reset */,
+ false /* not initially signaled */);
+ bool success = false;
+ Task* task = NewRunnableFunction(
+ &SetCookieOnIOThread,
+ GURL(url), cookie, context_getter, &event, &success);
+ if (!BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, task)) {
+ reply.SendError("Couldn't post task to set the cookie");
+ return;
+ }
+ event.Wait();
+
+ if (!success) {
+ reply.SendError("Could not set the cookie");
+ return;
+ }
+ reply.SendSuccess(NULL);
+}
+
+} // namespace automation_util
diff --git a/chrome/browser/automation/automation_util.h b/chrome/browser/automation/automation_util.h
new file mode 100644
index 0000000..bb38344
--- /dev/null
+++ b/chrome/browser/automation/automation_util.h
@@ -0,0 +1,72 @@
+// Copyright (c) 2011 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_AUTOMATION_AUTOMATION_UTIL_H_
+#define CHROME_BROWSER_AUTOMATION_AUTOMATION_UTIL_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "chrome/browser/automation/automation_provider.h"
+#include "content/browser/tab_contents/tab_contents.h"
+
+class DictionaryValue;
+
+// This file contains automation utility functions.
+
+namespace automation_util {
+
+// Gets the size and value of the cookie string for |url| in the given tab.
+// Can be called from any thread.
+void GetCookies(const GURL& url,
+ TabContents* contents,
+ int* value_size,
+ std::string* value);
+
+// Sets a cookie for |url| in the given tab. Can be called from any thread.
+void SetCookie(const GURL& url,
+ const std::string value,
+ TabContents* contents,
+ int* response_value);
+
+// Deletes a cookie for |url| in the given tab. Can be called from any thread.
+void DeleteCookie(const GURL& url,
+ const std::string& cookie_name,
+ TabContents* contents,
+ bool* success);
+
+// Gets the cookies for the given URL. Uses the JSON interface.
+// Example:
+// input: { "windex": 1, "tab_index": 1, "url": "http://www.google.com" }
+// output: { "cookies": "PREF=12012" }
+void GetCookiesJSON(AutomationProvider* provider,
+ DictionaryValue* args,
+ IPC::Message* reply_message);
+
+// Deletes the cookie with the given name for the URL. Uses the JSON interface.
+// Example:
+// input: { "windex": 1,
+// "tab_index": 1,
+// "url": "http://www.google.com",
+// "name": "my_cookie"
+// }
+// output: none
+void DeleteCookieJSON(AutomationProvider* provider,
+ DictionaryValue* args,
+ IPC::Message* reply_message);
+
+// Sets a cookie for the given URL. Uses the JSON interface.
+// Example:
+// input: { "windex": 1,
+// "tab_index": 1,
+// "url": "http://www.google.com",
+// "cookie": "PREF=21321"
+// }
+// output: none
+void SetCookieJSON(AutomationProvider* provider,
+ DictionaryValue* args,
+ IPC::Message* reply_message);
+
+} // namespace automation_util
+
+#endif // CHROME_BROWSER_AUTOMATION_AUTOMATION_UTIL_H_
diff --git a/chrome/browser/automation/testing_automation_provider.cc b/chrome/browser/automation/testing_automation_provider.cc
index a2385b0..476f0ee 100644
--- a/chrome/browser/automation/testing_automation_provider.cc
+++ b/chrome/browser/automation/testing_automation_provider.cc
@@ -30,6 +30,7 @@
#include "chrome/browser/automation/automation_provider_list.h"
#include "chrome/browser/automation/automation_provider_observers.h"
#include "chrome/browser/automation/automation_tab_tracker.h"
+#include "chrome/browser/automation/automation_util.h"
#include "chrome/browser/automation/automation_window_tracker.h"
#include "chrome/browser/automation/ui_controls.h"
#include "chrome/browser/blocked_content_container.h"
@@ -72,7 +73,6 @@
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
-#include "chrome/common/net/url_request_context_getter.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "content/browser/renderer_host/render_process_host.h"
@@ -81,7 +81,6 @@
#include "content/common/common_param_traits.h"
#include "content/common/notification_service.h"
#include "net/base/cookie_store.h"
-#include "net/url_request/url_request_context.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h"
#include "ui/base/events.h"
#include "ui/base/message_box_flags.h"
@@ -89,34 +88,6 @@
namespace {
-void GetCookiesOnIOThread(
- const GURL& url,
- const scoped_refptr<URLRequestContextGetter>& context_getter,
- base::WaitableEvent* event,
- std::string* cookies) {
- *cookies = context_getter->GetCookieStore()->GetCookies(url);
- event->Signal();
-}
-
-void SetCookieOnIOThread(
- const GURL& url,
- const std::string& value,
- const scoped_refptr<URLRequestContextGetter>& context_getter,
- base::WaitableEvent* event,
- bool* success) {
- *success = context_getter->GetCookieStore()->SetCookie(url, value);
- event->Signal();
-}
-
-void DeleteCookieOnIOThread(
- const GURL& url,
- const std::string& name,
- const scoped_refptr<URLRequestContextGetter>& context_getter,
- base::WaitableEvent* event) {
- context_getter->GetCookieStore()->DeleteCookie(url, name);
- event->Signal();
-}
-
void SendMouseClick(int flags) {
ui_controls::MouseButton button = ui_controls::LEFT;
if ((flags & ui::EF_LEFT_BUTTON_DOWN) ==
@@ -508,67 +479,26 @@ void TestingAutomationProvider::CloseTab(int tab_handle,
void TestingAutomationProvider::GetCookies(const GURL& url, int handle,
int* value_size,
std::string* value) {
- *value_size = -1;
- if (url.is_valid() && tab_tracker_->ContainsHandle(handle)) {
- // Since we are running on the UI thread don't call GetURLRequestContext().
- scoped_refptr<URLRequestContextGetter> context_getter =
- tab_tracker_->GetResource(handle)->profile()->GetRequestContext();
-
- base::WaitableEvent event(true /* manual reset */,
- false /* not initially signaled */);
- CHECK(BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- NewRunnableFunction(&GetCookiesOnIOThread,
- url, context_getter, &event, value)));
- event.Wait();
-
- *value_size = static_cast<int>(value->size());
- }
+ TabContents *contents = tab_tracker_->ContainsHandle(handle) ?
+ tab_tracker_->GetResource(handle)->tab_contents() : NULL;
+ automation_util::GetCookies(url, contents, value_size, value);
}
void TestingAutomationProvider::SetCookie(const GURL& url,
const std::string value,
int handle,
int* response_value) {
- *response_value = -1;
-
- if (url.is_valid() && tab_tracker_->ContainsHandle(handle)) {
- // Since we are running on the UI thread don't call GetURLRequestContext().
- scoped_refptr<URLRequestContextGetter> context_getter =
- tab_tracker_->GetResource(handle)->profile()->GetRequestContext();
-
- base::WaitableEvent event(true /* manual reset */,
- false /* not initially signaled */);
- bool success = false;
- CHECK(BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- NewRunnableFunction(&SetCookieOnIOThread,
- url, value, context_getter, &event,
- &success)));
- event.Wait();
- if (success)
- *response_value = 1;
- }
+ TabContents *contents = tab_tracker_->ContainsHandle(handle) ?
+ tab_tracker_->GetResource(handle)->tab_contents() : NULL;
+ automation_util::SetCookie(url, value, contents, response_value);
}
void TestingAutomationProvider::DeleteCookie(const GURL& url,
const std::string& cookie_name,
int handle, bool* success) {
- *success = false;
- if (url.is_valid() && tab_tracker_->ContainsHandle(handle)) {
- // Since we are running on the UI thread don't call GetURLRequestContext().
- scoped_refptr<URLRequestContextGetter> context_getter =
- tab_tracker_->GetResource(handle)->profile()->GetRequestContext();
-
- base::WaitableEvent event(true /* manual reset */,
- false /* not initially signaled */);
- CHECK(BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- NewRunnableFunction(&DeleteCookieOnIOThread,
- url, cookie_name, context_getter, &event)));
- event.Wait();
- *success = true;
- }
+ TabContents *contents = tab_tracker_->ContainsHandle(handle) ?
+ tab_tracker_->GetResource(handle)->tab_contents() : NULL;
+ automation_util::DeleteCookie(url, cookie_name, contents, success);
}
void TestingAutomationProvider::ShowCollectedCookiesDialog(
@@ -5024,116 +4954,17 @@ void TestingAutomationProvider::GetTabTitleJSON(
void TestingAutomationProvider::GetCookiesJSON(
DictionaryValue* args, IPC::Message* reply_message) {
- AutomationJSONReply reply(this, reply_message);
- Browser* browser;
- std::string error;
- if (!GetBrowserFromJSONArgs(args, &browser, &error)) {
- reply.SendError(error);
- return;
- }
- std::string url;
- if (!args->GetString("url", &url)) {
- reply.SendError("'url' missing or invalid");
- return;
- }
-
- // Since we are running on the UI thread don't call GetURLRequestContext().
- scoped_refptr<URLRequestContextGetter> context_getter =
- browser->profile()->GetRequestContext();
-
- std::string cookies;
- base::WaitableEvent event(true /* manual reset */,
- false /* not initially signaled */);
- Task* task = NewRunnableFunction(
- &GetCookiesOnIOThread,
- GURL(url), context_getter, &event, &cookies);
- if (!BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, task)) {
- reply.SendError("Couldn't post task to get the cookies");
- return;
- }
- event.Wait();
-
- DictionaryValue dict;
- dict.SetString("cookies", cookies);
- reply.SendSuccess(&dict);
+ automation_util::GetCookiesJSON(this, args, reply_message);
}
void TestingAutomationProvider::DeleteCookieJSON(
DictionaryValue* args, IPC::Message* reply_message) {
- AutomationJSONReply reply(this, reply_message);
- Browser* browser;
- std::string error;
- if (!GetBrowserFromJSONArgs(args, &browser, &error)) {
- reply.SendError(error);
- return;
- }
- std::string url, name;
- if (!args->GetString("url", &url)) {
- reply.SendError("'url' missing or invalid");
- return;
- }
- if (!args->GetString("name", &name)) {
- reply.SendError("'name' missing or invalid");
- return;
- }
-
- // Since we are running on the UI thread don't call GetURLRequestContext().
- scoped_refptr<URLRequestContextGetter> context_getter =
- browser->profile()->GetRequestContext();
-
- base::WaitableEvent event(true /* manual reset */,
- false /* not initially signaled */);
- Task* task = NewRunnableFunction(
- &DeleteCookieOnIOThread,
- GURL(url), name, context_getter, &event);
- if (!BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, task)) {
- reply.SendError("Couldn't post task to delete the cookie");
- return;
- }
- event.Wait();
- reply.SendSuccess(NULL);
+ automation_util::DeleteCookieJSON(this, args, reply_message);
}
void TestingAutomationProvider::SetCookieJSON(
DictionaryValue* args, IPC::Message* reply_message) {
- AutomationJSONReply reply(this, reply_message);
- Browser* browser;
- std::string error;
- if (!GetBrowserFromJSONArgs(args, &browser, &error)) {
- reply.SendError(error);
- return;
- }
- std::string url, cookie;
- if (!args->GetString("url", &url)) {
- reply.SendError("'url' missing or invalid");
- return;
- }
- if (!args->GetString("cookie", &cookie)) {
- reply.SendError("'cookie' missing or invalid");
- return;
- }
-
- // Since we are running on the UI thread don't call GetURLRequestContext().
- scoped_refptr<URLRequestContextGetter> context_getter =
- browser->profile()->GetRequestContext();
-
- base::WaitableEvent event(true /* manual reset */,
- false /* not initially signaled */);
- bool success = false;
- Task* task = NewRunnableFunction(
- &SetCookieOnIOThread,
- GURL(url), cookie, context_getter, &event, &success);
- if (!BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, task)) {
- reply.SendError("Couldn't post task to set the cookie");
- return;
- }
- event.Wait();
-
- if (!success) {
- reply.SendError("Could not set the cookie");
- return;
- }
- reply.SendSuccess(NULL);
+ automation_util::SetCookieJSON(this, args, reply_message);
}
void TestingAutomationProvider::GetTabIds(
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 0c2502c..da6f45a 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -6,6 +6,7 @@
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/renderer_host/browser_render_process_host.h"
#include "content/browser/renderer_host/render_view_host.h"
namespace chrome {
@@ -19,6 +20,10 @@ void ChromeContentBrowserClient::OnRenderViewCreation(
if (service) {
bool is_extension_process = service->ExtensionBindingsAllowed(url);
render_view_host->set_is_extension_process(is_extension_process);
+
+ const Extension* installed_app = service->GetInstalledApp(url);
+ static_cast<BrowserRenderProcessHost*>(render_view_host->process())->
+ set_installed_app(installed_app);
}
}
diff --git a/chrome/browser/extensions/extension_host.cc b/chrome/browser/extensions/extension_host.cc
index 20fd0a4..0566619 100644
--- a/chrome/browser/extensions/extension_host.cc
+++ b/chrome/browser/extensions/extension_host.cc
@@ -21,6 +21,7 @@
#include "chrome/browser/file_select_helper.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/renderer_host/browser_render_process_host.h"
#include "chrome/browser/renderer_preferences_util.h"
#include "chrome/browser/tab_contents/popup_menu_helper_mac.h"
#include "chrome/browser/themes/browser_theme_provider.h"
@@ -137,6 +138,11 @@ ExtensionHost::ExtensionHost(const Extension* extension,
render_view_host_ = new RenderViewHost(site_instance, this, MSG_ROUTING_NONE,
NULL);
render_view_host_->set_is_extension_process(true);
+ if (extension->is_app()) {
+ BrowserRenderProcessHost* process = static_cast<BrowserRenderProcessHost*>(
+ render_view_host_->process());
+ process->set_installed_app(extension);
+ }
render_view_host_->AllowBindings(BindingsPolicy::EXTENSION);
if (enable_dom_automation_)
render_view_host_->AllowBindings(BindingsPolicy::DOM_AUTOMATION);
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index 702fc86..a0d334e 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -326,14 +326,22 @@ bool ExtensionService::IsDownloadFromMiniGallery(const GURL& download_url) {
false); // case_sensitive
}
-bool ExtensionService::IsInstalledApp(const GURL& url) {
+const Extension* ExtensionService::GetInstalledApp(const GURL& url) {
// Check for hosted app.
- if (GetExtensionByWebExtent(url) != NULL)
- return true;
+ const Extension* app = GetExtensionByWebExtent(url);
+ if (app)
+ return app;
// Check for packaged app.
- const Extension* extension = GetExtensionByURL(url);
- return extension != NULL && extension->is_app();
+ app = GetExtensionByURL(url);
+ if (app && app->is_app())
+ return app;
+
+ return NULL;
+}
+
+bool ExtensionService::IsInstalledApp(const GURL& url) {
+ return !!GetInstalledApp(url);
}
// static
diff --git a/chrome/browser/extensions/extension_service.h b/chrome/browser/extensions/extension_service.h
index 32a6356..096319a 100644
--- a/chrome/browser/extensions/extension_service.h
+++ b/chrome/browser/extensions/extension_service.h
@@ -108,6 +108,9 @@ class ExtensionService
// Used to test if we need to show the "Loading" dialog for themes.
static bool IsDownloadFromMiniGallery(const GURL& download_url);
+ // Returns the Extension of hosted or packaged apps, NULL otherwise.
+ const Extension* GetInstalledApp(const GURL& url);
+
// Returns whether the URL is from either a hosted or packaged app.
bool IsInstalledApp(const GURL& url);
diff --git a/chrome/browser/extensions/isolated_app_apitest.cc b/chrome/browser/extensions/isolated_app_apitest.cc
new file mode 100644
index 0000000..1d0c5da
--- /dev/null
+++ b/chrome/browser/extensions/isolated_app_apitest.cc
@@ -0,0 +1,141 @@
+// Copyright (c) 2011 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 "base/utf_string_conversions.h"
+#include "chrome/browser/automation/automation_util.h"
+#include "chrome/browser/extensions/extension_apitest.h"
+#include "chrome/browser/extensions/extension_host.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/renderer_host/browser_render_process_host.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/test/ui_test_utils.h"
+#include "content/browser/renderer_host/render_view_host.h"
+#include "content/browser/tab_contents/tab_contents.h"
+#include "net/base/mock_host_resolver.h"
+
+namespace {
+
+class IsolatedAppApiTest : public ExtensionApiTest {
+ public:
+ // Returns whether the given tab's current URL has the given cookie.
+ bool WARN_UNUSED_RESULT HasCookie(TabContents* contents, std::string cookie) {
+ int value_size;
+ std::string actual_cookie;
+ automation_util::GetCookies(contents->GetURL(), contents, &value_size,
+ &actual_cookie);
+ return actual_cookie.find(cookie) != std::string::npos;
+ }
+
+ const Extension* GetInstalledApp(TabContents* contents) {
+ return static_cast<BrowserRenderProcessHost*>(
+ contents->render_view_host()->process())->installed_app();
+ }
+};
+
+} // namespace
+
+// Tests that cookies set within an isolated app are not visible to normal
+// pages or other apps.
+IN_PROC_BROWSER_TEST_F(IsolatedAppApiTest, CookieIsolation) {
+ CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kDisablePopupBlocking);
+ CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableExperimentalAppManifests);
+
+ host_resolver()->AddRule("*", "127.0.0.1");
+ ASSERT_TRUE(test_server()->Start());
+
+ ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("isolated_apps/app1")));
+ ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("isolated_apps/app2")));
+
+ // The app under test acts on URLs whose host is "localhost",
+ // so the URLs we navigate to must have host "localhost".
+ GURL base_url = test_server()->GetURL(
+ "files/extensions/api_test/isolated_apps/");
+ GURL::Replacements replace_host;
+ std::string host_str("localhost"); // Must stay in scope with replace_host.
+ replace_host.SetHostStr(host_str);
+ base_url = base_url.ReplaceComponents(replace_host);
+
+ browser()->NewTab();
+ ui_test_utils::NavigateToURL(browser(), base_url.Resolve("app1/main.html"));
+ browser()->NewTab();
+ ui_test_utils::NavigateToURL(browser(), base_url.Resolve("app2/main.html"));
+ browser()->NewTab();
+ ui_test_utils::NavigateToURL(browser(),
+ base_url.Resolve("non_app/main.html"));
+
+ // Ensure first two tabs have installed apps.
+ TabContents* tab1 = browser()->GetTabContentsAt(1);
+ TabContents* tab2 = browser()->GetTabContentsAt(2);
+ TabContents* tab3 = browser()->GetTabContentsAt(3);
+ ASSERT_TRUE(GetInstalledApp(tab1));
+ ASSERT_TRUE(GetInstalledApp(tab2));
+ ASSERT_TRUE(!GetInstalledApp(tab3));
+
+ // Check that each tab sees its own cookie.
+ ASSERT_TRUE(HasCookie(tab1, "app1=3"));
+ ASSERT_TRUE(HasCookie(tab2, "app2=4"));
+ ASSERT_TRUE(HasCookie(tab3, "normalPage=5"));
+
+ // Check that app1 tab cannot see the other cookies.
+ ASSERT_FALSE(HasCookie(tab1, "app2"));
+ ASSERT_FALSE(HasCookie(tab1, "normalPage"));
+
+ // Check that app2 tab cannot see the other cookies.
+ ASSERT_FALSE(HasCookie(tab2, "app1"));
+ ASSERT_FALSE(HasCookie(tab2, "normalPage"));
+
+ // Check that normal tab cannot see the other cookies.
+ ASSERT_FALSE(HasCookie(tab3, "app1"));
+ ASSERT_FALSE(HasCookie(tab3, "app2"));
+
+ // Check that the non_app iframe cookie is associated with app1 and not the
+ // normal tab. (For now, iframes are always rendered in their parent
+ // process, even if they aren't in the app manifest.)
+ ASSERT_TRUE(HasCookie(tab1, "nonAppFrame=6"));
+ ASSERT_FALSE(HasCookie(tab3, "nonAppFrame"));
+}
+
+// Without the --enable-experimental-app-manifests flag, all the tabs
+// should see each others' cookies.
+IN_PROC_BROWSER_TEST_F(IsolatedAppApiTest, CookieIsolationRequiresFlag) {
+ CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kDisablePopupBlocking);
+
+ host_resolver()->AddRule("*", "127.0.0.1");
+ ASSERT_TRUE(test_server()->Start());
+
+ ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("isolated_apps/app1")));
+ ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("isolated_apps/app2")));
+
+ // The app under test acts on URLs whose host is "localhost",
+ // so the URLs we navigate to must have host "localhost".
+ GURL base_url = test_server()->GetURL(
+ "files/extensions/api_test/isolated_apps/");
+ GURL::Replacements replace_host;
+ std::string host_str("localhost"); // Must stay in scope with replace_host.
+ replace_host.SetHostStr(host_str);
+ base_url = base_url.ReplaceComponents(replace_host);
+
+ browser()->NewTab();
+ ui_test_utils::NavigateToURL(browser(), base_url.Resolve("app1/main.html"));
+ browser()->NewTab();
+ ui_test_utils::NavigateToURL(browser(), base_url.Resolve("app2/main.html"));
+ browser()->NewTab();
+ ui_test_utils::NavigateToURL(browser(),
+ base_url.Resolve("non_app/main.html"));
+
+ // Check that tabs see each others' cookies.
+ ASSERT_TRUE(HasCookie(browser()->GetTabContentsAt(1), "app2=4"));
+ ASSERT_TRUE(HasCookie(browser()->GetTabContentsAt(1), "normalPage=5"));
+ ASSERT_TRUE(HasCookie(browser()->GetTabContentsAt(1), "nonAppFrame=6"));
+ ASSERT_TRUE(HasCookie(browser()->GetTabContentsAt(2), "app1=3"));
+ ASSERT_TRUE(HasCookie(browser()->GetTabContentsAt(2), "normalPage=5"));
+ ASSERT_TRUE(HasCookie(browser()->GetTabContentsAt(2), "nonAppFrame=6"));
+ ASSERT_TRUE(HasCookie(browser()->GetTabContentsAt(3), "app1=3"));
+ ASSERT_TRUE(HasCookie(browser()->GetTabContentsAt(3), "app2=4"));
+ ASSERT_TRUE(HasCookie(browser()->GetTabContentsAt(3), "nonAppFrame=6"));
+}
diff --git a/chrome/browser/net/chrome_url_request_context.cc b/chrome/browser/net/chrome_url_request_context.cc
index 32066a1..e8b68be 100644
--- a/chrome/browser/net/chrome_url_request_context.cc
+++ b/chrome/browser/net/chrome_url_request_context.cc
@@ -77,6 +77,29 @@ class FactoryForExtensions : public ChromeURLRequestContextFactory {
const scoped_refptr<const ProfileIOData> profile_io_data_;
};
+// Factory that creates the ChromeURLRequestContext for a given isolated app.
+class FactoryForIsolatedApp : public ChromeURLRequestContextFactory {
+ public:
+ FactoryForIsolatedApp(const ProfileIOData* profile_io_data,
+ const std::string& app_id,
+ ChromeURLRequestContextGetter* main_context)
+ : profile_io_data_(profile_io_data),
+ app_id_(app_id),
+ main_request_context_getter_(main_context) {}
+
+ virtual scoped_refptr<ChromeURLRequestContext> Create() {
+ // We will copy most of the state from the main request context.
+ return profile_io_data_->GetIsolatedAppRequestContext(
+ main_request_context_getter_->GetIOContext(), app_id_);
+ }
+
+ private:
+ const scoped_refptr<const ProfileIOData> profile_io_data_;
+ const std::string app_id_;
+ scoped_refptr<ChromeURLRequestContextGetter>
+ main_request_context_getter_;
+};
+
// Factory that creates the ChromeURLRequestContext for media.
class FactoryForMedia : public ChromeURLRequestContextFactory {
public:
@@ -215,6 +238,20 @@ ChromeURLRequestContextGetter::CreateOriginalForExtensions(
// static
ChromeURLRequestContextGetter*
+ChromeURLRequestContextGetter::CreateOriginalForIsolatedApp(
+ Profile* profile,
+ const ProfileIOData* profile_io_data,
+ const std::string& app_id) {
+ DCHECK(!profile->IsOffTheRecord());
+ ChromeURLRequestContextGetter* main_context =
+ static_cast<ChromeURLRequestContextGetter*>(profile->GetRequestContext());
+ return new ChromeURLRequestContextGetter(
+ profile,
+ new FactoryForIsolatedApp(profile_io_data, app_id, main_context));
+}
+
+// static
+ChromeURLRequestContextGetter*
ChromeURLRequestContextGetter::CreateOffTheRecord(
Profile* profile, const ProfileIOData* profile_io_data) {
DCHECK(profile->IsOffTheRecord());
@@ -231,6 +268,20 @@ ChromeURLRequestContextGetter::CreateOffTheRecordForExtensions(
profile, new FactoryForExtensions(profile_io_data));
}
+// static
+ChromeURLRequestContextGetter*
+ChromeURLRequestContextGetter::CreateOffTheRecordForIsolatedApp(
+ Profile* profile,
+ const ProfileIOData* profile_io_data,
+ const std::string& app_id) {
+ DCHECK(profile->IsOffTheRecord());
+ ChromeURLRequestContextGetter* main_context =
+ static_cast<ChromeURLRequestContextGetter*>(profile->GetRequestContext());
+ return new ChromeURLRequestContextGetter(
+ profile,
+ new FactoryForIsolatedApp(profile_io_data, app_id, main_context));
+}
+
void ChromeURLRequestContextGetter::CleanupOnUIThread() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
// Unregister for pref notifications.
@@ -324,6 +375,24 @@ ChromeURLRequestContext::ChromeURLRequestContext()
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
}
+void ChromeURLRequestContext::CopyFrom(ChromeURLRequestContext* other) {
+ URLRequestContext::CopyFrom(other);
+
+ // Copy ChromeURLRequestContext parameters.
+ set_user_script_dir_path(other->user_script_dir_path());
+ set_appcache_service(other->appcache_service());
+ set_database_tracker(other->database_tracker());
+ set_chrome_cookie_policy(other->chrome_cookie_policy_);
+ set_host_content_settings_map(other->host_content_settings_map());
+ set_host_zoom_map(other->host_zoom_map_);
+ set_blob_storage_context(other->blob_storage_context());
+ set_file_system_context(other->file_system_context());
+ set_extension_info_map(other->extension_info_map_);
+ set_prerender_manager(other->prerender_manager());
+ // ChromeURLDataManagerBackend is unique per context.
+ set_is_incognito(other->is_incognito());
+}
+
void ChromeURLRequestContext::set_chrome_cookie_policy(
ChromeCookiePolicy* cookie_policy) {
chrome_cookie_policy_ = cookie_policy; // Take a strong reference.
diff --git a/chrome/browser/net/chrome_url_request_context.h b/chrome/browser/net/chrome_url_request_context.h
index fab3f71..b8a87d2 100644
--- a/chrome/browser/net/chrome_url_request_context.h
+++ b/chrome/browser/net/chrome_url_request_context.h
@@ -47,6 +47,9 @@ class ChromeURLRequestContext : public net::URLRequestContext {
public:
ChromeURLRequestContext();
+ // Copies the state from |other| into this context.
+ void CopyFrom(ChromeURLRequestContext* other);
+
// Gets the path to the directory user scripts are stored in.
FilePath user_script_dir_path() const {
return user_script_dir_path_;
@@ -140,6 +143,11 @@ class ChromeURLRequestContext : public net::URLRequestContext {
virtual ~ChromeURLRequestContext();
private:
+ // ---------------------------------------------------------------------------
+ // Important: When adding any new members below, consider whether they need to
+ // be added to CopyFrom.
+ // ---------------------------------------------------------------------------
+
// Path to the directory user scripts are stored in.
FilePath user_script_dir_path_;
@@ -158,6 +166,11 @@ class ChromeURLRequestContext : public net::URLRequestContext {
bool is_incognito_;
+ // ---------------------------------------------------------------------------
+ // Important: When adding any new members above, consider whether they need to
+ // be added to CopyFrom.
+ // ---------------------------------------------------------------------------
+
DISALLOW_COPY_AND_ASSIGN(ChromeURLRequestContext);
};
@@ -213,6 +226,13 @@ class ChromeURLRequestContextGetter : public URLRequestContextGetter,
static ChromeURLRequestContextGetter* CreateOriginalForExtensions(
Profile* profile, const ProfileIOData* profile_io_data);
+ // Create an instance for an original profile for an app with isolated
+ // storage. This is expected to get called on UI thread.
+ static ChromeURLRequestContextGetter* CreateOriginalForIsolatedApp(
+ Profile* profile,
+ const ProfileIOData* profile_io_data,
+ const std::string& app_id);
+
// Create an instance for use with an OTR profile. This is expected to get
// called on the UI thread.
static ChromeURLRequestContextGetter* CreateOffTheRecord(
@@ -223,6 +243,13 @@ class ChromeURLRequestContextGetter : public URLRequestContextGetter,
static ChromeURLRequestContextGetter* CreateOffTheRecordForExtensions(
Profile* profile, const ProfileIOData* profile_io_data);
+ // Create an instance for an OTR profile for an app with isolated storage.
+ // This is expected to get called on UI thread.
+ static ChromeURLRequestContextGetter* CreateOffTheRecordForIsolatedApp(
+ Profile* profile,
+ const ProfileIOData* profile_io_data,
+ const std::string& app_id);
+
// Clean up UI thread resources. This is expected to get called on the UI
// thread before the instance is deleted on the IO thread.
void CleanupOnUIThread();
diff --git a/chrome/browser/net/sqlite_persistent_cookie_store.cc b/chrome/browser/net/sqlite_persistent_cookie_store.cc
index 6b92bfd..495efb5 100644
--- a/chrome/browser/net/sqlite_persistent_cookie_store.cc
+++ b/chrome/browser/net/sqlite_persistent_cookie_store.cc
@@ -18,6 +18,7 @@
#include "base/scoped_ptr.h"
#include "base/string_util.h"
#include "base/threading/thread.h"
+#include "base/threading/thread_restrictions.h"
#include "chrome/browser/diagnostics/sqlite_diagnostics.h"
#include "content/browser/browser_thread.h"
#include "googleurl/src/gurl.h"
@@ -156,6 +157,17 @@ bool SQLitePersistentCookieStore::Backend::Load(
// This function should be called only once per instance.
DCHECK(!db_.get());
+ // Ensure the parent directory for storing cookies is created before reading
+ // from it. We make an exception to allow IO on the UI thread here because
+ // we are going to disk anyway in db_->Open. (This code will be moved to the
+ // DB thread as part of http://crbug.com/52909.)
+ {
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
+ const FilePath dir = path_.DirName();
+ if (!file_util::PathExists(dir) && !file_util::CreateDirectory(dir))
+ return false;
+ }
+
db_.reset(new sql::Connection);
if (!db_->Open(path_)) {
NOTREACHED() << "Unable to open cookie DB.";
diff --git a/chrome/browser/notifications/balloon_host.cc b/chrome/browser/notifications/balloon_host.cc
index 9dfee2b..a4aa634 100644
--- a/chrome/browser/notifications/balloon_host.cc
+++ b/chrome/browser/notifications/balloon_host.cc
@@ -6,9 +6,11 @@
#include "chrome/browser/browser_list.h"
#include "chrome/browser/extensions/extension_process_manager.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/notifications/balloon.h"
#include "chrome/browser/notifications/notification.h"
#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/renderer_host/browser_render_process_host.h"
#include "chrome/browser/renderer_preferences_util.h"
#include "chrome/common/bindings_policy.h"
#include "chrome/common/render_messages.h"
@@ -201,6 +203,11 @@ void BalloonHost::Init() {
if (extension_function_dispatcher_.get()) {
rvh->AllowBindings(BindingsPolicy::EXTENSION);
rvh->set_is_extension_process(true);
+ const Extension* installed_app =
+ GetProfile()->GetExtensionService()->GetInstalledApp(
+ balloon_->notification().content_url());
+ static_cast<BrowserRenderProcessHost*>(rvh->process())->set_installed_app(
+ installed_app);
} else if (enable_web_ui_) {
rvh->AllowBindings(BindingsPolicy::WEB_UI);
}
diff --git a/chrome/browser/profiles/off_the_record_profile_io_data.cc b/chrome/browser/profiles/off_the_record_profile_io_data.cc
index 2be3631..26cacf1 100644
--- a/chrome/browser/profiles/off_the_record_profile_io_data.cc
+++ b/chrome/browser/profiles/off_the_record_profile_io_data.cc
@@ -6,6 +6,7 @@
#include "base/command_line.h"
#include "base/logging.h"
+#include "base/stl_util-inl.h"
#include "build/build_config.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/io_thread.h"
@@ -14,6 +15,7 @@
#include "chrome/browser/net/chrome_net_log.h"
#include "chrome/browser/net/chrome_network_delegate.h"
#include "chrome/browser/net/chrome_url_request_context.h"
+#include "chrome/common/extensions/extension.h"
#include "chrome/common/url_constants.h"
#include "content/browser/browser_thread.h"
#include "net/ftp/ftp_network_layer.h"
@@ -37,6 +39,14 @@ OffTheRecordProfileIOData::Handle::~Handle() {
main_request_context_getter_->CleanupOnUIThread();
if (extensions_request_context_getter_)
extensions_request_context_getter_->CleanupOnUIThread();
+
+ // Clean up all isolated app request contexts.
+ for (ChromeURLRequestContextGetterMap::iterator iter =
+ app_request_context_getter_map_.begin();
+ iter != app_request_context_getter_map_.end();
+ ++iter) {
+ iter->second->CleanupOnUIThread();
+ }
}
scoped_refptr<ChromeURLRequestContextGetter>
@@ -66,6 +76,27 @@ OffTheRecordProfileIOData::Handle::GetExtensionsRequestContextGetter() const {
return extensions_request_context_getter_;
}
+scoped_refptr<ChromeURLRequestContextGetter>
+OffTheRecordProfileIOData::Handle::GetIsolatedAppRequestContextGetter(
+ const std::string& app_id) const {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(!app_id.empty());
+ LazyInitialize();
+
+ // Keep a map of request context getters, one per requested app ID.
+ ChromeURLRequestContextGetterMap::iterator iter =
+ app_request_context_getter_map_.find(app_id);
+ if (iter != app_request_context_getter_map_.end())
+ return iter->second;
+
+ ChromeURLRequestContextGetter* context =
+ ChromeURLRequestContextGetter::CreateOffTheRecordForIsolatedApp(
+ profile_, io_data_, app_id);
+ app_request_context_getter_map_[app_id] = context;
+
+ return context;
+}
+
void OffTheRecordProfileIOData::Handle::LazyInitialize() const {
if (!initialized_) {
InitializeProfileParams(profile_, &io_data_->lazy_params_->profile_params);
@@ -79,7 +110,9 @@ OffTheRecordProfileIOData::LazyParams::~LazyParams() {}
OffTheRecordProfileIOData::OffTheRecordProfileIOData()
: ProfileIOData(true),
initialized_(false) {}
-OffTheRecordProfileIOData::~OffTheRecordProfileIOData() {}
+OffTheRecordProfileIOData::~OffTheRecordProfileIOData() {
+ STLDeleteValues(&app_http_factory_map_);
+}
void OffTheRecordProfileIOData::LazyInitializeInternal() const {
main_request_context_ = new RequestContext;
@@ -164,6 +197,37 @@ void OffTheRecordProfileIOData::LazyInitializeInternal() const {
new net::FtpNetworkLayer(main_request_context_->host_resolver()));
}
+scoped_refptr<ProfileIOData::RequestContext>
+OffTheRecordProfileIOData::InitializeAppRequestContext(
+ scoped_refptr<ChromeURLRequestContext> main_context,
+ const std::string& app_id) const {
+ scoped_refptr<ProfileIOData::RequestContext> context = new RequestContext;
+
+ // Copy most state from the main context.
+ context->CopyFrom(main_context);
+
+ // Use a separate in-memory cookie store for the app.
+ // TODO(creis): We should have a cookie delegate for notifying the cookie
+ // extensions API, but we need to update it to understand isolated apps first.
+ context->set_cookie_store(
+ new net::CookieMonster(NULL, NULL));
+
+ // Use a separate in-memory cache for the app.
+ net::HttpCache::BackendFactory* app_backend =
+ net::HttpCache::DefaultBackend::InMemory(0);
+ net::HttpNetworkSession* main_network_session =
+ main_http_factory_->GetSession();
+ net::HttpCache* app_http_cache =
+ new net::HttpCache(main_network_session, app_backend);
+
+ // Keep track of app_http_cache to delete it when we go away.
+ DCHECK(!app_http_factory_map_[app_id]);
+ app_http_factory_map_[app_id] = app_http_cache;
+ context->set_http_transaction_factory(app_http_cache);
+
+ return context;
+}
+
scoped_refptr<ChromeURLRequestContext>
OffTheRecordProfileIOData::AcquireMainRequestContext() const {
DCHECK(main_request_context_);
@@ -187,3 +251,15 @@ OffTheRecordProfileIOData::AcquireExtensionsRequestContext() const {
extensions_request_context_ = NULL;
return context;
}
+
+scoped_refptr<ChromeURLRequestContext>
+OffTheRecordProfileIOData::AcquireIsolatedAppRequestContext(
+ scoped_refptr<ChromeURLRequestContext> main_context,
+ const std::string& app_id) const {
+ // We create per-app contexts on demand, unlike the others above.
+ scoped_refptr<RequestContext> app_request_context =
+ InitializeAppRequestContext(main_context, app_id);
+ DCHECK(app_request_context);
+ app_request_context->set_profile_io_data(this);
+ return app_request_context;
+}
diff --git a/chrome/browser/profiles/off_the_record_profile_io_data.h b/chrome/browser/profiles/off_the_record_profile_io_data.h
index 3a6edf5..bac5c43 100644
--- a/chrome/browser/profiles/off_the_record_profile_io_data.h
+++ b/chrome/browser/profiles/off_the_record_profile_io_data.h
@@ -8,6 +8,7 @@
#include "base/basictypes.h"
#include "base/file_path.h"
+#include "base/hash_tables.h"
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/profiles/profile_io_data.h"
@@ -40,8 +41,15 @@ class OffTheRecordProfileIOData : public ProfileIOData {
GetMainRequestContextGetter() const;
scoped_refptr<ChromeURLRequestContextGetter>
GetExtensionsRequestContextGetter() const;
+ scoped_refptr<ChromeURLRequestContextGetter>
+ GetIsolatedAppRequestContextGetter(
+ const std::string& app_id) const;
private:
+ typedef base::hash_map<std::string,
+ scoped_refptr<ChromeURLRequestContextGetter> >
+ ChromeURLRequestContextGetterMap;
+
// Lazily initialize ProfileParams. We do this on the calls to
// Get*RequestContextGetter(), so we only initialize ProfileParams right
// before posting a task to the IO thread to start using them. This prevents
@@ -59,6 +67,8 @@ class OffTheRecordProfileIOData : public ProfileIOData {
main_request_context_getter_;
mutable scoped_refptr<ChromeURLRequestContextGetter>
extensions_request_context_getter_;
+ mutable ChromeURLRequestContextGetterMap
+ app_request_context_getter_map_;
const scoped_refptr<OffTheRecordProfileIOData> io_data_;
Profile* const profile_;
@@ -79,17 +89,27 @@ class OffTheRecordProfileIOData : public ProfileIOData {
ProfileParams profile_params;
};
+ typedef base::hash_map<std::string, net::HttpTransactionFactory* >
+ HttpTransactionFactoryMap;
+
OffTheRecordProfileIOData();
~OffTheRecordProfileIOData();
// Lazily initializes ProfileIOData.
virtual void LazyInitializeInternal() const;
+ virtual scoped_refptr<RequestContext> InitializeAppRequestContext(
+ scoped_refptr<ChromeURLRequestContext> main_context,
+ const std::string& app_id) const;
virtual scoped_refptr<ChromeURLRequestContext>
AcquireMainRequestContext() const;
virtual scoped_refptr<ChromeURLRequestContext>
AcquireMediaRequestContext() const;
virtual scoped_refptr<ChromeURLRequestContext>
AcquireExtensionsRequestContext() const;
+ virtual scoped_refptr<ChromeURLRequestContext>
+ AcquireIsolatedAppRequestContext(
+ scoped_refptr<ChromeURLRequestContext> main_context,
+ const std::string& app_id) const;
// Lazy initialization params.
mutable scoped_ptr<LazyParams> lazy_params_;
@@ -105,6 +125,9 @@ class OffTheRecordProfileIOData : public ProfileIOData {
mutable scoped_ptr<net::DnsCertProvenanceChecker> dns_cert_checker_;
mutable scoped_ptr<net::HttpTransactionFactory> main_http_factory_;
+ // One HttpTransactionFactory per isolated app.
+ mutable HttpTransactionFactoryMap app_http_factory_map_;
+
DISALLOW_COPY_AND_ASSIGN(OffTheRecordProfileIOData);
};
diff --git a/chrome/browser/profiles/profile.cc b/chrome/browser/profiles/profile.cc
index b56e449..2ec2de4 100644
--- a/chrome/browser/profiles/profile.cc
+++ b/chrome/browser/profiles/profile.cc
@@ -35,6 +35,7 @@
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
+#include "chrome/common/extensions/extension.h"
#include "chrome/common/json_pref_store.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/render_messages.h"
@@ -419,6 +420,17 @@ class OffTheRecordProfileImpl : public Profile,
return io_data_.GetMainRequestContextGetter();
}
+ virtual URLRequestContextGetter* GetRequestContextForPossibleApp(
+ const Extension* installed_app) {
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableExperimentalAppManifests) &&
+ installed_app != NULL &&
+ installed_app->is_storage_isolated())
+ return GetRequestContextForIsolatedApp(installed_app->id());
+
+ return GetRequestContext();
+ }
+
virtual URLRequestContextGetter* GetRequestContextForMedia() {
// In OTR mode, media request context is the same as the original one.
return io_data_.GetMainRequestContextGetter();
@@ -428,6 +440,11 @@ class OffTheRecordProfileImpl : public Profile,
return io_data_.GetExtensionsRequestContextGetter();
}
+ URLRequestContextGetter* GetRequestContextForIsolatedApp(
+ const std::string& app_id) {
+ return io_data_.GetIsolatedAppRequestContextGetter(app_id);
+ }
+
virtual net::SSLConfigService* GetSSLConfigService() {
return profile_->GetSSLConfigService();
}
diff --git a/chrome/browser/profiles/profile.h b/chrome/browser/profiles/profile.h
index 15d3b09..9b70f2c 100644
--- a/chrome/browser/profiles/profile.h
+++ b/chrome/browser/profiles/profile.h
@@ -346,6 +346,14 @@ class Profile {
// happen on the UI thread.
virtual URLRequestContextGetter* GetRequestContext() = 0;
+ // Returns the request context appropriate for the given app. If installed_app
+ // is null or installed_app->is_storage_isolated() returns false, this is
+ // equivalent to calling GetRequestContext().
+ // TODO(creis): After isolated app storage is no longer an experimental
+ // feature, consider making this the default contract for GetRequestContext.
+ virtual URLRequestContextGetter* GetRequestContextForPossibleApp(
+ const Extension* installed_app) = 0;
+
// Returns the request context for media resources asociated with this
// profile.
virtual URLRequestContextGetter* GetRequestContextForMedia() = 0;
@@ -354,6 +362,11 @@ class Profile {
// is only used for a separate cookie store currently.
virtual URLRequestContextGetter* GetRequestContextForExtensions() = 0;
+ // Returns the request context used within an installed app that has
+ // requested isolated storage.
+ virtual URLRequestContextGetter* GetRequestContextForIsolatedApp(
+ const std::string& app_id) = 0;
+
// Called by the ExtensionService that lives in this profile. Gives the
// profile a chance to react to the load event before the EXTENSION_LOADED
// notification has fired. The purpose for handling this event first is to
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index d973c1f..f500f42 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -341,10 +341,13 @@ ProfileImpl::ProfileImpl(const FilePath& path)
extensions_cookie_path =
extensions_cookie_path.Append(chrome::kExtensionsCookieFilename);
+ FilePath app_path = GetPath().Append(chrome::kIsolatedAppStateDirname);
+
// Make sure we initialize the ProfileIOData after everything else has been
// initialized that we might be reading from the IO thread.
io_data_.Init(cookie_path, cache_path, cache_max_size,
- media_cache_path, media_cache_max_size, extensions_cookie_path);
+ media_cache_path, media_cache_max_size, extensions_cookie_path,
+ app_path);
// Initialize the ProfilePolicyConnector after |io_data_| since it requires
// the URLRequestContextGetter to be initialized.
@@ -821,6 +824,17 @@ URLRequestContextGetter* ProfileImpl::GetRequestContext() {
return request_context;
}
+URLRequestContextGetter* ProfileImpl::GetRequestContextForPossibleApp(
+ const Extension* installed_app) {
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableExperimentalAppManifests) &&
+ installed_app != NULL &&
+ installed_app->is_storage_isolated())
+ return GetRequestContextForIsolatedApp(installed_app->id());
+
+ return GetRequestContext();
+}
+
URLRequestContextGetter* ProfileImpl::GetRequestContextForMedia() {
return io_data_.GetMediaRequestContextGetter();
}
@@ -838,6 +852,11 @@ URLRequestContextGetter* ProfileImpl::GetRequestContextForExtensions() {
return io_data_.GetExtensionsRequestContextGetter();
}
+URLRequestContextGetter* ProfileImpl::GetRequestContextForIsolatedApp(
+ const std::string& app_id) {
+ return io_data_.GetIsolatedAppRequestContextGetter(app_id);
+}
+
void ProfileImpl::RegisterExtensionWithRequestContexts(
const Extension* extension) {
BrowserThread::PostTask(
diff --git a/chrome/browser/profiles/profile_impl.h b/chrome/browser/profiles/profile_impl.h
index 4544601..d870dea 100644
--- a/chrome/browser/profiles/profile_impl.h
+++ b/chrome/browser/profiles/profile_impl.h
@@ -86,8 +86,12 @@ class ProfileImpl : public Profile,
virtual BrowserThemeProvider* GetThemeProvider();
virtual bool HasCreatedDownloadManager() const;
virtual URLRequestContextGetter* GetRequestContext();
+ virtual URLRequestContextGetter* GetRequestContextForPossibleApp(
+ const Extension* installed_app);
virtual URLRequestContextGetter* GetRequestContextForMedia();
virtual URLRequestContextGetter* GetRequestContextForExtensions();
+ virtual URLRequestContextGetter* GetRequestContextForIsolatedApp(
+ const std::string& app_id);
virtual void RegisterExtensionWithRequestContexts(const Extension* extension);
virtual void UnregisterExtensionWithRequestContexts(
const Extension* extension);
diff --git a/chrome/browser/profiles/profile_impl_io_data.cc b/chrome/browser/profiles/profile_impl_io_data.cc
index faffcfb..68b853c 100644
--- a/chrome/browser/profiles/profile_impl_io_data.cc
+++ b/chrome/browser/profiles/profile_impl_io_data.cc
@@ -5,7 +5,9 @@
#include "chrome/browser/profiles/profile_impl_io_data.h"
#include "base/command_line.h"
+#include "base/file_util.h"
#include "base/logging.h"
+#include "base/stl_util-inl.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/io_thread.h"
#include "chrome/browser/net/chrome_cookie_policy.h"
@@ -15,6 +17,7 @@
#include "chrome/browser/net/sqlite_persistent_cookie_store.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_switches.h"
+#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "content/browser/browser_thread.h"
#include "net/ftp/ftp_network_layer.h"
@@ -36,6 +39,14 @@ ProfileImplIOData::Handle::~Handle() {
media_request_context_getter_->CleanupOnUIThread();
if (extensions_request_context_getter_)
extensions_request_context_getter_->CleanupOnUIThread();
+
+ // Clean up all isolated app request contexts.
+ for (ChromeURLRequestContextGetterMap::iterator iter =
+ app_request_context_getter_map_.begin();
+ iter != app_request_context_getter_map_.end();
+ ++iter) {
+ iter->second->CleanupOnUIThread();
+ }
}
void ProfileImplIOData::Handle::Init(const FilePath& cookie_path,
@@ -43,7 +54,8 @@ void ProfileImplIOData::Handle::Init(const FilePath& cookie_path,
int cache_max_size,
const FilePath& media_cache_path,
int media_cache_max_size,
- const FilePath& extensions_cookie_path) {
+ const FilePath& extensions_cookie_path,
+ const FilePath& app_path) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(!io_data_->lazy_params_.get());
LazyParams* lazy_params = new LazyParams;
@@ -58,6 +70,9 @@ void ProfileImplIOData::Handle::Init(const FilePath& cookie_path,
lazy_params->io_thread = g_browser_process->io_thread();
io_data_->lazy_params_.reset(lazy_params);
+
+ // Keep track of isolated app path separately so we can use it on demand.
+ io_data_->app_path_ = app_path;
}
scoped_refptr<ChromeURLRequestContextGetter>
@@ -96,9 +111,33 @@ ProfileImplIOData::Handle::GetExtensionsRequestContextGetter() const {
return extensions_request_context_getter_;
}
+scoped_refptr<ChromeURLRequestContextGetter>
+ProfileImplIOData::Handle::GetIsolatedAppRequestContextGetter(
+ const std::string& app_id) const {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(!app_id.empty());
+ LazyInitialize();
+
+ // Keep a map of request context getters, one per requested app ID.
+ ChromeURLRequestContextGetterMap::iterator iter =
+ app_request_context_getter_map_.find(app_id);
+ if (iter != app_request_context_getter_map_.end())
+ return iter->second;
+
+ ChromeURLRequestContextGetter* context =
+ ChromeURLRequestContextGetter::CreateOriginalForIsolatedApp(
+ profile_, io_data_, app_id);
+ app_request_context_getter_map_[app_id] = context;
+
+ return context;
+}
+
void ProfileImplIOData::Handle::LazyInitialize() const {
if (!initialized_) {
InitializeProfileParams(profile_, &io_data_->lazy_params_->profile_params);
+ // Keep track of clear_local_state_on_exit for isolated apps.
+ io_data_->clear_local_state_on_exit_ =
+ io_data_->lazy_params_->profile_params.clear_local_state_on_exit;
initialized_ = true;
}
}
@@ -110,7 +149,9 @@ ProfileImplIOData::LazyParams::LazyParams()
ProfileImplIOData::LazyParams::~LazyParams() {}
ProfileImplIOData::ProfileImplIOData() : ProfileIOData(false) {}
-ProfileImplIOData::~ProfileImplIOData() {}
+ProfileImplIOData::~ProfileImplIOData() {
+ STLDeleteValues(&app_http_factory_map_);
+}
void ProfileImplIOData::LazyInitializeInternal() const {
main_request_context_ = new RequestContext;
@@ -255,6 +296,72 @@ void ProfileImplIOData::LazyInitializeInternal() const {
lazy_params_.reset();
}
+scoped_refptr<ProfileIOData::RequestContext>
+ProfileImplIOData::InitializeAppRequestContext(
+ scoped_refptr<ChromeURLRequestContext> main_context,
+ const std::string& app_id) const {
+ scoped_refptr<ProfileIOData::RequestContext> context = new RequestContext;
+
+ // Copy most state from the main context.
+ context->CopyFrom(main_context);
+
+ FilePath app_path = app_path_.AppendASCII(app_id);
+ FilePath cookie_path = app_path.Append(chrome::kCookieFilename);
+ FilePath cache_path = app_path.Append(chrome::kCacheDirname);
+ // TODO(creis): Determine correct cache size.
+ int cache_max_size = 0;
+
+ const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ bool record_mode = chrome::kRecordModeEnabled &&
+ command_line.HasSwitch(switches::kRecordMode);
+ bool playback_mode = command_line.HasSwitch(switches::kPlaybackMode);
+
+ // Use a separate HTTP disk cache for isolated apps.
+ net::HttpCache::DefaultBackend* app_backend =
+ new net::HttpCache::DefaultBackend(
+ net::DISK_CACHE,
+ cache_path,
+ cache_max_size,
+ BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE));
+ net::HttpNetworkSession* main_network_session =
+ main_http_factory_->GetSession();
+ net::HttpCache* app_http_cache =
+ new net::HttpCache(main_network_session, app_backend);
+
+ scoped_refptr<net::CookieStore> cookie_store = NULL;
+ if (record_mode || playback_mode) {
+ // Don't use existing cookies and use an in-memory store.
+ // TODO(creis): We should have a cookie delegate for notifying the cookie
+ // extensions API, but we need to update it to understand isolated apps
+ // first.
+ cookie_store = new net::CookieMonster(NULL, NULL);
+ app_http_cache->set_mode(
+ record_mode ? net::HttpCache::RECORD : net::HttpCache::PLAYBACK);
+ }
+
+ // Use an app-specific cookie store.
+ if (!cookie_store) {
+ DCHECK(!cookie_path.empty());
+
+ scoped_refptr<SQLitePersistentCookieStore> cookie_db =
+ new SQLitePersistentCookieStore(cookie_path);
+ cookie_db->SetClearLocalStateOnExit(clear_local_state_on_exit_);
+ // TODO(creis): We should have a cookie delegate for notifying the cookie
+ // extensions API, but we need to update it to understand isolated apps
+ // first.
+ cookie_store = new net::CookieMonster(cookie_db.get(), NULL);
+ }
+
+ context->set_cookie_store(cookie_store);
+
+ // Keep track of app_http_cache to delete it when we go away.
+ DCHECK(!app_http_factory_map_[app_id]);
+ app_http_factory_map_[app_id] = app_http_cache;
+ context->set_http_transaction_factory(app_http_cache);
+
+ return context;
+}
+
scoped_refptr<ChromeURLRequestContext>
ProfileImplIOData::AcquireMainRequestContext() const {
DCHECK(main_request_context_);
@@ -281,3 +388,15 @@ ProfileImplIOData::AcquireExtensionsRequestContext() const {
extensions_request_context_ = NULL;
return context;
}
+
+scoped_refptr<ChromeURLRequestContext>
+ProfileImplIOData::AcquireIsolatedAppRequestContext(
+ scoped_refptr<ChromeURLRequestContext> main_context,
+ const std::string& app_id) const {
+ // We create per-app contexts on demand, unlike the others above.
+ scoped_refptr<RequestContext> app_request_context =
+ InitializeAppRequestContext(main_context, app_id);
+ DCHECK(app_request_context);
+ app_request_context->set_profile_io_data(this);
+ return app_request_context;
+}
diff --git a/chrome/browser/profiles/profile_impl_io_data.h b/chrome/browser/profiles/profile_impl_io_data.h
index f7be093..8ab2af1 100644
--- a/chrome/browser/profiles/profile_impl_io_data.h
+++ b/chrome/browser/profiles/profile_impl_io_data.h
@@ -7,6 +7,7 @@
#pragma once
#include "base/basictypes.h"
+#include "base/hash_tables.h"
#include "base/ref_counted.h"
#include "chrome/browser/profiles/profile_io_data.h"
@@ -34,7 +35,8 @@ class ProfileImplIOData : public ProfileIOData {
int cache_max_size,
const FilePath& media_cache_path,
int media_cache_max_size,
- const FilePath& extensions_cookie_path);
+ const FilePath& extensions_cookie_path,
+ const FilePath& app_path);
scoped_refptr<ChromeURLRequestContextGetter>
GetMainRequestContextGetter() const;
@@ -42,8 +44,15 @@ class ProfileImplIOData : public ProfileIOData {
GetMediaRequestContextGetter() const;
scoped_refptr<ChromeURLRequestContextGetter>
GetExtensionsRequestContextGetter() const;
+ scoped_refptr<ChromeURLRequestContextGetter>
+ GetIsolatedAppRequestContextGetter(
+ const std::string& app_id) const;
private:
+ typedef base::hash_map<std::string,
+ scoped_refptr<ChromeURLRequestContextGetter> >
+ ChromeURLRequestContextGetterMap;
+
// Lazily initialize ProfileParams. We do this on the calls to
// Get*RequestContextGetter(), so we only initialize ProfileParams right
// before posting a task to the IO thread to start using them. This prevents
@@ -63,6 +72,7 @@ class ProfileImplIOData : public ProfileIOData {
media_request_context_getter_;
mutable scoped_refptr<ChromeURLRequestContextGetter>
extensions_request_context_getter_;
+ mutable ChromeURLRequestContextGetterMap app_request_context_getter_map_;
const scoped_refptr<ProfileImplIOData> io_data_;
Profile* const profile_;
@@ -91,17 +101,27 @@ class ProfileImplIOData : public ProfileIOData {
ProfileParams profile_params;
};
+ typedef base::hash_map<std::string, net::HttpTransactionFactory* >
+ HttpTransactionFactoryMap;
+
ProfileImplIOData();
virtual ~ProfileImplIOData();
// Lazily initializes ProfileImplIOData.
virtual void LazyInitializeInternal() const;
+ virtual scoped_refptr<RequestContext> InitializeAppRequestContext(
+ scoped_refptr<ChromeURLRequestContext> main_context,
+ const std::string& app_id) const;
virtual scoped_refptr<ChromeURLRequestContext>
AcquireMainRequestContext() const;
virtual scoped_refptr<ChromeURLRequestContext>
AcquireMediaRequestContext() const;
virtual scoped_refptr<ChromeURLRequestContext>
AcquireExtensionsRequestContext() const;
+ virtual scoped_refptr<ChromeURLRequestContext>
+ AcquireIsolatedAppRequestContext(
+ scoped_refptr<ChromeURLRequestContext> main_context,
+ const std::string& app_id) const;
// Lazy initialization params.
mutable scoped_ptr<LazyParams> lazy_params_;
@@ -115,6 +135,13 @@ class ProfileImplIOData : public ProfileIOData {
mutable scoped_ptr<net::HttpTransactionFactory> main_http_factory_;
mutable scoped_ptr<net::HttpTransactionFactory> media_http_factory_;
+ // One HttpTransactionFactory per isolated app.
+ mutable HttpTransactionFactoryMap app_http_factory_map_;
+
+ // Parameters needed for isolated apps.
+ FilePath app_path_;
+ bool clear_local_state_on_exit_;
+
DISALLOW_COPY_AND_ASSIGN(ProfileImplIOData);
};
diff --git a/chrome/browser/profiles/profile_io_data.cc b/chrome/browser/profiles/profile_io_data.cc
index 3d155fe..3720f2d 100644
--- a/chrome/browser/profiles/profile_io_data.cc
+++ b/chrome/browser/profiles/profile_io_data.cc
@@ -229,6 +229,17 @@ ProfileIOData::GetExtensionsRequestContext() const {
return context;
}
+scoped_refptr<ChromeURLRequestContext>
+ProfileIOData::GetIsolatedAppRequestContext(
+ scoped_refptr<ChromeURLRequestContext> main_context,
+ const std::string& app_id) const {
+ LazyInitialize();
+ scoped_refptr<ChromeURLRequestContext> context =
+ AcquireIsolatedAppRequestContext(main_context, app_id);
+ DCHECK(context);
+ return context;
+}
+
void ProfileIOData::LazyInitialize() const {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (initialized_)
diff --git a/chrome/browser/profiles/profile_io_data.h b/chrome/browser/profiles/profile_io_data.h
index 705ca3a..3a2bcd5 100644
--- a/chrome/browser/profiles/profile_io_data.h
+++ b/chrome/browser/profiles/profile_io_data.h
@@ -57,12 +57,15 @@ class DatabaseTracker;
// accessor.
class ProfileIOData : public base::RefCountedThreadSafe<ProfileIOData> {
public:
- // These should only be called at most once each. Ownership is reversed they
- // get called, from ProfileIOData owning ChromeURLRequestContext to vice
+ // These should only be called at most once each. Ownership is reversed when
+ // they get called, from ProfileIOData owning ChromeURLRequestContext to vice
// versa.
scoped_refptr<ChromeURLRequestContext> GetMainRequestContext() const;
scoped_refptr<ChromeURLRequestContext> GetMediaRequestContext() const;
scoped_refptr<ChromeURLRequestContext> GetExtensionsRequestContext() const;
+ scoped_refptr<ChromeURLRequestContext> GetIsolatedAppRequestContext(
+ scoped_refptr<ChromeURLRequestContext> main_context,
+ const std::string& app_id) const;
protected:
friend class base::RefCountedThreadSafe<ProfileIOData>;
@@ -139,10 +142,16 @@ class ProfileIOData : public base::RefCountedThreadSafe<ProfileIOData> {
// Virtual interface for subtypes to implement:
// --------------------------------------------
- // Does that actual initialization of the ProfileIOData subtype. Subtypes
+ // Does the actual initialization of the ProfileIOData subtype. Subtypes
// should use the static helper functions above to implement this.
virtual void LazyInitializeInternal() const = 0;
+ // Does an on-demand initialization of a RequestContext for the given
+ // isolated app.
+ virtual scoped_refptr<RequestContext> InitializeAppRequestContext(
+ scoped_refptr<ChromeURLRequestContext> main_context,
+ const std::string& app_id) const = 0;
+
// These functions are used to transfer ownership of the lazily initialized
// context from ProfileIOData to the URLRequestContextGetter.
virtual scoped_refptr<ChromeURLRequestContext>
@@ -151,6 +160,10 @@ class ProfileIOData : public base::RefCountedThreadSafe<ProfileIOData> {
AcquireMediaRequestContext() const = 0;
virtual scoped_refptr<ChromeURLRequestContext>
AcquireExtensionsRequestContext() const = 0;
+ virtual scoped_refptr<ChromeURLRequestContext>
+ AcquireIsolatedAppRequestContext(
+ scoped_refptr<ChromeURLRequestContext> main_context,
+ const std::string& app_id) const = 0;
mutable bool initialized_;
diff --git a/chrome/browser/renderer_host/browser_render_process_host.cc b/chrome/browser/renderer_host/browser_render_process_host.cc
index e4698c9..fc7ed5c 100644
--- a/chrome/browser/renderer_host/browser_render_process_host.cc
+++ b/chrome/browser/renderer_host/browser_render_process_host.cc
@@ -243,8 +243,10 @@ namespace {
class RendererURLRequestContextOverride
: public ResourceMessageFilter::URLRequestContextOverride {
public:
- explicit RendererURLRequestContextOverride(Profile* profile)
- : request_context_(profile->GetRequestContext()),
+ RendererURLRequestContextOverride(Profile* profile,
+ const Extension* installed_app)
+ : request_context_(profile->GetRequestContextForPossibleApp(
+ installed_app)),
media_request_context_(profile->GetRequestContextForMedia()) {
}
@@ -440,11 +442,13 @@ void BrowserRenderProcessHost::CreateMessageFilters() {
new RenderMessageFilter(id(),
PluginService::GetInstance(),
profile(),
+ profile()->GetRequestContextForPossibleApp(
+ installed_app_),
widget_helper_));
channel_->AddFilter(render_message_filter);
scoped_refptr<RendererURLRequestContextOverride> url_request_context_override(
- new RendererURLRequestContextOverride(profile()));
+ new RendererURLRequestContextOverride(profile(), installed_app_));
ResourceMessageFilter* resource_message_filter = new ResourceMessageFilter(
id(), ChildProcessInfo::RENDER_PROCESS,
diff --git a/chrome/browser/renderer_host/browser_render_process_host.h b/chrome/browser/renderer_host/browser_render_process_host.h
index 8d969d1..23a3384 100644
--- a/chrome/browser/renderer_host/browser_render_process_host.h
+++ b/chrome/browser/renderer_host/browser_render_process_host.h
@@ -16,6 +16,7 @@
#include "base/scoped_callback_factory.h"
#include "base/scoped_ptr.h"
#include "base/timer.h"
+#include "chrome/common/extensions/extension.h"
#include "content/browser/child_process_launcher.h"
#include "content/browser/renderer_host/render_process_host.h"
#include "content/common/notification_observer.h"
@@ -52,6 +53,12 @@ class BrowserRenderProcessHost : public RenderProcessHost,
explicit BrowserRenderProcessHost(Profile* profile);
~BrowserRenderProcessHost();
+ // Whether this process is associated with an installed app.
+ const Extension* installed_app() const { return installed_app_; }
+ void set_installed_app(const Extension* installed_app) {
+ installed_app_ = installed_app;
+ }
+
// RenderProcessHost implementation (public portion).
virtual bool Init(bool is_accessibility_enabled, bool is_extensions_process);
virtual int GetNextRoutingID();
@@ -199,7 +206,10 @@ class BrowserRenderProcessHost : public RenderProcessHost,
// when running in single-process mode.
bool extension_process_;
- // Usedt to launch and terminate the process without blocking the UI thread.
+ // The Extension for the hosted or packaged app if any, NULL otherwise.
+ scoped_refptr<const Extension> installed_app_;
+
+ // Used to launch and terminate the process without blocking the UI thread.
scoped_ptr<ChildProcessLauncher> child_process_;
// Messages we queue while waiting for the process handle. We queue them here
diff --git a/chrome/browser/sidebar/sidebar_container.cc b/chrome/browser/sidebar/sidebar_container.cc
index cab6dc2..529eb8f 100644
--- a/chrome/browser/sidebar/sidebar_container.cc
+++ b/chrome/browser/sidebar/sidebar_container.cc
@@ -6,6 +6,7 @@
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/renderer_host/browser_render_process_host.h"
#include "chrome/common/bindings_policy.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_resource.h"
@@ -32,6 +33,12 @@ SidebarContainer::SidebarContainer(TabContents* tab,
sidebar_contents_.reset(
new TabContents(tab->profile(), NULL, MSG_ROUTING_NONE, NULL, NULL));
sidebar_contents_->render_view_host()->set_is_extension_process(true);
+ const Extension* extension = GetExtension();
+ if (extension && extension->is_app()) {
+ BrowserRenderProcessHost* process = static_cast<BrowserRenderProcessHost*>(
+ sidebar_contents_->render_view_host()->process());
+ process->set_installed_app(extension);
+ }
sidebar_contents_->render_view_host()->AllowBindings(
BindingsPolicy::EXTENSION);
sidebar_contents_->set_delegate(this);
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 16898a7..d958d47 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -203,6 +203,8 @@
'browser/automation/automation_autocomplete_edit_tracker.h',
'browser/automation/automation_browser_tracker.cc',
'browser/automation/automation_browser_tracker.h',
+ 'browser/automation/automation_util.cc',
+ 'browser/automation/automation_util.h',
'browser/automation/automation_extension_function.cc',
'browser/automation/automation_extension_function.h',
'browser/automation/automation_extension_tracker.cc',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index b6b26cab..c41abc7 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -2242,6 +2242,7 @@
'browser/extensions/extension_webrequest_apitest.cc',
'browser/extensions/extension_websocket_apitest.cc',
'browser/extensions/extension_webstore_private_browsertest.cc',
+ 'browser/extensions/isolated_app_apitest.cc',
'browser/extensions/notifications_apitest.cc',
'browser/extensions/page_action_apitest.cc',
'browser/extensions/permissions_apitest.cc',
diff --git a/chrome/common/chrome_constants.cc b/chrome/common/chrome_constants.cc
index f1752c8..0ccf500 100644
--- a/chrome/common/chrome_constants.cc
+++ b/chrome/common/chrome_constants.cc
@@ -84,6 +84,7 @@ const FilePath::CharType kAppCacheDirname[] = FPL("Application Cache");
const FilePath::CharType kThemePackFilename[] = FPL("Cached Theme.pak");
const FilePath::CharType kCookieFilename[] = FPL("Cookies");
const FilePath::CharType kExtensionsCookieFilename[] = FPL("Extension Cookies");
+const FilePath::CharType kIsolatedAppStateDirname[] = FPL("Isolated Apps");
const FilePath::CharType kFaviconsFilename[] = FPL("Favicons");
const FilePath::CharType kHistoryFilename[] = FPL("History");
const FilePath::CharType kLocalStateFilename[] = FPL("Local State");
diff --git a/chrome/common/chrome_constants.h b/chrome/common/chrome_constants.h
index 5a4befc..0070a0f 100644
--- a/chrome/common/chrome_constants.h
+++ b/chrome/common/chrome_constants.h
@@ -46,6 +46,7 @@ extern const FilePath::CharType kAppCacheDirname[];
extern const FilePath::CharType kThemePackFilename[];
extern const FilePath::CharType kCookieFilename[];
extern const FilePath::CharType kExtensionsCookieFilename[];
+extern const FilePath::CharType kIsolatedAppStateDirname[];
extern const FilePath::CharType kFaviconsFilename[];
extern const FilePath::CharType kHistoryFilename[];
extern const FilePath::CharType kLocalStateFilename[];
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index ea8c178..a323cc3 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -457,6 +457,10 @@ const char kEnableDNSCertProvenanceChecking[] =
const char kEnableDNSSECCerts[] = "enable-dnssec-certs";
+// Enables app manifest features that are in development.
+const char kEnableExperimentalAppManifests[] =
+ "enable-experimental-app-manifests";
+
// Enables extension APIs that are in development.
const char kEnableExperimentalExtensionApis[] =
"enable-experimental-extension-apis";
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index a8d9fea..e297a72 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -139,6 +139,7 @@ extern const char kEnableDataTransferItems[];
extern const char kEnableDeviceMotion[];
extern const char kEnableDNSCertProvenanceChecking[];
extern const char kEnableDNSSECCerts[];
+extern const char kEnableExperimentalAppManifests[];
extern const char kEnableExperimentalExtensionApis[];
extern const char kEnableExtensionTimelineApi[];
extern const char kEnableFastback[];
diff --git a/chrome/common/extensions/extension.cc b/chrome/common/extensions/extension.cc
index 0be0dbc..c86ba40 100644
--- a/chrome/common/extensions/extension.cc
+++ b/chrome/common/extensions/extension.cc
@@ -1140,6 +1140,43 @@ bool Extension::LoadLaunchContainer(const DictionaryValue* manifest,
return true;
}
+bool Extension::LoadAppIsolation(const DictionaryValue* manifest,
+ std::string* error) {
+ // Only parse app isolation features if this switch is present.
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableExperimentalAppManifests))
+ return true;
+
+ Value* temp = NULL;
+ if (!manifest->Get(keys::kIsolation, &temp))
+ return true;
+
+ if (temp->GetType() != Value::TYPE_LIST) {
+ *error = errors::kInvalidIsolation;
+ return false;
+ }
+
+ ListValue* isolation_list = static_cast<ListValue*>(temp);
+ for (size_t i = 0; i < isolation_list->GetSize(); ++i) {
+ std::string isolation_string;
+ if (!isolation_list->GetString(i, &isolation_string)) {
+ *error = ExtensionErrorUtils::FormatErrorMessage(
+ errors::kInvalidIsolationValue,
+ base::UintToString(i));
+ return false;
+ }
+
+ // Check for isolated storage.
+ if (isolation_string == values::kIsolatedStorage) {
+ is_storage_isolated_ = true;
+ } else {
+ LOG(WARNING) << "Did not recognize isolation type: "
+ << isolation_string;
+ }
+ }
+ return true;
+}
+
bool Extension::EnsureNotHybridApp(const DictionaryValue* manifest,
std::string* error) {
if (web_extent().is_empty())
@@ -1165,6 +1202,7 @@ Extension::Extension(const FilePath& path, Location location)
converted_from_user_script_(false),
is_theme_(false),
is_app_(false),
+ is_storage_isolated_(false),
launch_container_(extension_misc::LAUNCH_TAB),
launch_width_(0),
launch_height_(0) {
@@ -1803,7 +1841,8 @@ bool Extension::InitFromValue(const DictionaryValue& source, bool require_key,
parse_strictness, error) ||
!EnsureNotHybridApp(manifest_value_.get(), error) ||
!LoadLaunchURL(manifest_value_.get(), error) ||
- !LoadLaunchContainer(manifest_value_.get(), error)) {
+ !LoadLaunchContainer(manifest_value_.get(), error) ||
+ !LoadAppIsolation(manifest_value_.get(), error)) {
return false;
}
diff --git a/chrome/common/extensions/extension.h b/chrome/common/extensions/extension.h
index 7e2b593..5f934f3 100644
--- a/chrome/common/extensions/extension.h
+++ b/chrome/common/extensions/extension.h
@@ -483,6 +483,7 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
bool is_app() const { return is_app_; }
bool is_hosted_app() const { return is_app() && !web_extent().is_empty(); }
bool is_packaged_app() const { return is_app() && web_extent().is_empty(); }
+ bool is_storage_isolated() const { return is_app() && is_storage_isolated_; }
const ExtensionExtent& web_extent() const { return extent_; }
const std::string& launch_local_path() const { return launch_local_path_; }
const std::string& launch_web_url() const { return launch_web_url_; }
@@ -574,6 +575,7 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
std::string* error);
bool LoadLaunchContainer(const DictionaryValue* manifest, std::string* error);
bool LoadLaunchURL(const DictionaryValue* manifest, std::string* error);
+ bool LoadAppIsolation(const DictionaryValue* manifest, std::string* error);
bool EnsureNotHybridApp(const DictionaryValue* manifest, std::string* error);
// Helper method to load an ExtensionAction from the page_action or
@@ -736,6 +738,9 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
// Whether this extension uses app features.
bool is_app_;
+ // Whether this extension requests isolated storage.
+ bool is_storage_isolated_;
+
// The local path inside the extension to use with the launcher.
std::string launch_local_path_;
diff --git a/chrome/common/extensions/extension_constants.cc b/chrome/common/extensions/extension_constants.cc
index 96fd349..0facbf9 100644
--- a/chrome/common/extensions/extension_constants.cc
+++ b/chrome/common/extensions/extension_constants.cc
@@ -23,6 +23,7 @@ const char* kHomepageURL = "homepage_url";
const char* kIcons = "icons";
const char* kIncognito = "incognito";
const char* kIncludeGlobs = "include_globs";
+const char* kIsolation = "app.isolation";
const char* kJs = "js";
const char* kLaunch = "app.launch";
const char* kLaunchContainer = "app.launch.container";
@@ -80,6 +81,7 @@ const char* kWebURLs = "app.urls";
namespace extension_manifest_values {
const char* kIncognitoSplit = "split";
const char* kIncognitoSpanning = "spanning";
+const char* kIsolatedStorage = "storage";
const char* kRunAtDocumentStart = "document_start";
const char* kRunAtDocumentEnd = "document_end";
const char* kRunAtDocumentIdle = "document_idle";
@@ -153,6 +155,10 @@ const char* kInvalidIcons =
"Invalid value for 'icons'.";
const char* kInvalidIncognitoBehavior =
"Invalid value for 'incognito'.";
+const char* kInvalidIsolation =
+ "Invalid value for 'app.isolation'.";
+const char* kInvalidIsolationValue =
+ "Invalid value for 'app.isolation[*]'.";
const char* kInvalidJs =
"Invalid value for 'content_scripts[*].js[*]'.";
const char* kInvalidJsList =
diff --git a/chrome/common/extensions/extension_constants.h b/chrome/common/extensions/extension_constants.h
index bad2a5b..3e8e130 100644
--- a/chrome/common/extensions/extension_constants.h
+++ b/chrome/common/extensions/extension_constants.h
@@ -28,6 +28,7 @@ namespace extension_manifest_keys {
extern const char* kIcons;
extern const char* kIncognito;
extern const char* kIncludeGlobs;
+ extern const char* kIsolation;
extern const char* kJs;
extern const char* kLaunch;
extern const char* kLaunchContainer;
@@ -86,6 +87,7 @@ namespace extension_manifest_keys {
namespace extension_manifest_values {
extern const char* kIncognitoSplit;
extern const char* kIncognitoSpanning;
+ extern const char* kIsolatedStorage;
extern const char* kLaunchContainerPanel;
extern const char* kLaunchContainerTab;
extern const char* kLaunchContainerWindow;
@@ -128,6 +130,8 @@ namespace extension_manifest_errors {
extern const char* kInvalidIconPath;
extern const char* kInvalidIcons;
extern const char* kInvalidIncognitoBehavior;
+ extern const char* kInvalidIsolation;
+ extern const char* kInvalidIsolationValue;
extern const char* kInvalidJs;
extern const char* kInvalidJsList;
extern const char* kInvalidKey;
diff --git a/chrome/common/extensions/extension_manifests_unittest.cc b/chrome/common/extensions/extension_manifests_unittest.cc
index 63172a9..91951ea 100644
--- a/chrome/common/extensions/extension_manifests_unittest.cc
+++ b/chrome/common/extensions/extension_manifests_unittest.cc
@@ -547,3 +547,18 @@ TEST_F(ExtensionManifestTest, ForbidPortsInPermissions) {
// to flag this case.
LoadStrictAndExpectSuccess("forbid_ports_in_permissions.json");
}
+
+TEST_F(ExtensionManifestTest, IsolatedApps) {
+ // Requires --enable-experimental-app-manifests
+ scoped_refptr<Extension> extension(
+ LoadAndExpectSuccess("isolated_app_valid.json"));
+ EXPECT_FALSE(extension->is_storage_isolated());
+
+ CommandLine old_command_line = *CommandLine::ForCurrentProcess();
+ CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableExperimentalAppManifests);
+ scoped_refptr<Extension> extension2(
+ LoadAndExpectSuccess("isolated_app_valid.json"));
+ EXPECT_TRUE(extension2->is_storage_isolated());
+ *CommandLine::ForCurrentProcess() = old_command_line;
+}
diff --git a/chrome/test/data/extensions/api_test/app_process/manifest.json b/chrome/test/data/extensions/api_test/app_process/manifest.json
index 2e35457..42a95fc 100644
--- a/chrome/test/data/extensions/api_test/app_process/manifest.json
+++ b/chrome/test/data/extensions/api_test/app_process/manifest.json
@@ -11,7 +11,7 @@
"http://localhost/files/extensions/api_test/app_process/path4"
],
"launch": {
- "web_url": "http://localhost:1337/files/extensions/api_test/app_process/path1/foo.html"
+ "web_url": "http://localhost/files/extensions/api_test/app_process/path1/foo.html"
}
}
}
diff --git a/chrome/test/data/extensions/api_test/isolated_apps/app1/main.html b/chrome/test/data/extensions/api_test/isolated_apps/app1/main.html
new file mode 100644
index 0000000..427902c
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/isolated_apps/app1/main.html
@@ -0,0 +1,15 @@
+<html>
+<body>
+Isolated App 1
+
+<script>
+ // Set a cookie within the app.
+ var expire = new Date();
+ expire.setDate(expire.getDate() + 1); // tomorrow
+ document.cookie = "app1=3; path=/; expires=" + expire + ";"
+</script>
+
+<!-- Include an iframe to a non-app URL. -->
+<iframe src="../non_app/subframe.html"></iframe>
+</body>
+</html>
diff --git a/chrome/test/data/extensions/api_test/isolated_apps/app1/manifest.json b/chrome/test/data/extensions/api_test/isolated_apps/app1/manifest.json
new file mode 100644
index 0000000..2ef8d1c
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/isolated_apps/app1/manifest.json
@@ -0,0 +1,16 @@
+{
+ "name": "isolated_app1",
+ "version": "0.1",
+ "description": "Tests isolation of stored data for apps.",
+ "app": {
+ "urls": [
+ "http://localhost/files/extensions/api_test/isolated_apps/app1"
+ ],
+ "launch": {
+ "web_url": "http://localhost/files/extensions/api_test/isolated_apps/app1/main.html"
+ },
+ "isolation": [
+ "storage"
+ ]
+ }
+}
diff --git a/chrome/test/data/extensions/api_test/isolated_apps/app2/main.html b/chrome/test/data/extensions/api_test/isolated_apps/app2/main.html
new file mode 100644
index 0000000..506e874
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/isolated_apps/app2/main.html
@@ -0,0 +1,12 @@
+<html>
+<body>
+Isolated App 2
+
+<script>
+ // Set a cookie within the app.
+ var expire = new Date();
+ expire.setDate(expire.getDate() + 1); // tomorrow
+ document.cookie = "app2=4; path=/; expires=" + expire + ";"
+</script>
+</body>
+</html>
diff --git a/chrome/test/data/extensions/api_test/isolated_apps/app2/manifest.json b/chrome/test/data/extensions/api_test/isolated_apps/app2/manifest.json
new file mode 100644
index 0000000..5ce184c
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/isolated_apps/app2/manifest.json
@@ -0,0 +1,16 @@
+{
+ "name": "isolated_app2",
+ "version": "0.1",
+ "description": "Tests isolation of stored data for apps.",
+ "app": {
+ "urls": [
+ "http://localhost/files/extensions/api_test/isolated_apps/app2"
+ ],
+ "launch": {
+ "web_url": "http://localhost/files/extensions/api_test/isolated_apps/app2/main.html"
+ },
+ "isolation": [
+ "storage"
+ ]
+ }
+}
diff --git a/chrome/test/data/extensions/api_test/isolated_apps/non_app/main.html b/chrome/test/data/extensions/api_test/isolated_apps/non_app/main.html
new file mode 100644
index 0000000..ab8c9b31
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/isolated_apps/non_app/main.html
@@ -0,0 +1,12 @@
+<html>
+<body>
+Normal page
+
+<script>
+ // Set a cookie outside any apps.
+ var expire = new Date();
+ expire.setDate(expire.getDate() + 1); // tomorrow
+ document.cookie = "normalPage=5; path=/; expires=" + expire + ";"
+</script>
+</body>
+</html>
diff --git a/chrome/test/data/extensions/api_test/isolated_apps/non_app/subframe.html b/chrome/test/data/extensions/api_test/isolated_apps/non_app/subframe.html
new file mode 100644
index 0000000..41fb7e7
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/isolated_apps/non_app/subframe.html
@@ -0,0 +1,12 @@
+<html>
+<body>
+Normal page
+
+<script>
+ // Set a cookie from a page in an iframe.
+ var expire = new Date();
+ expire.setDate(expire.getDate() + 1); // tomorrow
+ document.cookie = "nonAppFrame=6; path=/; expires=" + expire + ";"
+</script>
+</body>
+</html>
diff --git a/chrome/test/data/extensions/manifest_tests/isolated_app_valid.json b/chrome/test/data/extensions/manifest_tests/isolated_app_valid.json
new file mode 100644
index 0000000..eb2ccb0
--- /dev/null
+++ b/chrome/test/data/extensions/manifest_tests/isolated_app_valid.json
@@ -0,0 +1,15 @@
+{
+ "name": "test",
+ "version": "1",
+ "app": {
+ "urls": [
+ "http://www.google.com/mail/"
+ ],
+ "launch": {
+ "web_url": "http://www.google.com/mail/"
+ },
+ "isolation": [
+ "storage"
+ ]
+ }
+}
diff --git a/chrome/test/testing_profile.cc b/chrome/test/testing_profile.cc
index 2534ef0..a348337 100644
--- a/chrome/test/testing_profile.cc
+++ b/chrome/test/testing_profile.cc
@@ -563,6 +563,14 @@ URLRequestContextGetter* TestingProfile::GetRequestContext() {
return request_context_.get();
}
+URLRequestContextGetter* TestingProfile::GetRequestContextForPossibleApp(
+ const Extension* installed_app) {
+ if (installed_app != NULL && installed_app->is_storage_isolated())
+ return GetRequestContextForIsolatedApp(installed_app->id());
+
+ return GetRequestContext();
+}
+
void TestingProfile::CreateRequestContext() {
if (!request_context_)
request_context_ = new TestURLRequestContextGetter();
@@ -590,6 +598,13 @@ UserStyleSheetWatcher* TestingProfile::GetUserStyleSheetWatcher() {
return NULL;
}
+URLRequestContextGetter* TestingProfile::GetRequestContextForIsolatedApp(
+ const std::string& app_id) {
+ // We don't test isolated app storage here yet, so returning the same dummy
+ // context is sufficient for now.
+ return GetRequestContext();
+}
+
FindBarState* TestingProfile::GetFindBarState() {
if (!find_bar_state_.get())
find_bar_state_.reset(new FindBarState());
diff --git a/chrome/test/testing_profile.h b/chrome/test/testing_profile.h
index 49063b5..3ae70ba 100644
--- a/chrome/test/testing_profile.h
+++ b/chrome/test/testing_profile.h
@@ -201,6 +201,8 @@ class TestingProfile : public Profile {
// getter is currently only capable of returning a Context that helps test
// the CookieMonster. See implementation comments for more details.
virtual URLRequestContextGetter* GetRequestContext();
+ virtual URLRequestContextGetter* GetRequestContextForPossibleApp(
+ const Extension* installed_app);
void CreateRequestContext();
// Clears out the created request context (which must be done before shutting
// down the IO thread to avoid leaks).
@@ -208,6 +210,8 @@ class TestingProfile : public Profile {
virtual URLRequestContextGetter* GetRequestContextForMedia();
virtual URLRequestContextGetter* GetRequestContextForExtensions();
+ virtual URLRequestContextGetter* GetRequestContextForIsolatedApp(
+ const std::string& app_id);
virtual net::SSLConfigService* GetSSLConfigService();
virtual UserStyleSheetWatcher* GetUserStyleSheetWatcher();
diff --git a/content/browser/renderer_host/render_message_filter.cc b/content/browser/renderer_host/render_message_filter.cc
index 0c5c83a..7683d4f 100644
--- a/content/browser/renderer_host/render_message_filter.cc
+++ b/content/browser/renderer_host/render_message_filter.cc
@@ -279,11 +279,13 @@ RenderMessageFilter::RenderMessageFilter(
int render_process_id,
PluginService* plugin_service,
Profile* profile,
+ URLRequestContextGetter* request_context,
RenderWidgetHelper* render_widget_helper)
: resource_dispatcher_host_(g_browser_process->resource_dispatcher_host()),
plugin_service_(plugin_service),
profile_(profile),
content_settings_(profile->GetHostContentSettingsMap()),
+ request_context_(request_context),
extensions_request_context_(profile->GetRequestContextForExtensions()),
render_widget_helper_(render_widget_helper),
notification_prefs_(
@@ -292,7 +294,6 @@ RenderMessageFilter::RenderMessageFilter(
off_the_record_(profile->IsOffTheRecord()),
webkit_context_(profile->GetWebKitContext()),
render_process_id_(render_process_id) {
- request_context_ = profile_->GetRequestContext();
DCHECK(request_context_);
render_widget_helper_->Init(render_process_id_, resource_dispatcher_host_);
diff --git a/content/browser/renderer_host/render_message_filter.h b/content/browser/renderer_host/render_message_filter.h
index ab6ba38..18b35df 100644
--- a/content/browser/renderer_host/render_message_filter.h
+++ b/content/browser/renderer_host/render_message_filter.h
@@ -61,6 +61,7 @@ class RenderMessageFilter : public BrowserMessageFilter {
RenderMessageFilter(int render_process_id,
PluginService* plugin_service,
Profile* profile,
+ URLRequestContextGetter* request_context,
RenderWidgetHelper* render_widget_helper);
// BrowserMessageFilter methods:
diff --git a/net/url_request/url_request_context.cc b/net/url_request/url_request_context.cc
index 2f558cc..7e02641 100644
--- a/net/url_request/url_request_context.cc
+++ b/net/url_request/url_request_context.cc
@@ -27,6 +27,29 @@ URLRequestContext::URLRequestContext()
ftp_transaction_factory_(NULL) {
}
+void URLRequestContext::CopyFrom(URLRequestContext* other) {
+ // Copy URLRequestContext parameters.
+ // Do not copy is_main_.
+ set_net_log(other->net_log());
+ set_host_resolver(other->host_resolver());
+ set_cert_verifier(other->cert_verifier());
+ set_dnsrr_resolver(other->dnsrr_resolver());
+ set_dns_cert_checker(other->dns_cert_checker());
+ set_http_auth_handler_factory(other->http_auth_handler_factory());
+ set_proxy_service(other->proxy_service());
+ set_ssl_config_service(other->ssl_config_service());
+ set_network_delegate(other->network_delegate());
+ set_cookie_store(other->cookie_store());
+ set_cookie_policy(other->cookie_policy());
+ set_transport_security_state(other->transport_security_state());
+ // FTPAuthCache is unique per context.
+ set_accept_language(other->accept_language());
+ set_accept_charset(other->accept_charset());
+ set_referrer_charset(other->referrer_charset());
+ set_http_transaction_factory(other->http_transaction_factory());
+ set_ftp_transaction_factory(other->ftp_transaction_factory());
+}
+
void URLRequestContext::set_cookie_store(CookieStore* cookie_store) {
cookie_store_ = cookie_store;
}
diff --git a/net/url_request/url_request_context.h b/net/url_request/url_request_context.h
index 7976126..63e069a 100644
--- a/net/url_request/url_request_context.h
+++ b/net/url_request/url_request_context.h
@@ -44,6 +44,9 @@ class URLRequestContext
public:
URLRequestContext();
+ // Copies the state from |other| into this context.
+ void CopyFrom(URLRequestContext* other);
+
NetLog* net_log() const {
return net_log_;
}
@@ -183,6 +186,11 @@ class URLRequestContext
virtual ~URLRequestContext();
private:
+ // ---------------------------------------------------------------------------
+ // Important: When adding any new members below, consider whether they need to
+ // be added to CopyFrom.
+ // ---------------------------------------------------------------------------
+
// Indicates whether or not this is the main URLRequestContext.
bool is_main_;
@@ -211,6 +219,11 @@ class URLRequestContext
HttpTransactionFactory* http_transaction_factory_;
FtpTransactionFactory* ftp_transaction_factory_;
+ // ---------------------------------------------------------------------------
+ // Important: When adding any new members below, consider whether they need to
+ // be added to CopyFrom.
+ // ---------------------------------------------------------------------------
+
DISALLOW_COPY_AND_ASSIGN(URLRequestContext);
};