Commit 3dbc36e7 authored by falken's avatar falken Committed by Commit bot

Respect content settings for Service Worker registration

Add an AllowServiceWorker setting and use it when registering/unregistering
a Service Worker.

BUG=419277

Review URL: https://codereview.chromium.org/625533002

Cr-Commit-Position: refs/heads/master@{#299127}
parent 42868761
...@@ -1460,6 +1460,16 @@ bool ChromeContentBrowserClient::AllowAppCache( ...@@ -1460,6 +1460,16 @@ bool ChromeContentBrowserClient::AllowAppCache(
IsSettingCookieAllowed(manifest_url, first_party); IsSettingCookieAllowed(manifest_url, first_party);
} }
bool ChromeContentBrowserClient::AllowServiceWorker(
const GURL& scope,
const GURL& first_party_url,
content::ResourceContext* context) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
ProfileIOData* io_data = ProfileIOData::FromResourceContext(context);
return io_data->GetCookieSettings()->
IsSettingCookieAllowed(scope, first_party_url);
}
bool ChromeContentBrowserClient::AllowGetCookie( bool ChromeContentBrowserClient::AllowGetCookie(
const GURL& url, const GURL& url,
const GURL& first_party, const GURL& first_party,
......
...@@ -123,6 +123,9 @@ class ChromeContentBrowserClient : public content::ContentBrowserClient { ...@@ -123,6 +123,9 @@ class ChromeContentBrowserClient : public content::ContentBrowserClient {
virtual bool AllowAppCache(const GURL& manifest_url, virtual bool AllowAppCache(const GURL& manifest_url,
const GURL& first_party, const GURL& first_party,
content::ResourceContext* context) OVERRIDE; content::ResourceContext* context) OVERRIDE;
virtual bool AllowServiceWorker(const GURL& scope,
const GURL& first_party,
content::ResourceContext* context) OVERRIDE;
virtual bool AllowGetCookie(const GURL& url, virtual bool AllowGetCookie(const GURL& url,
const GURL& first_party, const GURL& first_party,
const net::CookieList& cookie_list, const net::CookieList& cookie_list,
......
...@@ -838,8 +838,8 @@ void RenderProcessHostImpl::CreateMessageFilters() { ...@@ -838,8 +838,8 @@ void RenderProcessHostImpl::CreateMessageFilters() {
AddFilter(message_port_message_filter_.get()); AddFilter(message_port_message_filter_.get());
scoped_refptr<ServiceWorkerDispatcherHost> service_worker_filter = scoped_refptr<ServiceWorkerDispatcherHost> service_worker_filter =
new ServiceWorkerDispatcherHost(GetID(), new ServiceWorkerDispatcherHost(
message_port_message_filter_.get()); GetID(), message_port_message_filter_.get(), resource_context);
service_worker_filter->Init( service_worker_filter->Init(
storage_partition_impl_->GetServiceWorkerContext()); storage_partition_impl_->GetServiceWorkerContext());
AddFilter(service_worker_filter.get()); AddFilter(service_worker_filter.get());
......
...@@ -94,7 +94,7 @@ net::URLRequestJob* ServiceWorkerControlleeRequestHandler::MaybeCreateJob( ...@@ -94,7 +94,7 @@ net::URLRequestJob* ServiceWorkerControlleeRequestHandler::MaybeCreateJob(
frame_type_, frame_type_,
body_); body_);
if (is_main_resource_load_) if (is_main_resource_load_)
PrepareForMainResource(request->url()); PrepareForMainResource(request);
else else
PrepareForSubResource(); PrepareForSubResource();
...@@ -131,7 +131,7 @@ void ServiceWorkerControlleeRequestHandler::GetExtraResponseInfo( ...@@ -131,7 +131,7 @@ void ServiceWorkerControlleeRequestHandler::GetExtraResponseInfo(
} }
void ServiceWorkerControlleeRequestHandler::PrepareForMainResource( void ServiceWorkerControlleeRequestHandler::PrepareForMainResource(
const GURL& url) { const net::URLRequest* request) {
DCHECK(job_.get()); DCHECK(job_.get());
DCHECK(context_); DCHECK(context_);
DCHECK(provider_host_); DCHECK(provider_host_);
...@@ -139,7 +139,7 @@ void ServiceWorkerControlleeRequestHandler::PrepareForMainResource( ...@@ -139,7 +139,7 @@ void ServiceWorkerControlleeRequestHandler::PrepareForMainResource(
"ServiceWorker", "ServiceWorker",
"ServiceWorkerControlleeRequestHandler::PrepareForMainResource", "ServiceWorkerControlleeRequestHandler::PrepareForMainResource",
job_.get(), job_.get(),
"URL", url.spec()); "URL", request->url().spec());
// The corresponding provider_host may already have associated a registration // The corresponding provider_host may already have associated a registration
// in redirect case, unassociate it now. // in redirect case, unassociate it now.
provider_host_->DisassociateRegistration(); provider_host_->DisassociateRegistration();
...@@ -148,8 +148,9 @@ void ServiceWorkerControlleeRequestHandler::PrepareForMainResource( ...@@ -148,8 +148,9 @@ void ServiceWorkerControlleeRequestHandler::PrepareForMainResource(
// registration while we're finding an existing registration. // registration while we're finding an existing registration.
provider_host_->SetAllowAssociation(false); provider_host_->SetAllowAssociation(false);
GURL stripped_url = net::SimplifyUrlForRequest(url); GURL stripped_url = net::SimplifyUrlForRequest(request->url());
provider_host_->SetDocumentUrl(stripped_url); provider_host_->SetDocumentUrl(stripped_url);
provider_host_->SetTopmostFrameUrl(request->first_party_for_cookies());
context_->storage()->FindRegistrationForDocument( context_->storage()->FindRegistrationForDocument(
stripped_url, stripped_url,
base::Bind(&self::DidLookupRegistrationForMainResource, base::Bind(&self::DidLookupRegistrationForMainResource,
......
...@@ -60,7 +60,7 @@ class CONTENT_EXPORT ServiceWorkerControlleeRequestHandler ...@@ -60,7 +60,7 @@ class CONTENT_EXPORT ServiceWorkerControlleeRequestHandler
typedef ServiceWorkerControlleeRequestHandler self; typedef ServiceWorkerControlleeRequestHandler self;
// For main resource case. // For main resource case.
void PrepareForMainResource(const GURL& url); void PrepareForMainResource(const net::URLRequest* request);
void DidLookupRegistrationForMainResource( void DidLookupRegistrationForMainResource(
ServiceWorkerStatusCode status, ServiceWorkerStatusCode status,
const scoped_refptr<ServiceWorkerRegistration>& registration); const scoped_refptr<ServiceWorkerRegistration>& registration);
......
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
#include "content/browser/service_worker/service_worker_utils.h" #include "content/browser/service_worker/service_worker_utils.h"
#include "content/common/service_worker/embedded_worker_messages.h" #include "content/common/service_worker/embedded_worker_messages.h"
#include "content/common/service_worker/service_worker_messages.h" #include "content/common/service_worker/service_worker_messages.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/common/content_client.h"
#include "ipc/ipc_message_macros.h" #include "ipc/ipc_message_macros.h"
#include "net/base/net_util.h" #include "net/base/net_util.h"
#include "third_party/WebKit/public/platform/WebServiceWorkerError.h" #include "third_party/WebKit/public/platform/WebServiceWorkerError.h"
...@@ -31,6 +33,7 @@ namespace { ...@@ -31,6 +33,7 @@ namespace {
const char kShutdownErrorMessage[] = const char kShutdownErrorMessage[] =
"The Service Worker system has shutdown."; "The Service Worker system has shutdown.";
const char kDisabledErrorMessage[] = "The browser has disabled Service Worker.";
const uint32 kFilteredMessageClasses[] = { const uint32 kFilteredMessageClasses[] = {
ServiceWorkerMsgStart, ServiceWorkerMsgStart,
...@@ -52,24 +55,18 @@ bool OriginCanAccessServiceWorkers(const GURL& url) { ...@@ -52,24 +55,18 @@ bool OriginCanAccessServiceWorkers(const GURL& url) {
bool CanRegisterServiceWorker(const GURL& document_url, bool CanRegisterServiceWorker(const GURL& document_url,
const GURL& pattern, const GURL& pattern,
const GURL& script_url) { const GURL& script_url) {
// TODO: Respect Chrome's content settings, if we add a setting for
// controlling whether Service Worker is allowed.
return AllOriginsMatch(document_url, pattern, script_url) && return AllOriginsMatch(document_url, pattern, script_url) &&
OriginCanAccessServiceWorkers(document_url); OriginCanAccessServiceWorkers(document_url);
} }
bool CanUnregisterServiceWorker(const GURL& document_url, bool CanUnregisterServiceWorker(const GURL& document_url,
const GURL& pattern) { const GURL& pattern) {
// TODO: Respect Chrome's content settings, if we add a setting for
// controlling whether Service Worker is allowed.
return document_url.GetOrigin() == pattern.GetOrigin() && return document_url.GetOrigin() == pattern.GetOrigin() &&
OriginCanAccessServiceWorkers(document_url); OriginCanAccessServiceWorkers(document_url);
} }
bool CanGetRegistration(const GURL& document_url, bool CanGetRegistration(const GURL& document_url,
const GURL& given_document_url) { const GURL& given_document_url) {
// TODO: Respect Chrome's content settings, if we add a setting for
// controlling whether Service Worker is allowed.
return document_url.GetOrigin() == given_document_url.GetOrigin() && return document_url.GetOrigin() == given_document_url.GetOrigin() &&
OriginCanAccessServiceWorkers(document_url); OriginCanAccessServiceWorkers(document_url);
} }
...@@ -78,11 +75,13 @@ bool CanGetRegistration(const GURL& document_url, ...@@ -78,11 +75,13 @@ bool CanGetRegistration(const GURL& document_url,
ServiceWorkerDispatcherHost::ServiceWorkerDispatcherHost( ServiceWorkerDispatcherHost::ServiceWorkerDispatcherHost(
int render_process_id, int render_process_id,
MessagePortMessageFilter* message_port_message_filter) MessagePortMessageFilter* message_port_message_filter,
ResourceContext* resource_context)
: BrowserMessageFilter(kFilteredMessageClasses, : BrowserMessageFilter(kFilteredMessageClasses,
arraysize(kFilteredMessageClasses)), arraysize(kFilteredMessageClasses)),
render_process_id_(render_process_id), render_process_id_(render_process_id),
message_port_message_filter_(message_port_message_filter), message_port_message_filter_(message_port_message_filter),
resource_context_(resource_context),
channel_ready_(false) { channel_ready_(false) {
} }
...@@ -258,6 +257,17 @@ void ServiceWorkerDispatcherHost::OnRegisterServiceWorker( ...@@ -258,6 +257,17 @@ void ServiceWorkerDispatcherHost::OnRegisterServiceWorker(
BadMessageReceived(); BadMessageReceived();
return; return;
} }
if (!GetContentClient()->browser()->AllowServiceWorker(
pattern, provider_host->topmost_frame_url(), resource_context_)) {
Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
thread_id,
request_id,
WebServiceWorkerError::ErrorTypeDisabled,
base::ASCIIToUTF16(kDisabledErrorMessage)));
return;
}
TRACE_EVENT_ASYNC_BEGIN2("ServiceWorker", TRACE_EVENT_ASYNC_BEGIN2("ServiceWorker",
"ServiceWorkerDispatcherHost::RegisterServiceWorker", "ServiceWorkerDispatcherHost::RegisterServiceWorker",
request_id, request_id,
...@@ -310,6 +320,16 @@ void ServiceWorkerDispatcherHost::OnUnregisterServiceWorker( ...@@ -310,6 +320,16 @@ void ServiceWorkerDispatcherHost::OnUnregisterServiceWorker(
return; return;
} }
if (!GetContentClient()->browser()->AllowServiceWorker(
pattern, provider_host->topmost_frame_url(), resource_context_)) {
Send(new ServiceWorkerMsg_ServiceWorkerUnregistrationError(
thread_id,
request_id,
WebServiceWorkerError::ErrorTypeDisabled,
base::ASCIIToUTF16(kDisabledErrorMessage)));
return;
}
TRACE_EVENT_ASYNC_BEGIN1( TRACE_EVENT_ASYNC_BEGIN1(
"ServiceWorker", "ServiceWorker",
"ServiceWorkerDispatcherHost::UnregisterServiceWorker", "ServiceWorkerDispatcherHost::UnregisterServiceWorker",
...@@ -359,6 +379,18 @@ void ServiceWorkerDispatcherHost::OnGetRegistration( ...@@ -359,6 +379,18 @@ void ServiceWorkerDispatcherHost::OnGetRegistration(
return; return;
} }
if (!GetContentClient()->browser()->AllowServiceWorker(
provider_host->document_url(),
provider_host->topmost_frame_url(),
resource_context_)) {
Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationError(
thread_id,
request_id,
WebServiceWorkerError::ErrorTypeDisabled,
base::ASCIIToUTF16(kDisabledErrorMessage)));
return;
}
DCHECK_CURRENTLY_ON(BrowserThread::IO); DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (GetContext()->storage()->IsDisabled()) { if (GetContext()->storage()->IsDisabled()) {
SendGetRegistrationError(thread_id, request_id, SERVICE_WORKER_ERROR_ABORT); SendGetRegistrationError(thread_id, request_id, SERVICE_WORKER_ERROR_ABORT);
......
...@@ -19,6 +19,7 @@ struct EmbeddedWorkerHostMsg_ReportConsoleMessage_Params; ...@@ -19,6 +19,7 @@ struct EmbeddedWorkerHostMsg_ReportConsoleMessage_Params;
namespace content { namespace content {
class MessagePortMessageFilter; class MessagePortMessageFilter;
class ResourceContext;
class ServiceWorkerContextCore; class ServiceWorkerContextCore;
class ServiceWorkerContextWrapper; class ServiceWorkerContextWrapper;
class ServiceWorkerHandle; class ServiceWorkerHandle;
...@@ -32,7 +33,8 @@ class CONTENT_EXPORT ServiceWorkerDispatcherHost : public BrowserMessageFilter { ...@@ -32,7 +33,8 @@ class CONTENT_EXPORT ServiceWorkerDispatcherHost : public BrowserMessageFilter {
public: public:
ServiceWorkerDispatcherHost( ServiceWorkerDispatcherHost(
int render_process_id, int render_process_id,
MessagePortMessageFilter* message_port_message_filter); MessagePortMessageFilter* message_port_message_filter,
ResourceContext* resource_context);
void Init(ServiceWorkerContextWrapper* context_wrapper); void Init(ServiceWorkerContextWrapper* context_wrapper);
...@@ -158,6 +160,7 @@ class CONTENT_EXPORT ServiceWorkerDispatcherHost : public BrowserMessageFilter { ...@@ -158,6 +160,7 @@ class CONTENT_EXPORT ServiceWorkerDispatcherHost : public BrowserMessageFilter {
int render_process_id_; int render_process_id_;
MessagePortMessageFilter* const message_port_message_filter_; MessagePortMessageFilter* const message_port_message_filter_;
ResourceContext* resource_context_;
scoped_refptr<ServiceWorkerContextWrapper> context_wrapper_; scoped_refptr<ServiceWorkerContextWrapper> context_wrapper_;
IDMap<ServiceWorkerHandle, IDMapOwnPointer> handles_; IDMap<ServiceWorkerHandle, IDMapOwnPointer> handles_;
......
...@@ -16,7 +16,9 @@ ...@@ -16,7 +16,9 @@
#include "content/common/service_worker/embedded_worker_messages.h" #include "content/common/service_worker/embedded_worker_messages.h"
#include "content/common/service_worker/service_worker_messages.h" #include "content/common/service_worker/service_worker_messages.h"
#include "content/public/common/content_switches.h" #include "content/public/common/content_switches.h"
#include "content/public/test/mock_resource_context.h"
#include "content/public/test/test_browser_thread_bundle.h" #include "content/public/test/test_browser_thread_bundle.h"
#include "content/test/test_content_browser_client.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
namespace content { namespace content {
...@@ -28,8 +30,9 @@ class TestingServiceWorkerDispatcherHost : public ServiceWorkerDispatcherHost { ...@@ -28,8 +30,9 @@ class TestingServiceWorkerDispatcherHost : public ServiceWorkerDispatcherHost {
TestingServiceWorkerDispatcherHost( TestingServiceWorkerDispatcherHost(
int process_id, int process_id,
ServiceWorkerContextWrapper* context_wrapper, ServiceWorkerContextWrapper* context_wrapper,
ResourceContext* resource_context,
EmbeddedWorkerTestHelper* helper) EmbeddedWorkerTestHelper* helper)
: ServiceWorkerDispatcherHost(process_id, NULL), : ServiceWorkerDispatcherHost(process_id, NULL, resource_context),
bad_messages_received_count_(0), bad_messages_received_count_(0),
helper_(helper) { helper_(helper) {
Init(context_wrapper); Init(context_wrapper);
...@@ -60,7 +63,7 @@ class ServiceWorkerDispatcherHostTest : public testing::Test { ...@@ -60,7 +63,7 @@ class ServiceWorkerDispatcherHostTest : public testing::Test {
virtual void SetUp() { virtual void SetUp() {
helper_.reset(new EmbeddedWorkerTestHelper(kRenderProcessId)); helper_.reset(new EmbeddedWorkerTestHelper(kRenderProcessId));
dispatcher_host_ = new TestingServiceWorkerDispatcherHost( dispatcher_host_ = new TestingServiceWorkerDispatcherHost(
kRenderProcessId, context_wrapper(), helper_.get()); kRenderProcessId, context_wrapper(), &resource_context_, helper_.get());
} }
virtual void TearDown() { virtual void TearDown() {
...@@ -120,10 +123,47 @@ class ServiceWorkerDispatcherHostTest : public testing::Test { ...@@ -120,10 +123,47 @@ class ServiceWorkerDispatcherHostTest : public testing::Test {
} }
TestBrowserThreadBundle browser_thread_bundle_; TestBrowserThreadBundle browser_thread_bundle_;
content::MockResourceContext resource_context_;
scoped_ptr<EmbeddedWorkerTestHelper> helper_; scoped_ptr<EmbeddedWorkerTestHelper> helper_;
scoped_refptr<TestingServiceWorkerDispatcherHost> dispatcher_host_; scoped_refptr<TestingServiceWorkerDispatcherHost> dispatcher_host_;
}; };
class ServiceWorkerTestContentBrowserClient : public TestContentBrowserClient {
public:
ServiceWorkerTestContentBrowserClient() {}
virtual bool AllowServiceWorker(const GURL& scope,
const GURL& first_party,
content::ResourceContext* context) OVERRIDE {
return false;
}
};
TEST_F(ServiceWorkerDispatcherHostTest,
Register_ContentSettingsDisallowsServiceWorker) {
ServiceWorkerTestContentBrowserClient test_browser_client;
ContentBrowserClient* old_browser_client =
SetBrowserClientForTesting(&test_browser_client);
const int64 kProviderId = 99; // Dummy value
scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL));
host->SetDocumentUrl(GURL("https://www.example.com/foo"));
context()->AddProviderHost(host.Pass());
Register(kProviderId,
GURL("https://www.example.com/"),
GURL("https://www.example.com/bar"),
ServiceWorkerMsg_ServiceWorkerRegistrationError::ID);
Unregister(kProviderId,
GURL("https://www.example.com/"),
ServiceWorkerMsg_ServiceWorkerUnregistrationError::ID);
GetRegistration(kProviderId,
GURL("https://www.example.com/"),
ServiceWorkerMsg_ServiceWorkerGetRegistrationError::ID);
SetBrowserClientForTesting(old_browser_client);
}
TEST_F(ServiceWorkerDispatcherHostTest, Register_HTTPS) { TEST_F(ServiceWorkerDispatcherHostTest, Register_HTTPS) {
const int64 kProviderId = 99; // Dummy value const int64 kProviderId = 99; // Dummy value
scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost( scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
......
...@@ -60,6 +60,10 @@ void ServiceWorkerProviderHost::SetDocumentUrl(const GURL& url) { ...@@ -60,6 +60,10 @@ void ServiceWorkerProviderHost::SetDocumentUrl(const GURL& url) {
document_url_ = url; document_url_ = url;
} }
void ServiceWorkerProviderHost::SetTopmostFrameUrl(const GURL& url) {
topmost_frame_url_ = url;
}
void ServiceWorkerProviderHost::SetControllerVersionAttribute( void ServiceWorkerProviderHost::SetControllerVersionAttribute(
ServiceWorkerVersion* version) { ServiceWorkerVersion* version) {
if (version == controlling_version_.get()) if (version == controlling_version_.get())
......
...@@ -83,6 +83,9 @@ class CONTENT_EXPORT ServiceWorkerProviderHost ...@@ -83,6 +83,9 @@ class CONTENT_EXPORT ServiceWorkerProviderHost
void SetDocumentUrl(const GURL& url); void SetDocumentUrl(const GURL& url);
const GURL& document_url() const { return document_url_; } const GURL& document_url() const { return document_url_; }
void SetTopmostFrameUrl(const GURL& url);
const GURL& topmost_frame_url() const { return topmost_frame_url_; }
// Associates to |registration| to listen for its version change events. // Associates to |registration| to listen for its version change events.
void AssociateRegistration(ServiceWorkerRegistration* registration); void AssociateRegistration(ServiceWorkerRegistration* registration);
...@@ -151,6 +154,7 @@ class CONTENT_EXPORT ServiceWorkerProviderHost ...@@ -151,6 +154,7 @@ class CONTENT_EXPORT ServiceWorkerProviderHost
const int process_id_; const int process_id_;
const int provider_id_; const int provider_id_;
GURL document_url_; GURL document_url_;
GURL topmost_frame_url_;
std::vector<GURL> associated_patterns_; std::vector<GURL> associated_patterns_;
scoped_refptr<ServiceWorkerRegistration> associated_registration_; scoped_refptr<ServiceWorkerRegistration> associated_registration_;
......
...@@ -82,8 +82,10 @@ void ServiceWorkerRequestHandler::InitializeHandler( ...@@ -82,8 +82,10 @@ void ServiceWorkerRequestHandler::InitializeHandler(
return; return;
if (skip_service_worker) { if (skip_service_worker) {
if (ServiceWorkerUtils::IsMainResourceType(resource_type)) if (ServiceWorkerUtils::IsMainResourceType(resource_type)) {
provider_host->SetDocumentUrl(net::SimplifyUrlForRequest(request->url())); provider_host->SetDocumentUrl(net::SimplifyUrlForRequest(request->url()));
provider_host->SetTopmostFrameUrl(request->first_party_for_cookies());
}
return; return;
} }
......
...@@ -116,6 +116,13 @@ bool ContentBrowserClient::AllowAppCache(const GURL& manifest_url, ...@@ -116,6 +116,13 @@ bool ContentBrowserClient::AllowAppCache(const GURL& manifest_url,
return true; return true;
} }
bool ContentBrowserClient::AllowServiceWorker(
const GURL& scope,
const GURL& document_url,
content::ResourceContext* context) {
return true;
}
bool ContentBrowserClient::AllowGetCookie(const GURL& url, bool ContentBrowserClient::AllowGetCookie(const GURL& url,
const GURL& first_party, const GURL& first_party,
const net::CookieList& cookie_list, const net::CookieList& cookie_list,
......
...@@ -273,6 +273,13 @@ class CONTENT_EXPORT ContentBrowserClient { ...@@ -273,6 +273,13 @@ class CONTENT_EXPORT ContentBrowserClient {
const GURL& first_party, const GURL& first_party,
ResourceContext* context); ResourceContext* context);
// Allow the embedder to control if a Service Worker can be associated
// with the given scope.
// This is called on the IO thread.
virtual bool AllowServiceWorker(const GURL& scope,
const GURL& first_party,
content::ResourceContext* context);
// Allow the embedder to control if the given cookie can be read. // Allow the embedder to control if the given cookie can be read.
// This is called on the IO thread. // This is called on the IO thread.
virtual bool AllowGetCookie(const GURL& url, virtual bool AllowGetCookie(const GURL& url,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment