Index: android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.cc |
diff --git a/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.cc b/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.cc |
index c1a27bd4dd70dec04728943ff1e043d40efadad8..fcabd9794efd4d969e701ed5fb40f176668033f8 100644 |
--- a/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.cc |
+++ b/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.cc |
@@ -4,12 +4,13 @@ |
#include "android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.h" |
-#include "android_webview/browser/aw_login_delegate.h" |
#include "android_webview/browser/aw_contents_io_thread_client.h" |
+#include "android_webview/browser/aw_login_delegate.h" |
#include "android_webview/common/url_constants.h" |
#include "base/memory/scoped_ptr.h" |
#include "base/memory/scoped_vector.h" |
#include "content/components/navigation_interception/intercept_navigation_delegate.h" |
+#include "content/public/browser/browser_thread.h" |
#include "content/public/browser/resource_controller.h" |
#include "content/public/browser/resource_dispatcher_host.h" |
#include "content/public/browser/resource_dispatcher_host_login_delegate.h" |
@@ -18,12 +19,12 @@ |
#include "net/base/load_flags.h" |
#include "net/url_request/url_request.h" |
+using android_webview::AwContentsIoThreadClient; |
+using content::BrowserThread; |
using content::InterceptNavigationDelegate; |
namespace { |
-using android_webview::AwContentsIoThreadClient; |
- |
base::LazyInstance<android_webview::AwResourceDispatcherHostDelegate> |
g_webview_resource_dispatcher_host_delegate = LAZY_INSTANCE_INITIALIZER; |
@@ -40,65 +41,119 @@ void SetCacheControlFlag( |
request->set_load_flags(load_flags); |
} |
+} // namespace |
+ |
+namespace android_webview { |
+ |
// Calls through the IoThreadClient to check the embedders settings to determine |
-// if the request should be cancelled. |
+// if the request should be cancelled. There may not always be an IoThreadClient |
+// available for the |child_id|, |route_id| pair (in the case of newly created |
+// pop up windows, for example) and in that case the request and the client |
+// callbacks will be deferred the request until a client is ready. |
class IoThreadClientThrottle : public content::ResourceThrottle { |
public: |
IoThreadClientThrottle(int child_id, |
int route_id, |
- net::URLRequest* request) |
- : child_id_(child_id), |
- route_id_(route_id), |
- request_(request) { } |
+ net::URLRequest* request); |
+ virtual ~IoThreadClientThrottle(); |
+ |
+ // From content::ResourceThrottle |
virtual void WillStartRequest(bool* defer) OVERRIDE; |
+ virtual void WillRedirectRequest(const GURL& new_url, bool* defer) OVERRIDE; |
- scoped_ptr<AwContentsIoThreadClient> GetIoThreadClient() { |
- return AwContentsIoThreadClient::FromID(child_id_, route_id_); |
- } |
+ bool MaybeDeferRequest(bool* defer); |
+ void OnIoThreadClientReady(int new_child_id, int new_route_id); |
+ bool MaybeBlockRequest(); |
+ bool ShouldBlockRequest(); |
+ scoped_ptr<AwContentsIoThreadClient> GetIoThreadClient(); |
+ int get_child_id() const { return child_id_; } |
+ int get_route_id() const { return route_id_; } |
- private: |
+private: |
int child_id_; |
int route_id_; |
net::URLRequest* request_; |
}; |
+IoThreadClientThrottle::IoThreadClientThrottle(int child_id, |
+ int route_id, |
+ net::URLRequest* request) |
+ : child_id_(child_id), |
+ route_id_(route_id), |
+ request_(request) { } |
+ |
+IoThreadClientThrottle::~IoThreadClientThrottle() { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
+ g_webview_resource_dispatcher_host_delegate.Get(). |
+ RemovePendingThrottleOnIoThread(this); |
+} |
+ |
void IoThreadClientThrottle::WillStartRequest(bool* defer) { |
- // If there is no IO thread client set at this point, use a |
- // restrictive policy. This can happen for blocked popup |
- // windows for example. |
- // TODO(benm): Revert this to a DCHECK when the we support |
- // pop up windows being created in the WebView, as at that |
- // time we should always have an IoThreadClient at this |
- // point (i.e., the one associated with the new popup). |
- if (!GetIoThreadClient()) { |
+ if (!MaybeDeferRequest(defer)) { |
+ MaybeBlockRequest(); |
+ } |
+} |
+ |
+void IoThreadClientThrottle::WillRedirectRequest(const GURL& new_url, |
+ bool* defer) { |
+ WillStartRequest(defer); |
+} |
+ |
+bool IoThreadClientThrottle::MaybeDeferRequest(bool* defer) { |
+ scoped_ptr<AwContentsIoThreadClient> io_client = |
+ AwContentsIoThreadClient::FromID(child_id_, route_id_); |
+ *defer = false; |
+ if (!io_client.get()) { |
+ *defer = true; |
+ AwResourceDispatcherHostDelegate::AddPendingThrottle( |
+ child_id_, route_id_, this); |
+ } |
+ return *defer; |
+} |
+ |
+void IoThreadClientThrottle::OnIoThreadClientReady(int new_child_id, |
+ int new_route_id) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
+ |
+ if (!MaybeBlockRequest()) { |
+ controller()->Resume(); |
+ } |
+} |
+ |
+bool IoThreadClientThrottle::MaybeBlockRequest() { |
+ if (ShouldBlockRequest()) { |
controller()->CancelWithError(net::ERR_ACCESS_DENIED); |
- return; |
+ return true; |
} |
+ return false; |
+} |
+ |
+bool IoThreadClientThrottle::ShouldBlockRequest() { |
+ scoped_ptr<AwContentsIoThreadClient> io_client = |
+ AwContentsIoThreadClient::FromID(child_id_, route_id_); |
+ DCHECK(io_client.get()); |
// Part of implementation of WebSettings.allowContentAccess. |
if (request_->url().SchemeIs(android_webview::kContentScheme) && |
- GetIoThreadClient()->ShouldBlockContentUrls()) { |
- controller()->CancelWithError(net::ERR_ACCESS_DENIED); |
- return; |
+ io_client->ShouldBlockContentUrls()) { |
+ return true; |
} |
// Part of implementation of WebSettings.allowFileAccess. |
if (request_->url().SchemeIsFile() && |
- GetIoThreadClient()->ShouldBlockFileUrls()) { |
+ io_client->ShouldBlockFileUrls()) { |
const GURL& url = request_->url(); |
if (!url.has_path() || |
// Application's assets and resources are always available. |
(url.path().find(android_webview::kAndroidResourcePath) != 0 && |
url.path().find(android_webview::kAndroidAssetPath) != 0)) { |
- controller()->CancelWithError(net::ERR_ACCESS_DENIED); |
- return; |
+ return true; |
} |
} |
- if (GetIoThreadClient()->ShouldBlockNetworkLoads()) { |
+ if (io_client->ShouldBlockNetworkLoads()) { |
if (request_->url().SchemeIs(chrome::kFtpScheme)) { |
- controller()->CancelWithError(net::ERR_ACCESS_DENIED); |
- return; |
+ return true; |
} |
SetCacheControlFlag(request_, net::LOAD_ONLY_FROM_CACHE); |
} else { |
@@ -118,11 +173,13 @@ void IoThreadClientThrottle::WillStartRequest(bool* defer) { |
break; |
} |
} |
+ return false; |
} |
-} // namespace |
- |
-namespace android_webview { |
+scoped_ptr<AwContentsIoThreadClient> |
+ IoThreadClientThrottle::GetIoThreadClient() { |
+ return AwContentsIoThreadClient::FromID(child_id_, route_id_); |
+} |
// static |
void AwResourceDispatcherHostDelegate::ResourceDispatcherHostCreated() { |
@@ -193,4 +250,63 @@ bool AwResourceDispatcherHostDelegate::HandleExternalProtocol(const GURL& url, |
return false; |
} |
+void AwResourceDispatcherHostDelegate::RemovePendingThrottleOnIoThread( |
+ IoThreadClientThrottle* throttle) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
+ PendingThrottleMap::iterator it = pending_throttles_.find( |
+ ChildRouteIDPair(throttle->get_child_id(), throttle->get_route_id())); |
+ if (it != pending_throttles_.end()) { |
+ pending_throttles_.erase(it); |
+ } |
+} |
+ |
+// static |
+void AwResourceDispatcherHostDelegate::OnIoThreadClientReady( |
+ int new_child_id, |
+ int new_route_id) { |
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
+ base::Bind( |
+ &AwResourceDispatcherHostDelegate::OnIoThreadClientReadyInternal, |
+ base::Unretained( |
+ g_webview_resource_dispatcher_host_delegate.Pointer()), |
+ new_child_id, new_route_id)); |
+} |
+ |
+// static |
+void AwResourceDispatcherHostDelegate::AddPendingThrottle( |
+ int child_id, |
+ int route_id, |
+ IoThreadClientThrottle* pending_throttle) { |
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
+ base::Bind( |
+ &AwResourceDispatcherHostDelegate::AddPendingThrottleOnIoThread, |
+ base::Unretained( |
+ g_webview_resource_dispatcher_host_delegate.Pointer()), |
+ child_id, route_id, pending_throttle)); |
} |
+ |
+void AwResourceDispatcherHostDelegate::AddPendingThrottleOnIoThread( |
+ int child_id, |
+ int route_id, |
+ IoThreadClientThrottle* pending_throttle) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
+ pending_throttles_.insert( |
+ std::pair<ChildRouteIDPair, IoThreadClientThrottle*>( |
+ ChildRouteIDPair(child_id, route_id), pending_throttle)); |
+} |
+ |
+void AwResourceDispatcherHostDelegate::OnIoThreadClientReadyInternal( |
+ int new_child_id, |
+ int new_route_id) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
+ PendingThrottleMap::iterator it = pending_throttles_.find( |
+ ChildRouteIDPair(new_child_id, new_route_id)); |
+ |
+ if (it != pending_throttles_.end()) { |
+ IoThreadClientThrottle* throttle = it->second; |
+ throttle->OnIoThreadClientReady(new_child_id, new_route_id); |
+ pending_throttles_.erase(it); |
+ } |
+} |
+ |
+} // namespace android_webview |