OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "android_webview/browser/renderer_host/aw_resource_dispatcher_host_dele
gate.h" | 5 #include "android_webview/browser/renderer_host/aw_resource_dispatcher_host_dele
gate.h" |
6 | 6 |
| 7 #include "android_webview/browser/aw_contents_io_thread_client.h" |
7 #include "android_webview/browser/aw_login_delegate.h" | 8 #include "android_webview/browser/aw_login_delegate.h" |
8 #include "android_webview/browser/aw_contents_io_thread_client.h" | |
9 #include "android_webview/common/url_constants.h" | 9 #include "android_webview/common/url_constants.h" |
10 #include "base/memory/scoped_ptr.h" | 10 #include "base/memory/scoped_ptr.h" |
11 #include "base/memory/scoped_vector.h" | 11 #include "base/memory/scoped_vector.h" |
12 #include "content/components/navigation_interception/intercept_navigation_delega
te.h" | 12 #include "content/components/navigation_interception/intercept_navigation_delega
te.h" |
| 13 #include "content/public/browser/browser_thread.h" |
13 #include "content/public/browser/resource_controller.h" | 14 #include "content/public/browser/resource_controller.h" |
14 #include "content/public/browser/resource_dispatcher_host.h" | 15 #include "content/public/browser/resource_dispatcher_host.h" |
15 #include "content/public/browser/resource_dispatcher_host_login_delegate.h" | 16 #include "content/public/browser/resource_dispatcher_host_login_delegate.h" |
16 #include "content/public/browser/resource_throttle.h" | 17 #include "content/public/browser/resource_throttle.h" |
17 #include "content/public/common/url_constants.h" | 18 #include "content/public/common/url_constants.h" |
18 #include "net/base/load_flags.h" | 19 #include "net/base/load_flags.h" |
19 #include "net/url_request/url_request.h" | 20 #include "net/url_request/url_request.h" |
20 | 21 |
| 22 using android_webview::AwContentsIoThreadClient; |
| 23 using content::BrowserThread; |
21 using content::InterceptNavigationDelegate; | 24 using content::InterceptNavigationDelegate; |
22 | 25 |
23 namespace { | 26 namespace { |
24 | 27 |
25 using android_webview::AwContentsIoThreadClient; | |
26 | |
27 base::LazyInstance<android_webview::AwResourceDispatcherHostDelegate> | 28 base::LazyInstance<android_webview::AwResourceDispatcherHostDelegate> |
28 g_webview_resource_dispatcher_host_delegate = LAZY_INSTANCE_INITIALIZER; | 29 g_webview_resource_dispatcher_host_delegate = LAZY_INSTANCE_INITIALIZER; |
29 | 30 |
30 void SetCacheControlFlag( | 31 void SetCacheControlFlag( |
31 net::URLRequest* request, int flag) { | 32 net::URLRequest* request, int flag) { |
32 const int all_cache_control_flags = net::LOAD_BYPASS_CACHE | | 33 const int all_cache_control_flags = net::LOAD_BYPASS_CACHE | |
33 net::LOAD_VALIDATE_CACHE | | 34 net::LOAD_VALIDATE_CACHE | |
34 net::LOAD_PREFERRING_CACHE | | 35 net::LOAD_PREFERRING_CACHE | |
35 net::LOAD_ONLY_FROM_CACHE; | 36 net::LOAD_ONLY_FROM_CACHE; |
36 DCHECK((flag & all_cache_control_flags) == flag); | 37 DCHECK((flag & all_cache_control_flags) == flag); |
37 int load_flags = request->load_flags(); | 38 int load_flags = request->load_flags(); |
38 load_flags &= ~all_cache_control_flags; | 39 load_flags &= ~all_cache_control_flags; |
39 load_flags |= flag; | 40 load_flags |= flag; |
40 request->set_load_flags(load_flags); | 41 request->set_load_flags(load_flags); |
41 } | 42 } |
42 | 43 |
| 44 } // namespace |
| 45 |
| 46 namespace android_webview { |
| 47 |
43 // Calls through the IoThreadClient to check the embedders settings to determine | 48 // Calls through the IoThreadClient to check the embedders settings to determine |
44 // if the request should be cancelled. | 49 // if the request should be cancelled. There may not always be an IoThreadClient |
| 50 // available for the |child_id|, |route_id| pair (in the case of newly created |
| 51 // pop up windows, for example) and in that case the request and the client |
| 52 // callbacks will be deferred the request until a client is ready. |
45 class IoThreadClientThrottle : public content::ResourceThrottle { | 53 class IoThreadClientThrottle : public content::ResourceThrottle { |
46 public: | 54 public: |
47 IoThreadClientThrottle(int child_id, | 55 IoThreadClientThrottle(int child_id, |
48 int route_id, | 56 int route_id, |
49 net::URLRequest* request) | 57 net::URLRequest* request); |
50 : child_id_(child_id), | 58 virtual ~IoThreadClientThrottle(); |
51 route_id_(route_id), | 59 |
52 request_(request) { } | 60 // From content::ResourceThrottle |
53 virtual void WillStartRequest(bool* defer) OVERRIDE; | 61 virtual void WillStartRequest(bool* defer) OVERRIDE; |
| 62 virtual void WillRedirectRequest(const GURL& new_url, bool* defer) OVERRIDE; |
54 | 63 |
55 scoped_ptr<AwContentsIoThreadClient> GetIoThreadClient() { | 64 bool MaybeDeferRequest(bool* defer); |
56 return AwContentsIoThreadClient::FromID(child_id_, route_id_); | 65 void OnIoThreadClientReady(int new_child_id, int new_route_id); |
57 } | 66 bool MaybeBlockRequest(); |
| 67 bool ShouldBlockRequest(); |
| 68 scoped_ptr<AwContentsIoThreadClient> GetIoThreadClient(); |
| 69 int get_child_id() const { return child_id_; } |
| 70 int get_route_id() const { return route_id_; } |
58 | 71 |
59 private: | 72 private: |
60 int child_id_; | 73 int child_id_; |
61 int route_id_; | 74 int route_id_; |
62 net::URLRequest* request_; | 75 net::URLRequest* request_; |
63 }; | 76 }; |
64 | 77 |
| 78 IoThreadClientThrottle::IoThreadClientThrottle(int child_id, |
| 79 int route_id, |
| 80 net::URLRequest* request) |
| 81 : child_id_(child_id), |
| 82 route_id_(route_id), |
| 83 request_(request) { } |
| 84 |
| 85 IoThreadClientThrottle::~IoThreadClientThrottle() { |
| 86 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 87 g_webview_resource_dispatcher_host_delegate.Get(). |
| 88 RemovePendingThrottleOnIoThread(this); |
| 89 } |
| 90 |
65 void IoThreadClientThrottle::WillStartRequest(bool* defer) { | 91 void IoThreadClientThrottle::WillStartRequest(bool* defer) { |
66 // If there is no IO thread client set at this point, use a | 92 if (!MaybeDeferRequest(defer)) { |
67 // restrictive policy. This can happen for blocked popup | 93 MaybeBlockRequest(); |
68 // windows for example. | 94 } |
69 // TODO(benm): Revert this to a DCHECK when the we support | 95 } |
70 // pop up windows being created in the WebView, as at that | 96 |
71 // time we should always have an IoThreadClient at this | 97 void IoThreadClientThrottle::WillRedirectRequest(const GURL& new_url, |
72 // point (i.e., the one associated with the new popup). | 98 bool* defer) { |
73 if (!GetIoThreadClient()) { | 99 WillStartRequest(defer); |
| 100 } |
| 101 |
| 102 bool IoThreadClientThrottle::MaybeDeferRequest(bool* defer) { |
| 103 scoped_ptr<AwContentsIoThreadClient> io_client = |
| 104 AwContentsIoThreadClient::FromID(child_id_, route_id_); |
| 105 *defer = false; |
| 106 if (!io_client.get()) { |
| 107 *defer = true; |
| 108 AwResourceDispatcherHostDelegate::AddPendingThrottle( |
| 109 child_id_, route_id_, this); |
| 110 } |
| 111 return *defer; |
| 112 } |
| 113 |
| 114 void IoThreadClientThrottle::OnIoThreadClientReady(int new_child_id, |
| 115 int new_route_id) { |
| 116 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 117 |
| 118 if (!MaybeBlockRequest()) { |
| 119 controller()->Resume(); |
| 120 } |
| 121 } |
| 122 |
| 123 bool IoThreadClientThrottle::MaybeBlockRequest() { |
| 124 if (ShouldBlockRequest()) { |
74 controller()->CancelWithError(net::ERR_ACCESS_DENIED); | 125 controller()->CancelWithError(net::ERR_ACCESS_DENIED); |
75 return; | 126 return true; |
76 } | 127 } |
| 128 return false; |
| 129 } |
| 130 |
| 131 bool IoThreadClientThrottle::ShouldBlockRequest() { |
| 132 scoped_ptr<AwContentsIoThreadClient> io_client = |
| 133 AwContentsIoThreadClient::FromID(child_id_, route_id_); |
| 134 DCHECK(io_client.get()); |
77 | 135 |
78 // Part of implementation of WebSettings.allowContentAccess. | 136 // Part of implementation of WebSettings.allowContentAccess. |
79 if (request_->url().SchemeIs(android_webview::kContentScheme) && | 137 if (request_->url().SchemeIs(android_webview::kContentScheme) && |
80 GetIoThreadClient()->ShouldBlockContentUrls()) { | 138 io_client->ShouldBlockContentUrls()) { |
81 controller()->CancelWithError(net::ERR_ACCESS_DENIED); | 139 return true; |
82 return; | |
83 } | 140 } |
84 | 141 |
85 // Part of implementation of WebSettings.allowFileAccess. | 142 // Part of implementation of WebSettings.allowFileAccess. |
86 if (request_->url().SchemeIsFile() && | 143 if (request_->url().SchemeIsFile() && |
87 GetIoThreadClient()->ShouldBlockFileUrls()) { | 144 io_client->ShouldBlockFileUrls()) { |
88 const GURL& url = request_->url(); | 145 const GURL& url = request_->url(); |
89 if (!url.has_path() || | 146 if (!url.has_path() || |
90 // Application's assets and resources are always available. | 147 // Application's assets and resources are always available. |
91 (url.path().find(android_webview::kAndroidResourcePath) != 0 && | 148 (url.path().find(android_webview::kAndroidResourcePath) != 0 && |
92 url.path().find(android_webview::kAndroidAssetPath) != 0)) { | 149 url.path().find(android_webview::kAndroidAssetPath) != 0)) { |
93 controller()->CancelWithError(net::ERR_ACCESS_DENIED); | 150 return true; |
94 return; | |
95 } | 151 } |
96 } | 152 } |
97 | 153 |
98 if (GetIoThreadClient()->ShouldBlockNetworkLoads()) { | 154 if (io_client->ShouldBlockNetworkLoads()) { |
99 if (request_->url().SchemeIs(chrome::kFtpScheme)) { | 155 if (request_->url().SchemeIs(chrome::kFtpScheme)) { |
100 controller()->CancelWithError(net::ERR_ACCESS_DENIED); | 156 return true; |
101 return; | |
102 } | 157 } |
103 SetCacheControlFlag(request_, net::LOAD_ONLY_FROM_CACHE); | 158 SetCacheControlFlag(request_, net::LOAD_ONLY_FROM_CACHE); |
104 } else { | 159 } else { |
105 AwContentsIoThreadClient::CacheMode cache_mode = | 160 AwContentsIoThreadClient::CacheMode cache_mode = |
106 GetIoThreadClient()->GetCacheMode(); | 161 GetIoThreadClient()->GetCacheMode(); |
107 switch(cache_mode) { | 162 switch(cache_mode) { |
108 case AwContentsIoThreadClient::LOAD_CACHE_ELSE_NETWORK: | 163 case AwContentsIoThreadClient::LOAD_CACHE_ELSE_NETWORK: |
109 SetCacheControlFlag(request_, net::LOAD_PREFERRING_CACHE); | 164 SetCacheControlFlag(request_, net::LOAD_PREFERRING_CACHE); |
110 break; | 165 break; |
111 case AwContentsIoThreadClient::LOAD_NO_CACHE: | 166 case AwContentsIoThreadClient::LOAD_NO_CACHE: |
112 SetCacheControlFlag(request_, net::LOAD_BYPASS_CACHE); | 167 SetCacheControlFlag(request_, net::LOAD_BYPASS_CACHE); |
113 break; | 168 break; |
114 case AwContentsIoThreadClient::LOAD_CACHE_ONLY: | 169 case AwContentsIoThreadClient::LOAD_CACHE_ONLY: |
115 SetCacheControlFlag(request_, net::LOAD_ONLY_FROM_CACHE); | 170 SetCacheControlFlag(request_, net::LOAD_ONLY_FROM_CACHE); |
116 break; | 171 break; |
117 default: | 172 default: |
118 break; | 173 break; |
119 } | 174 } |
120 } | 175 } |
| 176 return false; |
121 } | 177 } |
122 | 178 |
123 } // namespace | 179 scoped_ptr<AwContentsIoThreadClient> |
124 | 180 IoThreadClientThrottle::GetIoThreadClient() { |
125 namespace android_webview { | 181 return AwContentsIoThreadClient::FromID(child_id_, route_id_); |
| 182 } |
126 | 183 |
127 // static | 184 // static |
128 void AwResourceDispatcherHostDelegate::ResourceDispatcherHostCreated() { | 185 void AwResourceDispatcherHostDelegate::ResourceDispatcherHostCreated() { |
129 content::ResourceDispatcherHost::Get()->SetDelegate( | 186 content::ResourceDispatcherHost::Get()->SetDelegate( |
130 &g_webview_resource_dispatcher_host_delegate.Get()); | 187 &g_webview_resource_dispatcher_host_delegate.Get()); |
131 } | 188 } |
132 | 189 |
133 AwResourceDispatcherHostDelegate::AwResourceDispatcherHostDelegate() | 190 AwResourceDispatcherHostDelegate::AwResourceDispatcherHostDelegate() |
134 : content::ResourceDispatcherHostDelegate() { | 191 : content::ResourceDispatcherHostDelegate() { |
135 } | 192 } |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
186 | 243 |
187 bool AwResourceDispatcherHostDelegate::HandleExternalProtocol(const GURL& url, | 244 bool AwResourceDispatcherHostDelegate::HandleExternalProtocol(const GURL& url, |
188 int child_id, | 245 int child_id, |
189 int route_id) { | 246 int route_id) { |
190 // The AwURLRequestJobFactory implementation should ensure this method never | 247 // The AwURLRequestJobFactory implementation should ensure this method never |
191 // gets called. | 248 // gets called. |
192 NOTREACHED(); | 249 NOTREACHED(); |
193 return false; | 250 return false; |
194 } | 251 } |
195 | 252 |
| 253 void AwResourceDispatcherHostDelegate::RemovePendingThrottleOnIoThread( |
| 254 IoThreadClientThrottle* throttle) { |
| 255 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 256 PendingThrottleMap::iterator it = pending_throttles_.find( |
| 257 ChildRouteIDPair(throttle->get_child_id(), throttle->get_route_id())); |
| 258 if (it != pending_throttles_.end()) { |
| 259 pending_throttles_.erase(it); |
| 260 } |
196 } | 261 } |
| 262 |
| 263 // static |
| 264 void AwResourceDispatcherHostDelegate::OnIoThreadClientReady( |
| 265 int new_child_id, |
| 266 int new_route_id) { |
| 267 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
| 268 base::Bind( |
| 269 &AwResourceDispatcherHostDelegate::OnIoThreadClientReadyInternal, |
| 270 base::Unretained( |
| 271 g_webview_resource_dispatcher_host_delegate.Pointer()), |
| 272 new_child_id, new_route_id)); |
| 273 } |
| 274 |
| 275 // static |
| 276 void AwResourceDispatcherHostDelegate::AddPendingThrottle( |
| 277 int child_id, |
| 278 int route_id, |
| 279 IoThreadClientThrottle* pending_throttle) { |
| 280 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
| 281 base::Bind( |
| 282 &AwResourceDispatcherHostDelegate::AddPendingThrottleOnIoThread, |
| 283 base::Unretained( |
| 284 g_webview_resource_dispatcher_host_delegate.Pointer()), |
| 285 child_id, route_id, pending_throttle)); |
| 286 } |
| 287 |
| 288 void AwResourceDispatcherHostDelegate::AddPendingThrottleOnIoThread( |
| 289 int child_id, |
| 290 int route_id, |
| 291 IoThreadClientThrottle* pending_throttle) { |
| 292 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 293 pending_throttles_.insert( |
| 294 std::pair<ChildRouteIDPair, IoThreadClientThrottle*>( |
| 295 ChildRouteIDPair(child_id, route_id), pending_throttle)); |
| 296 } |
| 297 |
| 298 void AwResourceDispatcherHostDelegate::OnIoThreadClientReadyInternal( |
| 299 int new_child_id, |
| 300 int new_route_id) { |
| 301 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 302 PendingThrottleMap::iterator it = pending_throttles_.find( |
| 303 ChildRouteIDPair(new_child_id, new_route_id)); |
| 304 |
| 305 if (it != pending_throttles_.end()) { |
| 306 IoThreadClientThrottle* throttle = it->second; |
| 307 throttle->OnIoThreadClientReady(new_child_id, new_route_id); |
| 308 pending_throttles_.erase(it); |
| 309 } |
| 310 } |
| 311 |
| 312 } // namespace android_webview |
OLD | NEW |