ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / android_webview / browser / renderer_host / aw_resource_dispatcher_host_delegate.cc
blob36f37d475348d75b0bd85d1d81a74ef288313eea
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
3 // found in the LICENSE file.
5 #include "android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.h"
7 #include <string>
9 #include "android_webview/browser/aw_contents_io_thread_client.h"
10 #include "android_webview/browser/aw_login_delegate.h"
11 #include "android_webview/browser/aw_resource_context.h"
12 #include "android_webview/common/url_constants.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/memory/scoped_vector.h"
15 #include "components/auto_login_parser/auto_login_parser.h"
16 #include "components/navigation_interception/intercept_navigation_delegate.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "content/public/browser/resource_controller.h"
19 #include "content/public/browser/resource_dispatcher_host.h"
20 #include "content/public/browser/resource_dispatcher_host_login_delegate.h"
21 #include "content/public/browser/resource_request_info.h"
22 #include "content/public/browser/resource_throttle.h"
23 #include "net/base/load_flags.h"
24 #include "net/base/net_errors.h"
25 #include "net/http/http_response_headers.h"
26 #include "net/url_request/url_request.h"
27 #include "url/url_constants.h"
29 using android_webview::AwContentsIoThreadClient;
30 using content::BrowserThread;
31 using content::ResourceType;
32 using navigation_interception::InterceptNavigationDelegate;
34 namespace {
36 base::LazyInstance<android_webview::AwResourceDispatcherHostDelegate>
37 g_webview_resource_dispatcher_host_delegate = LAZY_INSTANCE_INITIALIZER;
39 void SetCacheControlFlag(
40 net::URLRequest* request, int flag) {
41 const int all_cache_control_flags = net::LOAD_BYPASS_CACHE |
42 net::LOAD_VALIDATE_CACHE |
43 net::LOAD_PREFERRING_CACHE |
44 net::LOAD_ONLY_FROM_CACHE;
45 DCHECK_EQ((flag & all_cache_control_flags), flag);
46 int load_flags = request->load_flags();
47 load_flags &= ~all_cache_control_flags;
48 load_flags |= flag;
49 request->SetLoadFlags(load_flags);
52 } // namespace
54 namespace android_webview {
56 // Calls through the IoThreadClient to check the embedders settings to determine
57 // if the request should be cancelled. There may not always be an IoThreadClient
58 // available for the |render_process_id|, |render_frame_id| pair (in the case of
59 // newly created pop up windows, for example) and in that case the request and
60 // the client callbacks will be deferred the request until a client is ready.
61 class IoThreadClientThrottle : public content::ResourceThrottle {
62 public:
63 IoThreadClientThrottle(int render_process_id,
64 int render_frame_id,
65 net::URLRequest* request);
66 ~IoThreadClientThrottle() override;
68 // From content::ResourceThrottle
69 void WillStartRequest(bool* defer) override;
70 void WillRedirectRequest(const net::RedirectInfo& redirect_info,
71 bool* defer) override;
72 const char* GetNameForLogging() const override;
74 void OnIoThreadClientReady(int new_render_process_id,
75 int new_render_frame_id);
76 bool MaybeBlockRequest();
77 bool ShouldBlockRequest();
78 int render_process_id() const { return render_process_id_; }
79 int render_frame_id() const { return render_frame_id_; }
81 private:
82 int render_process_id_;
83 int render_frame_id_;
84 net::URLRequest* request_;
87 IoThreadClientThrottle::IoThreadClientThrottle(int render_process_id,
88 int render_frame_id,
89 net::URLRequest* request)
90 : render_process_id_(render_process_id),
91 render_frame_id_(render_frame_id),
92 request_(request) { }
94 IoThreadClientThrottle::~IoThreadClientThrottle() {
95 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
96 g_webview_resource_dispatcher_host_delegate.Get().
97 RemovePendingThrottleOnIoThread(this);
100 const char* IoThreadClientThrottle::GetNameForLogging() const {
101 return "IoThreadClientThrottle";
104 void IoThreadClientThrottle::WillStartRequest(bool* defer) {
105 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
106 if (render_frame_id_ < 1)
107 return;
108 DCHECK(render_process_id_);
109 *defer = false;
111 // Defer all requests of a pop up that is still not associated with Java
112 // client so that the client will get a chance to override requests.
113 scoped_ptr<AwContentsIoThreadClient> io_client =
114 AwContentsIoThreadClient::FromID(render_process_id_, render_frame_id_);
115 if (io_client && io_client->PendingAssociation()) {
116 *defer = true;
117 AwResourceDispatcherHostDelegate::AddPendingThrottle(
118 render_process_id_, render_frame_id_, this);
119 } else {
120 MaybeBlockRequest();
124 void IoThreadClientThrottle::WillRedirectRequest(
125 const net::RedirectInfo& redirect_info,
126 bool* defer) {
127 WillStartRequest(defer);
130 void IoThreadClientThrottle::OnIoThreadClientReady(int new_render_process_id,
131 int new_render_frame_id) {
132 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
134 if (!MaybeBlockRequest()) {
135 controller()->Resume();
139 bool IoThreadClientThrottle::MaybeBlockRequest() {
140 if (ShouldBlockRequest()) {
141 controller()->CancelWithError(net::ERR_ACCESS_DENIED);
142 return true;
144 return false;
147 bool IoThreadClientThrottle::ShouldBlockRequest() {
148 scoped_ptr<AwContentsIoThreadClient> io_client =
149 AwContentsIoThreadClient::FromID(render_process_id_, render_frame_id_);
150 if (!io_client)
151 return false;
153 // Part of implementation of WebSettings.allowContentAccess.
154 if (request_->url().SchemeIs(android_webview::kContentScheme) &&
155 io_client->ShouldBlockContentUrls()) {
156 return true;
159 // Part of implementation of WebSettings.allowFileAccess.
160 if (request_->url().SchemeIsFile() &&
161 io_client->ShouldBlockFileUrls()) {
162 const GURL& url = request_->url();
163 if (!url.has_path() ||
164 // Application's assets and resources are always available.
165 (url.path().find(android_webview::kAndroidResourcePath) != 0 &&
166 url.path().find(android_webview::kAndroidAssetPath) != 0)) {
167 return true;
171 if (io_client->ShouldBlockNetworkLoads()) {
172 if (request_->url().SchemeIs(url::kFtpScheme)) {
173 return true;
175 SetCacheControlFlag(request_, net::LOAD_ONLY_FROM_CACHE);
176 } else {
177 AwContentsIoThreadClient::CacheMode cache_mode = io_client->GetCacheMode();
178 switch(cache_mode) {
179 case AwContentsIoThreadClient::LOAD_CACHE_ELSE_NETWORK:
180 SetCacheControlFlag(request_, net::LOAD_PREFERRING_CACHE);
181 break;
182 case AwContentsIoThreadClient::LOAD_NO_CACHE:
183 SetCacheControlFlag(request_, net::LOAD_BYPASS_CACHE);
184 break;
185 case AwContentsIoThreadClient::LOAD_CACHE_ONLY:
186 SetCacheControlFlag(request_, net::LOAD_ONLY_FROM_CACHE);
187 break;
188 default:
189 break;
192 return false;
195 // static
196 void AwResourceDispatcherHostDelegate::ResourceDispatcherHostCreated() {
197 content::ResourceDispatcherHost::Get()->SetDelegate(
198 &g_webview_resource_dispatcher_host_delegate.Get());
201 AwResourceDispatcherHostDelegate::AwResourceDispatcherHostDelegate()
202 : content::ResourceDispatcherHostDelegate() {
205 AwResourceDispatcherHostDelegate::~AwResourceDispatcherHostDelegate() {
208 void AwResourceDispatcherHostDelegate::RequestBeginning(
209 net::URLRequest* request,
210 content::ResourceContext* resource_context,
211 content::AppCacheService* appcache_service,
212 ResourceType resource_type,
213 ScopedVector<content::ResourceThrottle>* throttles) {
215 AddExtraHeadersIfNeeded(request, resource_context);
217 const content::ResourceRequestInfo* request_info =
218 content::ResourceRequestInfo::ForRequest(request);
220 // We always push the throttles here. Checking the existence of io_client
221 // is racy when a popup window is created. That is because RequestBeginning
222 // is called whether or not requests are blocked via BlockRequestForRoute()
223 // however io_client may or may not be ready at the time depending on whether
224 // webcontents is created.
225 throttles->push_back(new IoThreadClientThrottle(
226 request_info->GetChildID(), request_info->GetRenderFrameID(), request));
228 // We allow intercepting only navigations within main frames. This
229 // is used to post onPageStarted. We handle shouldOverrideUrlLoading
230 // via a sync IPC.
231 if (resource_type == content::RESOURCE_TYPE_MAIN_FRAME)
232 throttles->push_back(InterceptNavigationDelegate::CreateThrottleFor(
233 request));
236 void AwResourceDispatcherHostDelegate::OnRequestRedirected(
237 const GURL& redirect_url,
238 net::URLRequest* request,
239 content::ResourceContext* resource_context,
240 content::ResourceResponse* response) {
241 AddExtraHeadersIfNeeded(request, resource_context);
245 void AwResourceDispatcherHostDelegate::DownloadStarting(
246 net::URLRequest* request,
247 content::ResourceContext* resource_context,
248 int child_id,
249 int route_id,
250 int request_id,
251 bool is_content_initiated,
252 bool must_download,
253 ScopedVector<content::ResourceThrottle>* throttles) {
254 GURL url(request->url());
255 std::string user_agent;
256 std::string content_disposition;
257 std::string mime_type;
258 int64 content_length = request->GetExpectedContentSize();
260 request->extra_request_headers().GetHeader(
261 net::HttpRequestHeaders::kUserAgent, &user_agent);
264 net::HttpResponseHeaders* response_headers = request->response_headers();
265 if (response_headers) {
266 response_headers->GetNormalizedHeader("content-disposition",
267 &content_disposition);
268 response_headers->GetMimeType(&mime_type);
271 request->Cancel();
273 const content::ResourceRequestInfo* request_info =
274 content::ResourceRequestInfo::ForRequest(request);
276 scoped_ptr<AwContentsIoThreadClient> io_client =
277 AwContentsIoThreadClient::FromID(
278 child_id, request_info->GetRenderFrameID());
280 // POST request cannot be repeated in general, so prevent client from
281 // retrying the same request, even if it is with a GET.
282 if ("GET" == request->method() && io_client) {
283 io_client->NewDownload(url,
284 user_agent,
285 content_disposition,
286 mime_type,
287 content_length);
291 content::ResourceDispatcherHostLoginDelegate*
292 AwResourceDispatcherHostDelegate::CreateLoginDelegate(
293 net::AuthChallengeInfo* auth_info,
294 net::URLRequest* request) {
295 return new AwLoginDelegate(auth_info, request);
298 bool AwResourceDispatcherHostDelegate::HandleExternalProtocol(const GURL& url,
299 int child_id,
300 int route_id) {
301 // The AwURLRequestJobFactory implementation should ensure this method never
302 // gets called.
303 NOTREACHED();
304 return false;
307 void AwResourceDispatcherHostDelegate::OnResponseStarted(
308 net::URLRequest* request,
309 content::ResourceContext* resource_context,
310 content::ResourceResponse* response,
311 IPC::Sender* sender) {
312 const content::ResourceRequestInfo* request_info =
313 content::ResourceRequestInfo::ForRequest(request);
314 if (!request_info) {
315 DLOG(FATAL) << "Started request without associated info: " <<
316 request->url();
317 return;
320 if (request_info->GetResourceType() == content::RESOURCE_TYPE_MAIN_FRAME) {
321 // Check for x-auto-login header.
322 auto_login_parser::HeaderData header_data;
323 if (auto_login_parser::ParserHeaderInResponse(
324 request, auto_login_parser::ALLOW_ANY_REALM, &header_data)) {
325 scoped_ptr<AwContentsIoThreadClient> io_client =
326 AwContentsIoThreadClient::FromID(request_info->GetChildID(),
327 request_info->GetRenderFrameID());
328 if (io_client) {
329 io_client->NewLoginRequest(
330 header_data.realm, header_data.account, header_data.args);
336 void AwResourceDispatcherHostDelegate::RemovePendingThrottleOnIoThread(
337 IoThreadClientThrottle* throttle) {
338 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
339 PendingThrottleMap::iterator it = pending_throttles_.find(
340 FrameRouteIDPair(throttle->render_process_id(),
341 throttle->render_frame_id()));
342 if (it != pending_throttles_.end()) {
343 pending_throttles_.erase(it);
347 // static
348 void AwResourceDispatcherHostDelegate::OnIoThreadClientReady(
349 int new_render_process_id,
350 int new_render_frame_id) {
351 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
352 base::Bind(
353 &AwResourceDispatcherHostDelegate::OnIoThreadClientReadyInternal,
354 base::Unretained(
355 g_webview_resource_dispatcher_host_delegate.Pointer()),
356 new_render_process_id, new_render_frame_id));
359 // static
360 void AwResourceDispatcherHostDelegate::AddPendingThrottle(
361 int render_process_id,
362 int render_frame_id,
363 IoThreadClientThrottle* pending_throttle) {
364 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
365 base::Bind(
366 &AwResourceDispatcherHostDelegate::AddPendingThrottleOnIoThread,
367 base::Unretained(
368 g_webview_resource_dispatcher_host_delegate.Pointer()),
369 render_process_id, render_frame_id, pending_throttle));
372 void AwResourceDispatcherHostDelegate::AddPendingThrottleOnIoThread(
373 int render_process_id,
374 int render_frame_id_id,
375 IoThreadClientThrottle* pending_throttle) {
376 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
377 pending_throttles_.insert(
378 std::pair<FrameRouteIDPair, IoThreadClientThrottle*>(
379 FrameRouteIDPair(render_process_id, render_frame_id_id),
380 pending_throttle));
383 void AwResourceDispatcherHostDelegate::OnIoThreadClientReadyInternal(
384 int new_render_process_id,
385 int new_render_frame_id) {
386 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
387 PendingThrottleMap::iterator it = pending_throttles_.find(
388 FrameRouteIDPair(new_render_process_id, new_render_frame_id));
390 if (it != pending_throttles_.end()) {
391 IoThreadClientThrottle* throttle = it->second;
392 throttle->OnIoThreadClientReady(new_render_process_id, new_render_frame_id);
393 pending_throttles_.erase(it);
397 void AwResourceDispatcherHostDelegate::AddExtraHeadersIfNeeded(
398 net::URLRequest* request,
399 content::ResourceContext* resource_context) {
400 const content::ResourceRequestInfo* request_info =
401 content::ResourceRequestInfo::ForRequest(request);
402 if (!request_info)
403 return;
404 if (request_info->GetResourceType() != content::RESOURCE_TYPE_MAIN_FRAME)
405 return;
407 const ui::PageTransition transition = request_info->GetPageTransition();
408 const bool is_load_url =
409 transition & ui::PAGE_TRANSITION_FROM_API;
410 const bool is_go_back_forward =
411 transition & ui::PAGE_TRANSITION_FORWARD_BACK;
412 const bool is_reload = ui::PageTransitionCoreTypeIs(
413 transition, ui::PAGE_TRANSITION_RELOAD);
414 if (is_load_url || is_go_back_forward || is_reload) {
415 AwResourceContext* awrc = static_cast<AwResourceContext*>(resource_context);
416 std::string extra_headers = awrc->GetExtraHeaders(request->url());
417 if (!extra_headers.empty()) {
418 net::HttpRequestHeaders headers;
419 headers.AddHeadersFromString(extra_headers);
420 for (net::HttpRequestHeaders::Iterator it(headers); it.GetNext(); ) {
421 request->SetExtraRequestHeaderByName(it.name(), it.value(), false);
427 } // namespace android_webview