diff options
author | darin@chromium.org <darin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-02-09 22:41:20 +0000 |
---|---|---|
committer | darin@chromium.org <darin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-02-09 22:41:20 +0000 |
commit | 3dbb80bca45a4fdf674250ed833842a71de41838 (patch) | |
tree | 46a087293623a29e8bb2a2b8e1567be6ac177c02 | |
parent | 76477871b30938124add005d5df27c0ffb544ee4 (diff) | |
download | chromium_src-3dbb80bca45a4fdf674250ed833842a71de41838.zip chromium_src-3dbb80bca45a4fdf674250ed833842a71de41838.tar.gz chromium_src-3dbb80bca45a4fdf674250ed833842a71de41838.tar.bz2 |
Trigger the blocked cookie notification UI.
This change involves two significant bits:
1- Add URLRequest::Delegate methods to report a blocked attempt to set a cookie
or get cookies, respectively.
2- Generalize the mechanisms we use to proxy notifications to the RenderViewHost
from the IO thread. See render_view_host_notification_task.h.
Finally, these are used together in ResourceDispatcherHost.
Note: Additional work is required to notify when JS attempts to set a cookie
fail.
R=brettw,eroman
BUG=34573
TEST=Configure the browser to block cookies, and then visit a site that tries to
set a cookie (e.g., cnn.com). You should see a cookie icon appear in the location
bar. If you click that it should report that cookies were blocked.
Review URL: http://codereview.chromium.org/600009
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@38527 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | base/task.h | 2 | ||||
-rw-r--r-- | chrome/browser/renderer_host/cross_site_resource_handler.cc | 76 | ||||
-rw-r--r-- | chrome/browser/renderer_host/render_view_host.cc | 10 | ||||
-rw-r--r-- | chrome/browser/renderer_host/render_view_host.h | 5 | ||||
-rw-r--r-- | chrome/browser/renderer_host/render_view_host_delegate.h | 10 | ||||
-rw-r--r-- | chrome/browser/renderer_host/render_view_host_notification_task.h | 237 | ||||
-rw-r--r-- | chrome/browser/renderer_host/resource_dispatcher_host.cc | 159 | ||||
-rw-r--r-- | chrome/browser/renderer_host/resource_dispatcher_host.h | 1 | ||||
-rw-r--r-- | chrome/browser/renderer_host/resource_request_details.h | 2 | ||||
-rw-r--r-- | chrome/browser/tab_contents/tab_contents.cc | 14 | ||||
-rw-r--r-- | chrome/browser/tab_contents/tab_contents.h | 5 | ||||
-rw-r--r-- | net/url_request/url_request.h | 8 | ||||
-rw-r--r-- | net/url_request/url_request_http_job.cc | 25 | ||||
-rw-r--r-- | net/url_request/url_request_unittest.cc | 129 | ||||
-rw-r--r-- | net/url_request/url_request_unittest.h | 28 |
15 files changed, 494 insertions, 217 deletions
diff --git a/base/task.h b/base/task.h index d71df20..cbb8c99 100644 --- a/base/task.h +++ b/base/task.h @@ -649,7 +649,7 @@ typename Callback5<Arg1, Arg2, Arg3, Arg4, Arg5>::Type* NewCallback( template <class T, class Method, class Params> class UnboundMethod { public: - UnboundMethod(Method m, Params p) : m_(m), p_(p) { + UnboundMethod(Method m, const Params& p) : m_(m), p_(p) { COMPILE_ASSERT((MethodUsesScopedRefptrCorrectly<Method, Params>::value), badunboundmethodparams); } diff --git a/chrome/browser/renderer_host/cross_site_resource_handler.cc b/chrome/browser/renderer_host/cross_site_resource_handler.cc index e178cf1..876547e 100644 --- a/chrome/browser/renderer_host/cross_site_resource_handler.cc +++ b/chrome/browser/renderer_host/cross_site_resource_handler.cc @@ -11,66 +11,11 @@ #include "chrome/browser/renderer_host/global_request_id.h" #include "chrome/browser/renderer_host/render_view_host.h" #include "chrome/browser/renderer_host/render_view_host_delegate.h" +#include "chrome/browser/renderer_host/render_view_host_notification_task.h" #include "chrome/browser/renderer_host/resource_dispatcher_host.h" #include "chrome/browser/renderer_host/resource_dispatcher_host_request_info.h" #include "net/base/io_buffer.h" -namespace { - -// Task to notify the TabContents that a cross-site response has begun, so that -// TabContents can tell the old page to run its onunload handler. -class CrossSiteNotifyTask : public Task { - public: - CrossSiteNotifyTask(int render_process_host_id, - int render_view_id, - int request_id) - : render_process_host_id_(render_process_host_id), - render_view_id_(render_view_id), - request_id_(request_id) {} - - void Run() { - RenderViewHost* view = - RenderViewHost::FromID(render_process_host_id_, render_view_id_); - if (view) { - view->OnCrossSiteResponse(render_process_host_id_, request_id_); - } else { - // The view couldn't be found. - // TODO(creis): Should notify the IO thread to proceed anyway, using - // ResourceDispatcherHost::OnClosePageACK. - } - } - - private: - int render_process_host_id_; - int render_view_id_; - int request_id_; -}; - -class CancelPendingRenderViewTask : public Task { - public: - CancelPendingRenderViewTask(int render_process_host_id, - int render_view_id) - : render_process_host_id_(render_process_host_id), - render_view_id_(render_view_id) {} - - void Run() { - RenderViewHost* view = - RenderViewHost::FromID(render_process_host_id_, render_view_id_); - if (view) { - RenderViewHostDelegate::RendererManagement* management_delegate = - view->delegate()->GetRendererManagementDelegate(); - if (management_delegate) - management_delegate->OnCrossSiteNavigationCanceled(); - } - } - - private: - int render_process_host_id_; - int render_view_id_; -}; - -} // namespace - CrossSiteResourceHandler::CrossSiteResourceHandler( ResourceHandler* handler, int render_process_host_id, @@ -162,10 +107,10 @@ bool CrossSiteResourceHandler::OnResponseCompleted( // Here the request was canceled, which happens when selecting "take me // back" from an interstitial. Nothing to do but cancel the pending // render view host. - ChromeThread::PostTask( - ChromeThread::UI, FROM_HERE, - new CancelPendingRenderViewTask( - render_process_host_id_, render_view_id_)); + CallRenderViewHostRendererManagementDelegate( + render_process_host_id_, render_view_id_, + &RenderViewHostDelegate::RendererManagement:: + OnCrossSiteNavigationCanceled); return next_handler_->OnResponseCompleted(request_id, status, security_info); } else { @@ -265,8 +210,11 @@ void CrossSiteResourceHandler::StartCrossSiteTransition( // Tell the tab responsible for this request that a cross-site response is // starting, so that it can tell its old renderer to run its onunload // handler now. We will wait to hear the corresponding ClosePage_ACK. - ChromeThread::PostTask( - ChromeThread::UI, FROM_HERE, - new CrossSiteNotifyTask( - render_process_host_id_, render_view_id_, request_id)); + CallRenderViewHostRendererManagementDelegate( + render_process_host_id_, render_view_id_, + &RenderViewHostDelegate::RendererManagement::OnCrossSiteResponse, + render_process_host_id_, request_id); + + // TODO(creis): If the above call should fail, then we need to notify the IO + // thread to proceed anyway, using ResourceDispatcherHost::OnClosePageACK. } diff --git a/chrome/browser/renderer_host/render_view_host.cc b/chrome/browser/renderer_host/render_view_host.cc index 89a2093..e235f50 100644 --- a/chrome/browser/renderer_host/render_view_host.cc +++ b/chrome/browser/renderer_host/render_view_host.cc @@ -356,16 +356,6 @@ int RenderViewHost::GetPendingRequestId() { return pending_request_id_; } -void RenderViewHost::OnCrossSiteResponse(int new_render_process_host_id, - int new_request_id) { - RenderViewHostDelegate::RendererManagement* management_delegate = - delegate_->GetRendererManagementDelegate(); - if (management_delegate) { - management_delegate->OnCrossSiteResponse(new_render_process_host_id, - new_request_id); - } -} - void RenderViewHost::Stop() { Send(new ViewMsg_Stop(routing_id())); } diff --git a/chrome/browser/renderer_host/render_view_host.h b/chrome/browser/renderer_host/render_view_host.h index 74e0e77..0ce1372 100644 --- a/chrome/browser/renderer_host/render_view_host.h +++ b/chrome/browser/renderer_host/render_view_host.h @@ -182,11 +182,6 @@ class RenderViewHost : public RenderWidgetHost { // hangs, in which case we need to swap to the pending RenderViewHost. int GetPendingRequestId(); - // Called by ResourceDispatcherHost when a response for a pending cross-site - // request is received. The ResourceDispatcherHost will pause the response - // until the onunload handler of the previous renderer is run. - void OnCrossSiteResponse(int new_render_process_host_id, int new_request_id); - // Stops the current load. void Stop(); diff --git a/chrome/browser/renderer_host/render_view_host_delegate.h b/chrome/browser/renderer_host/render_view_host_delegate.h index e782f4b..020537e 100644 --- a/chrome/browser/renderer_host/render_view_host_delegate.h +++ b/chrome/browser/renderer_host/render_view_host_delegate.h @@ -26,6 +26,7 @@ class Profile; struct RendererPreferences; class RenderProcessHost; class RenderViewHost; +class ResourceRedirectDetails; class ResourceRequestDetails; class SkBitmap; class TabContents; @@ -247,10 +248,8 @@ class RenderViewHostDelegate { // DidStartProvisionalLoadForFrame above because this is called for every // resource (images, automatically loaded subframes, etc.) and provisional // loads are only for user-initiated navigations. - // - // The pointer ownership is NOT transferred. virtual void DidStartReceivingResourceResponse( - ResourceRequestDetails* details) = 0; + const ResourceRequestDetails& details) = 0; // Sent when a provisional load is redirected. virtual void DidRedirectProvisionalLoad(int32 page_id, @@ -262,9 +261,8 @@ class RenderViewHostDelegate { // DidRedirectProvisionalLoad above because this is called for every // resource (images, automatically loaded subframes, etc.) and provisional // loads are only for user-initiated navigations. - // - // The pointer ownership is NOT transferred. - virtual void DidRedirectResource(ResourceRequestDetails* details) = 0; + virtual void DidRedirectResource( + const ResourceRedirectDetails& details) = 0; // The RenderView loaded a resource from an in-memory cache. // |security_info| contains the security info if this resource was diff --git a/chrome/browser/renderer_host/render_view_host_notification_task.h b/chrome/browser/renderer_host/render_view_host_notification_task.h new file mode 100644 index 0000000..3093802 --- /dev/null +++ b/chrome/browser/renderer_host/render_view_host_notification_task.h @@ -0,0 +1,237 @@ +// Copyright (c) 2010 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. + +// This file defines utility functions for sending notifications (calling +// methods that return void and do not have out params) to the RenderViewHost +// or one of its delegate interfaces. The notifications are dispatched +// asynchronously, and only if the specified RenderViewHost still exists. + +#ifndef CHROME_BROWSER_RENDERER_HOST_RENDER_VIEW_HOST_NOTIFICATION_TASK_H_ +#define CHROME_BROWSER_RENDERER_HOST_RENDER_VIEW_HOST_NOTIFICATION_TASK_H_ + +#include "base/task.h" +#include "chrome/browser/chrome_thread.h" +#include "chrome/browser/renderer_host/render_view_host.h" +#include "chrome/browser/renderer_host/render_view_host_delegate.h" + +// ---------------------------------------------------------------------------- + +namespace internal { + +// The simplest Mapper, used when proxying calls to a RenderViewHost. +class RenderViewHostIdentityMapper { + public: + typedef RenderViewHost MappedType; + static MappedType* Map(RenderViewHost* rvh) { return rvh; } +}; + +template <typename Method, typename Params, + typename Mapper = RenderViewHostIdentityMapper> +class RenderViewHostNotificationTask : public Task { + public: + RenderViewHostNotificationTask(int render_process_id, + int render_view_id, + Method method, + const Params& params) + : render_process_id_(render_process_id), + render_view_id_(render_view_id), + unbound_method_(method, params) { + } + + virtual void Run() { + RenderViewHost* rvh = RenderViewHost::FromID(render_process_id_, + render_view_id_); + typename Mapper::MappedType* obj = Mapper::Map(rvh); + if (obj) + unbound_method_.Run(obj); + } + + private: + int render_process_id_; + int render_view_id_; + UnboundMethod<typename Mapper::MappedType, Method, Params> unbound_method_; + + DISALLOW_COPY_AND_ASSIGN(RenderViewHostNotificationTask); +}; + +// For proxying calls to RenderViewHost + +template <typename Method, typename Params> +inline void CallRenderViewHostHelper(int render_process_id, int render_view_id, + Method method, const Params& params) { + ChromeThread::PostTask( + ChromeThread::UI, FROM_HERE, + new RenderViewHostNotificationTask<Method, Params>(render_process_id, + render_view_id, + method, + params)); +} + +// For proxying calls to RenderViewHostDelegate::Resource + +class RenderViewHostToResourceDelegate { + public: + typedef RenderViewHostDelegate::Resource MappedType; + static MappedType* Map(RenderViewHost* rvh) { + return rvh ? rvh->delegate()->GetResourceDelegate() : NULL; + } +}; + +template <typename Method, typename Params> +inline void CallRenderViewHostResourceDelegateHelper(int render_process_id, + int render_view_id, + Method method, + const Params& params) { + + ChromeThread::PostTask( + ChromeThread::UI, FROM_HERE, + new RenderViewHostNotificationTask< + Method, Params, RenderViewHostToResourceDelegate>(render_process_id, + render_view_id, + method, + params)); +} + +// For proxying calls to RenderViewHostDelegate::RendererManagement + +class RenderViewHostToRendererManagementDelegate { + public: + typedef RenderViewHostDelegate::RendererManagement MappedType; + static MappedType* Map(RenderViewHost* rvh) { + return rvh ? rvh->delegate()->GetRendererManagementDelegate() : NULL; + } +}; + +template <typename Method, typename Params> +inline void CallRenderViewHostRendererManagementDelegateHelper( + int render_process_id, + int render_view_id, + Method method, + const Params& params) { + ChromeThread::PostTask( + ChromeThread::UI, FROM_HERE, + new RenderViewHostNotificationTask< + Method, Params, RenderViewHostToRendererManagementDelegate>( + render_process_id, + render_view_id, + method, + params)); +} + +} // namespace internal + +// ---------------------------------------------------------------------------- +// Proxy calls to the specified RenderViewHost. + +template <typename Method> +inline void CallRenderViewHost(int render_process_id, + int render_view_id, + Method method) { + internal::CallRenderViewHostHelper(render_process_id, + render_view_id, + method, + MakeTuple()); +} + +template <typename Method, typename A> +inline void CallRenderViewHost(int render_process_id, + int render_view_id, + Method method, + const A& a) { + internal::CallRenderViewHostHelper(render_process_id, + render_view_id, + method, + MakeTuple(a)); +} + +template <typename Method, typename A, typename B> +inline void CallRenderViewHost(int render_process_id, + int render_view_id, + Method method, + const A& a, + const B& b) { + internal::CallRenderViewHostHelper(render_process_id, + render_view_id, + method, + MakeTuple(a, b)); +} + +// ---------------------------------------------------------------------------- +// Proxy calls to the specified RenderViewHost's Resource delegate. + +template <typename Method> +inline void CallRenderViewHostResourceDelegate(int render_process_id, + int render_view_id, + Method method) { + internal::CallRenderViewHostResourceDelegateHelper(render_process_id, + render_view_id, + method, + MakeTuple()); +} + +template <typename Method, typename A> +inline void CallRenderViewHostResourceDelegate(int render_process_id, + int render_view_id, + Method method, + const A& a) { + internal::CallRenderViewHostResourceDelegateHelper(render_process_id, + render_view_id, + method, + MakeTuple(a)); +} + +template <typename Method, typename A, typename B> +inline void CallRenderViewHostResourceDelegate(int render_process_id, + int render_view_id, + Method method, + const A& a, + const B& b) { + internal::CallRenderViewHostResourceDelegateHelper(render_process_id, + render_view_id, + method, + MakeTuple(a, b)); +} + +// ---------------------------------------------------------------------------- +// Proxy calls to the specified RenderViewHost's RendererManagement delegate. + +template <typename Method> +inline void CallRenderViewHostRendererManagementDelegate(int render_process_id, + int render_view_id, + Method method) { + internal::CallRenderViewHostRendererManagementDelegateHelper( + render_process_id, + render_view_id, + method, + MakeTuple()); +} + +template <typename Method, typename A> +inline void CallRenderViewHostRendererManagementDelegate(int render_process_id, + int render_view_id, + Method method, + const A& a) { + internal::CallRenderViewHostRendererManagementDelegateHelper( + render_process_id, + render_view_id, + method, + MakeTuple(a)); +} + +template <typename Method, typename A, typename B> +inline void CallRenderViewHostRendererManagementDelegate(int render_process_id, + int render_view_id, + Method method, + const A& a, + const B& b) { + internal::CallRenderViewHostRendererManagementDelegateHelper( + render_process_id, + render_view_id, + method, + MakeTuple(a, b)); +} + +// ---------------------------------------------------------------------------- + +#endif // CHROME_BROWSER_RENDERER_HOST_RENDER_VIEW_HOST_NOTIFICATION_TASK_H_ diff --git a/chrome/browser/renderer_host/resource_dispatcher_host.cc b/chrome/browser/renderer_host/resource_dispatcher_host.cc index 2907d7f..971888c 100644 --- a/chrome/browser/renderer_host/resource_dispatcher_host.cc +++ b/chrome/browser/renderer_host/resource_dispatcher_host.cc @@ -38,6 +38,7 @@ #include "chrome/browser/renderer_host/global_request_id.h" #include "chrome/browser/renderer_host/render_view_host.h" #include "chrome/browser/renderer_host/render_view_host_delegate.h" +#include "chrome/browser/renderer_host/render_view_host_notification_task.h" #include "chrome/browser/renderer_host/resource_dispatcher_host_request_info.h" #include "chrome/browser/renderer_host/resource_queue.h" #include "chrome/browser/renderer_host/resource_request_details.h" @@ -108,89 +109,6 @@ const int kMaxPendingDataMessages = 20; // This bound is 25MB, which allows for around 6000 outstanding requests. const int kMaxOutstandingRequestsCostPerProcess = 26214400; -// Calls ClosePageIgnoringUnloadEvents on the UI thread for the given -// RenderView. -// -// If there are more functions we need to call on RVH, we should generalize this -// like the "Delegate" notification task below. -class RVHCloseNotificationTask : public Task { - public: - RVHCloseNotificationTask(int render_process_host_id, - int render_view_host_id) - : render_process_host_id_(render_process_host_id), - render_view_host_id_(render_view_host_id) { - } - - virtual void Run() { - RenderViewHost* rvh = RenderViewHost::FromID(render_process_host_id_, - render_view_host_id_); - if (rvh) - rvh->ClosePageIgnoringUnloadEvents(); - } - - private: - int render_process_host_id_; - int render_view_host_id_; - - DISALLOW_COPY_AND_ASSIGN(RVHCloseNotificationTask); -}; - -// A RVHDelegateNotificationTask proxies a resource dispatcher notification -// from the IO thread to the RenderViewHostDelegate on the UI thread. It should -// be constructed on the IO thread and run in the UI thread. -class RVHDelegateNotificationTask : public Task { - public: - typedef void (RenderViewHostDelegate::Resource::* ResourceFunction) - (ResourceRequestDetails*); - - // Supply the originating URLRequest, a function on RenderViewHostDelegate - // to call, and the details to use as the parameter to the given function. - // - // This object will take ownership of the details pointer, which must be - // allocated on the heap. - RVHDelegateNotificationTask( - URLRequest* request, - ResourceFunction function, - ResourceRequestDetails* details) - : render_process_host_id_(-1), - render_view_host_id_(-1), - function_(function), - details_(details) { - if (!ResourceDispatcherHost::RenderViewForRequest(request, - &render_process_host_id_, - &render_view_host_id_)) { - // Issue a warning here - this can happen during normal operation (for - // example, if a worker exits while a network operation is pending), but - // it should be fairly rare. - DLOG(WARNING) << "Trying to deliver a message to a RenderViewHost" << - " that has already exited or has never existed."; - } - } - - virtual void Run() { - RenderViewHost* rvh = RenderViewHost::FromID(render_process_host_id_, - render_view_host_id_); - if (rvh) { - RenderViewHostDelegate::Resource* resource_delegate = - rvh->delegate()->GetResourceDelegate(); - if (resource_delegate) - (resource_delegate->*function_)(details_.get()); - } - } - - private: - int render_process_host_id_; - int render_view_host_id_; - - // The function to call on RenderViewHostDelegate::Resource on the UI thread. - ResourceFunction function_; - - // The details for the notification. - scoped_ptr<ResourceRequestDetails> details_; - - DISALLOW_COPY_AND_ASSIGN(RVHDelegateNotificationTask); -}; - // Consults the RendererSecurity policy to determine whether the // ResourceDispatcherHost should service this request. A request might be // disallowed if the renderer is not authorized to retrieve the request URL or @@ -635,10 +553,9 @@ void ResourceDispatcherHost::OnClosePageACK( // This is a tab close, so just forward the message to close it. DCHECK(params.new_render_process_host_id == -1); DCHECK(params.new_request_id == -1); - ChromeThread::PostTask( - ChromeThread::UI, FROM_HERE, - new RVHCloseNotificationTask(params.closing_process_id, - params.closing_route_id)); + CallRenderViewHost(params.closing_process_id, + params.closing_route_id, + &RenderViewHost::ClosePageIgnoringUnloadEvents); } } @@ -1057,6 +974,19 @@ void ResourceDispatcherHost::OnSSLCertificateError( SSLManager::OnSSLCertificateError(this, request, cert_error, cert); } +void ResourceDispatcherHost::OnSetCookieBlocked(URLRequest* request) { + RESOURCE_LOG("OnSetCookieBlocked: " << request->url().spec()); + + int render_process_id, render_view_id; + if (!RenderViewForRequest(request, &render_process_id, &render_view_id)) + return; + + CallRenderViewHostResourceDelegate( + render_process_id, render_view_id, + &RenderViewHostDelegate::Resource::OnContentBlocked, + CONTENT_SETTINGS_TYPE_COOKIES); +} + void ResourceDispatcherHost::OnResponseStarted(URLRequest* request) { RESOURCE_LOG("OnResponseStarted: " << request->url().spec()); ResourceDispatcherHostRequestInfo* info = InfoForRequest(request); @@ -1448,20 +1378,20 @@ bool ResourceDispatcherHost::RenderViewForRequest(const URLRequest* request, // If the request is from the worker process, find a tab that owns the worker. if (info->process_type() == ChildProcessInfo::WORKER_PROCESS) { - const WorkerProcessHost::WorkerInstance* worker_instance = - WorkerService::GetInstance()->FindWorkerInstance(info->child_id()); - if (!worker_instance) { - *render_process_host_id = -1; - *render_view_host_id = -1; - return false; - } - DCHECK(!worker_instance->worker_document_set()->IsEmpty()); - const WorkerDocumentSet::DocumentInfoSet& parents = - worker_instance->worker_document_set()->documents(); - // Need to display some related UI for this network request - pick an - // arbitrary parent to do so. - *render_process_host_id = parents.begin()->renderer_id(); - *render_view_host_id = parents.begin()->render_view_route_id(); + const WorkerProcessHost::WorkerInstance* worker_instance = + WorkerService::GetInstance()->FindWorkerInstance(info->child_id()); + if (!worker_instance) { + *render_process_host_id = -1; + *render_view_host_id = -1; + return false; + } + DCHECK(!worker_instance->worker_document_set()->IsEmpty()); + const WorkerDocumentSet::DocumentInfoSet& parents = + worker_instance->worker_document_set()->documents(); + // Need to display some related UI for this network request - pick an + // arbitrary parent to do so. + *render_process_host_id = parents.begin()->renderer_id(); + *render_view_host_id = parents.begin()->render_view_route_id(); } else { *render_process_host_id = info->child_id(); *render_view_host_id = info->route_id(); @@ -1511,13 +1441,15 @@ void ResourceDispatcherHost::NotifyResponseStarted(URLRequest* request, // Notify the observers on the IO thread. FOR_EACH_OBSERVER(Observer, observer_list_, OnRequestStarted(this, request)); + int render_process_id, render_view_id; + if (!RenderViewForRequest(request, &render_process_id, &render_view_id)) + return; + // Notify the observers on the UI thread. - ChromeThread::PostTask( - ChromeThread::UI, FROM_HERE, - new RVHDelegateNotificationTask( - request, - &RenderViewHostDelegate::Resource::DidStartReceivingResourceResponse, - new ResourceRequestDetails(request, GetCertID(request, child_id)))); + CallRenderViewHostResourceDelegate( + render_process_id, render_view_id, + &RenderViewHostDelegate::Resource::DidStartReceivingResourceResponse, + ResourceRequestDetails(request, GetCertID(request, child_id))); } void ResourceDispatcherHost::NotifyResponseCompleted(URLRequest* request, @@ -1534,14 +1466,15 @@ void ResourceDispatcherHost::NotifyReceivedRedirect(URLRequest* request, FOR_EACH_OBSERVER(Observer, observer_list_, OnReceivedRedirect(this, request, new_url)); - int cert_id = GetCertID(request, child_id); + int render_process_id, render_view_id; + if (!RenderViewForRequest(request, &render_process_id, &render_view_id)) + return; // Notify the observers on the UI thread. - ChromeThread::PostTask( - ChromeThread::UI, FROM_HERE, - new RVHDelegateNotificationTask( - request, &RenderViewHostDelegate::Resource::DidRedirectResource, - new ResourceRedirectDetails(request, cert_id, new_url))); + CallRenderViewHostResourceDelegate( + render_process_id, render_view_id, + &RenderViewHostDelegate::Resource::DidRedirectResource, + ResourceRedirectDetails(request, GetCertID(request, child_id), new_url)); } namespace { diff --git a/chrome/browser/renderer_host/resource_dispatcher_host.h b/chrome/browser/renderer_host/resource_dispatcher_host.h index eff192d..4e10dae 100644 --- a/chrome/browser/renderer_host/resource_dispatcher_host.h +++ b/chrome/browser/renderer_host/resource_dispatcher_host.h @@ -206,6 +206,7 @@ class ResourceDispatcherHost : public URLRequest::Delegate { virtual void OnSSLCertificateError(URLRequest* request, int cert_error, net::X509Certificate* cert); + virtual void OnSetCookieBlocked(URLRequest* request); virtual void OnResponseStarted(URLRequest* request); virtual void OnReadCompleted(URLRequest* request, int bytes_read); void OnResponseCompleted(URLRequest* request); diff --git a/chrome/browser/renderer_host/resource_request_details.h b/chrome/browser/renderer_host/resource_request_details.h index ad0df97d..600decd 100644 --- a/chrome/browser/renderer_host/resource_request_details.h +++ b/chrome/browser/renderer_host/resource_request_details.h @@ -92,8 +92,6 @@ class ResourceRequestDetails { int ssl_cert_status_; ResourceType::Type resource_type_; FilterPolicy::Type filter_policy_; - - DISALLOW_COPY_AND_ASSIGN(ResourceRequestDetails); }; // Details about a redirection of a resource request. diff --git a/chrome/browser/tab_contents/tab_contents.cc b/chrome/browser/tab_contents/tab_contents.cc index f3b986d..9c334dc 100644 --- a/chrome/browser/tab_contents/tab_contents.cc +++ b/chrome/browser/tab_contents/tab_contents.cc @@ -580,10 +580,11 @@ bool TabContents::IsContentBlocked(ContentSettingsType content_type) const { if (content_type == CONTENT_SETTINGS_TYPE_IMAGES || content_type == CONTENT_SETTINGS_TYPE_JAVASCRIPT || - content_type == CONTENT_SETTINGS_TYPE_PLUGINS) + content_type == CONTENT_SETTINGS_TYPE_PLUGINS || + content_type == CONTENT_SETTINGS_TYPE_COOKIES) return content_blocked_[content_type]; - // TODO(pkasting): Return a meaningful values for cookies. + NOTREACHED(); return false; } @@ -1893,18 +1894,19 @@ void TabContents::DidStartProvisionalLoadForFrame( } void TabContents::DidStartReceivingResourceResponse( - ResourceRequestDetails* details) { + const ResourceRequestDetails& details) { NotificationService::current()->Notify( NotificationType::RESOURCE_RESPONSE_STARTED, Source<NavigationController>(&controller()), - Details<ResourceRequestDetails>(details)); + Details<const ResourceRequestDetails>(&details)); } -void TabContents::DidRedirectResource(ResourceRequestDetails* details) { +void TabContents::DidRedirectResource( + const ResourceRedirectDetails& details) { NotificationService::current()->Notify( NotificationType::RESOURCE_RECEIVED_REDIRECT, Source<NavigationController>(&controller()), - Details<ResourceRequestDetails>(details)); + Details<const ResourceRequestDetails>(&details)); } void TabContents::DidLoadResourceFromMemoryCache( diff --git a/chrome/browser/tab_contents/tab_contents.h b/chrome/browser/tab_contents/tab_contents.h index eabbb71e..b66504c 100644 --- a/chrome/browser/tab_contents/tab_contents.h +++ b/chrome/browser/tab_contents/tab_contents.h @@ -814,11 +814,12 @@ class TabContents : public PageNavigator, bool is_main_frame, const GURL& url); virtual void DidStartReceivingResourceResponse( - ResourceRequestDetails* details); + const ResourceRequestDetails& details); virtual void DidRedirectProvisionalLoad(int32 page_id, const GURL& source_url, const GURL& target_url); - virtual void DidRedirectResource(ResourceRequestDetails* details); + virtual void DidRedirectResource( + const ResourceRedirectDetails& details); virtual void DidLoadResourceFromMemoryCache( const GURL& url, const std::string& frame_origin, diff --git a/net/url_request/url_request.h b/net/url_request/url_request.h index e586e28..b420cf8 100644 --- a/net/url_request/url_request.h +++ b/net/url_request/url_request.h @@ -187,6 +187,14 @@ class URLRequest { request->Cancel(); } + // Called when unable to get cookies due to policy. + virtual void OnGetCookiesBlocked(URLRequest* request) { + } + + // Called when unable to set a cookie due to policy. + virtual void OnSetCookieBlocked(URLRequest* request) { + } + // After calling Start(), the delegate will receive an OnResponseStarted // callback when the request has completed. If an error occurred, the // request->status() will be set. On success, all redirects have been diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc index 05fd0f2..ef17774 100644 --- a/net/url_request/url_request_http_job.cc +++ b/net/url_request/url_request_http_job.cc @@ -432,7 +432,9 @@ bool URLRequestHttpJob::ReadRawData(net::IOBuffer* buf, int buf_size, void URLRequestHttpJob::OnCanGetCookiesCompleted(int policy) { // If the request was destroyed, then there is no more work to do. if (request_ && request_->delegate()) { - if (request_->context()->cookie_store() && policy == net::OK) { + if (policy != net::OK) { + request_->delegate()->OnGetCookiesBlocked(request_); + } else if (request_->context()->cookie_store()) { net::CookieOptions options; options.set_include_httponly(); std::string cookies = @@ -442,7 +444,12 @@ void URLRequestHttpJob::OnCanGetCookiesCompleted(int policy) { !cookies.empty()) request_info_.extra_headers += "Cookie: " + cookies + "\r\n"; } - StartTransaction(); + // We may have been canceled within OnGetCookiesBlocked. + if (GetStatus().is_success()) { + StartTransaction(); + } else { + NotifyCanceled(); + } } Release(); // Balance AddRef taken in AddCookieHeaderAndStart } @@ -450,9 +457,10 @@ void URLRequestHttpJob::OnCanGetCookiesCompleted(int policy) { void URLRequestHttpJob::OnCanSetCookieCompleted(int policy) { // If the request was destroyed, then there is no more work to do. if (request_ && request_->delegate()) { - if (request_->context()->cookie_store() && - (policy == net::OK || - policy == net::OK_FOR_SESSION_ONLY)) { + if (policy != net::OK && + policy != net::OK_FOR_SESSION_ONLY) { + request_->delegate()->OnSetCookieBlocked(request_); + } else if (request_->context()->cookie_store()) { // OK to save the current response cookie now. net::CookieOptions options; options.set_include_httponly(); @@ -463,7 +471,12 @@ void URLRequestHttpJob::OnCanSetCookieCompleted(int policy) { options); } response_cookies_save_index_++; - SaveNextCookie(); + // We may have been canceled within OnSetCookieBlocked. + if (GetStatus().is_success()) { + SaveNextCookie(); + } else { + NotifyCanceled(); + } } Release(); // Balance AddRef taken in SaveNextCookie } diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc index d25ab08..16f4b3f 100644 --- a/net/url_request/url_request_unittest.cc +++ b/net/url_request/url_request_unittest.cc @@ -1241,6 +1241,8 @@ TEST_F(URLRequestTest, DoNotSendCookies) { req.set_context(context); req.Start(); MessageLoop::current()->Run(); + EXPECT_EQ(0, d.blocked_get_cookies_count()); + EXPECT_EQ(0, d.blocked_set_cookie_count()); } // Verify that the cookie is set. @@ -1253,6 +1255,8 @@ TEST_F(URLRequestTest, DoNotSendCookies) { EXPECT_TRUE(d.data_received().find("CookieToNotSend=1") != std::string::npos); + EXPECT_EQ(0, d.blocked_get_cookies_count()); + EXPECT_EQ(0, d.blocked_set_cookie_count()); } // Verify that the cookie isn't sent when LOAD_DO_NOT_SEND_COOKIES is set. @@ -1266,6 +1270,8 @@ TEST_F(URLRequestTest, DoNotSendCookies) { EXPECT_TRUE(d.data_received().find("Cookie: CookieToNotSend=1") == std::string::npos); + EXPECT_EQ(1, d.blocked_get_cookies_count()); + EXPECT_EQ(0, d.blocked_set_cookie_count()); } } @@ -1283,6 +1289,9 @@ TEST_F(URLRequestTest, DoNotSaveCookies) { req.set_context(context); req.Start(); MessageLoop::current()->Run(); + + EXPECT_EQ(0, d.blocked_get_cookies_count()); + EXPECT_EQ(0, d.blocked_set_cookie_count()); } // Try to set-up another cookie and update the previous cookie. @@ -1295,6 +1304,9 @@ TEST_F(URLRequestTest, DoNotSaveCookies) { req.Start(); MessageLoop::current()->Run(); + + EXPECT_EQ(0, d.blocked_get_cookies_count()); + EXPECT_EQ(2, d.blocked_set_cookie_count()); } // Verify the cookies weren't saved or updated. @@ -1309,6 +1321,9 @@ TEST_F(URLRequestTest, DoNotSaveCookies) { == std::string::npos); EXPECT_TRUE(d.data_received().find("CookieToNotUpdate=2") != std::string::npos); + + EXPECT_EQ(0, d.blocked_get_cookies_count()); + EXPECT_EQ(0, d.blocked_set_cookie_count()); } } @@ -1325,6 +1340,9 @@ TEST_F(URLRequestTest, DoNotSendCookies_ViaPolicy) { req.set_context(context); req.Start(); MessageLoop::current()->Run(); + + EXPECT_EQ(0, d.blocked_get_cookies_count()); + EXPECT_EQ(0, d.blocked_set_cookie_count()); } // Verify that the cookie is set. @@ -1337,6 +1355,9 @@ TEST_F(URLRequestTest, DoNotSendCookies_ViaPolicy) { EXPECT_TRUE(d.data_received().find("CookieToNotSend=1") != std::string::npos); + + EXPECT_EQ(0, d.blocked_get_cookies_count()); + EXPECT_EQ(0, d.blocked_set_cookie_count()); } // Verify that the cookie isn't sent. @@ -1354,6 +1375,9 @@ TEST_F(URLRequestTest, DoNotSendCookies_ViaPolicy) { == std::string::npos); context->set_cookie_policy(NULL); + + EXPECT_EQ(1, d.blocked_get_cookies_count()); + EXPECT_EQ(0, d.blocked_set_cookie_count()); } } @@ -1371,6 +1395,9 @@ TEST_F(URLRequestTest, DoNotSaveCookies_ViaPolicy) { req.set_context(context); req.Start(); MessageLoop::current()->Run(); + + EXPECT_EQ(0, d.blocked_get_cookies_count()); + EXPECT_EQ(0, d.blocked_set_cookie_count()); } // Try to set-up another cookie and update the previous cookie. @@ -1387,6 +1414,9 @@ TEST_F(URLRequestTest, DoNotSaveCookies_ViaPolicy) { MessageLoop::current()->Run(); context->set_cookie_policy(NULL); + + EXPECT_EQ(0, d.blocked_get_cookies_count()); + EXPECT_EQ(2, d.blocked_set_cookie_count()); } @@ -1402,6 +1432,9 @@ TEST_F(URLRequestTest, DoNotSaveCookies_ViaPolicy) { == std::string::npos); EXPECT_TRUE(d.data_received().find("CookieToNotUpdate=2") != std::string::npos); + + EXPECT_EQ(0, d.blocked_get_cookies_count()); + EXPECT_EQ(0, d.blocked_set_cookie_count()); } } @@ -1418,6 +1451,9 @@ TEST_F(URLRequestTest, DoNotSendCookies_ViaPolicy_Async) { req.set_context(context); req.Start(); MessageLoop::current()->Run(); + + EXPECT_EQ(0, d.blocked_get_cookies_count()); + EXPECT_EQ(0, d.blocked_set_cookie_count()); } // Verify that the cookie is set. @@ -1430,6 +1466,9 @@ TEST_F(URLRequestTest, DoNotSendCookies_ViaPolicy_Async) { EXPECT_TRUE(d.data_received().find("CookieToNotSend=1") != std::string::npos); + + EXPECT_EQ(0, d.blocked_get_cookies_count()); + EXPECT_EQ(0, d.blocked_set_cookie_count()); } // Verify that the cookie isn't sent. @@ -1448,6 +1487,9 @@ TEST_F(URLRequestTest, DoNotSendCookies_ViaPolicy_Async) { == std::string::npos); context->set_cookie_policy(NULL); + + EXPECT_EQ(1, d.blocked_get_cookies_count()); + EXPECT_EQ(0, d.blocked_set_cookie_count()); } } @@ -1465,6 +1507,9 @@ TEST_F(URLRequestTest, DoNotSaveCookies_ViaPolicy_Async) { req.set_context(context); req.Start(); MessageLoop::current()->Run(); + + EXPECT_EQ(0, d.blocked_get_cookies_count()); + EXPECT_EQ(0, d.blocked_set_cookie_count()); } // Try to set-up another cookie and update the previous cookie. @@ -1482,6 +1527,9 @@ TEST_F(URLRequestTest, DoNotSaveCookies_ViaPolicy_Async) { MessageLoop::current()->Run(); context->set_cookie_policy(NULL); + + EXPECT_EQ(0, d.blocked_get_cookies_count()); + EXPECT_EQ(2, d.blocked_set_cookie_count()); } // Verify the cookies weren't saved or updated. @@ -1496,10 +1544,13 @@ TEST_F(URLRequestTest, DoNotSaveCookies_ViaPolicy_Async) { == std::string::npos); EXPECT_TRUE(d.data_received().find("CookieToNotUpdate=2") != std::string::npos); + + EXPECT_EQ(0, d.blocked_get_cookies_count()); + EXPECT_EQ(0, d.blocked_set_cookie_count()); } } -TEST_F(URLRequestTest, CancelTest_DuringCookiePolicy) { +TEST_F(URLRequestTest, CancelTest_During_CookiePolicy) { scoped_refptr<HTTPTestServer> server = HTTPTestServer::CreateServer(L"", NULL); ASSERT_TRUE(NULL != server.get()); @@ -1516,7 +1567,78 @@ TEST_F(URLRequestTest, CancelTest_DuringCookiePolicy) { req.set_context(context); req.Start(); // Triggers an asynchronous cookie policy check. - // But, now we cancel the request. This should not cause a crash. + // But, now we cancel the request by letting it go out of scope. This + // should not cause a crash. + + EXPECT_EQ(0, d.blocked_get_cookies_count()); + EXPECT_EQ(0, d.blocked_set_cookie_count()); + } + + context->set_cookie_policy(NULL); + + // Let the cookie policy complete. Make sure it handles the destruction of + // the URLRequest properly. + MessageLoop::current()->RunAllPending(); +} + +TEST_F(URLRequestTest, CancelTest_During_OnGetCookiesBlocked) { + scoped_refptr<HTTPTestServer> server = + HTTPTestServer::CreateServer(L"", NULL); + ASSERT_TRUE(NULL != server.get()); + scoped_refptr<URLRequestTestContext> context = new URLRequestTestContext(); + + TestCookiePolicy cookie_policy(TestCookiePolicy::NO_GET_COOKIES); + context->set_cookie_policy(&cookie_policy); + + // Set up a cookie. + { + TestDelegate d; + d.set_cancel_in_get_cookies_blocked(true); + URLRequest req(server->TestServerPage("set-cookie?A=1&B=2&C=3"), + &d); + req.set_context(context); + req.Start(); // Triggers an asynchronous cookie policy check. + + MessageLoop::current()->Run(); + + EXPECT_EQ(URLRequestStatus::CANCELED, req.status().status()); + + EXPECT_EQ(1, d.blocked_get_cookies_count()); + EXPECT_EQ(0, d.blocked_set_cookie_count()); + } + + context->set_cookie_policy(NULL); +} + +TEST_F(URLRequestTest, CancelTest_During_OnSetCookieBlocked) { + scoped_refptr<HTTPTestServer> server = + HTTPTestServer::CreateServer(L"", NULL); + ASSERT_TRUE(NULL != server.get()); + scoped_refptr<URLRequestTestContext> context = new URLRequestTestContext(); + + TestCookiePolicy cookie_policy(TestCookiePolicy::NO_SET_COOKIE); + context->set_cookie_policy(&cookie_policy); + + // Set up a cookie. + { + TestDelegate d; + d.set_cancel_in_set_cookie_blocked(true); + URLRequest req(server->TestServerPage("set-cookie?A=1&B=2&C=3"), + &d); + req.set_context(context); + req.Start(); // Triggers an asynchronous cookie policy check. + + MessageLoop::current()->Run(); + + EXPECT_EQ(URLRequestStatus::CANCELED, req.status().status()); + + // Even though the response will contain 3 set-cookie headers, we expect + // only one to be blocked as that first one will cause OnSetCookieBlocked + // to be called, which will cancel the request. Once canceled, it should + // not attempt to set further cookies. + + EXPECT_EQ(0, d.blocked_get_cookies_count()); + EXPECT_EQ(1, d.blocked_set_cookie_count()); } context->set_cookie_policy(NULL); @@ -1540,6 +1662,9 @@ TEST_F(URLRequestTest, CookiePolicy_ForceSession) { req.Start(); // Triggers an asynchronous cookie policy check. MessageLoop::current()->Run(); + + EXPECT_EQ(0, d.blocked_get_cookies_count()); + EXPECT_EQ(0, d.blocked_set_cookie_count()); } // Now, check the cookie store. diff --git a/net/url_request/url_request_unittest.h b/net/url_request/url_request_unittest.h index 3f50335..16116d9 100644 --- a/net/url_request/url_request_unittest.h +++ b/net/url_request/url_request_unittest.h @@ -192,12 +192,16 @@ class TestDelegate : public URLRequest::Delegate { cancel_in_rs_(false), cancel_in_rd_(false), cancel_in_rd_pending_(false), + cancel_in_getcookiesblocked_(false), + cancel_in_setcookieblocked_(false), quit_on_complete_(true), quit_on_redirect_(false), allow_certificate_errors_(false), response_started_count_(0), received_bytes_count_(0), received_redirect_count_(0), + blocked_get_cookies_count_(0), + blocked_set_cookie_count_(0), received_data_before_response_(false), request_failed_(false), have_certificate_errors_(false), @@ -300,12 +304,30 @@ class TestDelegate : public URLRequest::Delegate { request->Cancel(); } + virtual void OnGetCookiesBlocked(URLRequest* request) { + blocked_get_cookies_count_++; + if (cancel_in_getcookiesblocked_) + request->Cancel(); + } + + virtual void OnSetCookieBlocked(URLRequest* request) { + blocked_set_cookie_count_++; + if (cancel_in_setcookieblocked_) + request->Cancel(); + } + void set_cancel_in_received_redirect(bool val) { cancel_in_rr_ = val; } void set_cancel_in_response_started(bool val) { cancel_in_rs_ = val; } void set_cancel_in_received_data(bool val) { cancel_in_rd_ = val; } void set_cancel_in_received_data_pending(bool val) { cancel_in_rd_pending_ = val; } + void set_cancel_in_get_cookies_blocked(bool val) { + cancel_in_getcookiesblocked_ = val; + } + void set_cancel_in_set_cookie_blocked(bool val) { + cancel_in_setcookieblocked_ = val; + } void set_quit_on_complete(bool val) { quit_on_complete_ = val; } void set_quit_on_redirect(bool val) { quit_on_redirect_ = val; } void set_allow_certificate_errors(bool val) { @@ -319,6 +341,8 @@ class TestDelegate : public URLRequest::Delegate { int bytes_received() const { return static_cast<int>(data_received_.size()); } int response_started_count() const { return response_started_count_; } int received_redirect_count() const { return received_redirect_count_; } + int blocked_get_cookies_count() const { return blocked_get_cookies_count_; } + int blocked_set_cookie_count() const { return blocked_set_cookie_count_; } bool received_data_before_response() const { return received_data_before_response_; } @@ -332,6 +356,8 @@ class TestDelegate : public URLRequest::Delegate { bool cancel_in_rs_; bool cancel_in_rd_; bool cancel_in_rd_pending_; + bool cancel_in_getcookiesblocked_; + bool cancel_in_setcookieblocked_; bool quit_on_complete_; bool quit_on_redirect_; bool allow_certificate_errors_; @@ -343,6 +369,8 @@ class TestDelegate : public URLRequest::Delegate { int response_started_count_; int received_bytes_count_; int received_redirect_count_; + int blocked_get_cookies_count_; + int blocked_set_cookie_count_; bool received_data_before_response_; bool request_failed_; bool have_certificate_errors_; |