Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / xwalk / runtime / browser / runtime_resource_dispatcher_host_delegate_android.cc
1 // Copyright (c) 2013 Intel Corporation. All rights reserved.
2 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5
6 #include "xwalk/runtime/browser/runtime_resource_dispatcher_host_delegate_android.h"
7
8 #include <string>
9 #include <utility>
10
11 #include "base/memory/scoped_ptr.h"
12 #include "base/memory/scoped_vector.h"
13 #include "components/auto_login_parser/auto_login_parser.h"
14 #include "components/navigation_interception/intercept_navigation_delegate.h"
15 #include "content/public/browser/browser_thread.h"
16 #include "content/public/browser/resource_controller.h"
17 #include "content/public/browser/resource_request_info.h"
18 #include "content/public/browser/resource_throttle.h"
19 #include "content/public/common/url_constants.h"
20 #include "net/base/load_flags.h"
21 #include "net/base/net_errors.h"
22 #include "net/http/http_response_headers.h"
23 #include "net/url_request/url_request.h"
24 #include "xwalk/runtime/browser/android/net/url_constants.h"
25 #include "xwalk/runtime/browser/android/xwalk_contents_io_thread_client.h"
26 #include "xwalk/runtime/browser/android/xwalk_download_resource_throttle.h"
27 #include "xwalk/runtime/browser/android/xwalk_login_delegate.h"
28 #include "xwalk/runtime/browser/xwalk_content_browser_client.h"
29 #include "xwalk/runtime/common/xwalk_content_client.h"
30
31 using content::BrowserThread;
32 using navigation_interception::InterceptNavigationDelegate;
33 using xwalk::XWalkContentsIoThreadClient;
34
35 namespace {
36 void SetCacheControlFlag(
37     net::URLRequest* request, int flag) {
38   const int all_cache_control_flags = net::LOAD_BYPASS_CACHE |
39       net::LOAD_VALIDATE_CACHE |
40       net::LOAD_PREFERRING_CACHE |
41       net::LOAD_ONLY_FROM_CACHE;
42   DCHECK((flag & all_cache_control_flags) == flag);
43   int load_flags = request->load_flags();
44   load_flags &= ~all_cache_control_flags;
45   load_flags |= flag;
46   request->SetLoadFlags(load_flags);
47 }
48 }  // namespace
49
50 namespace xwalk {
51
52 // Calls through the IoThreadClient to check the embedders settings to determine
53 // if the request should be cancelled. There may not always be an IoThreadClient
54 // available for the |render_process_id|, |render_frame_id| pair (in the case of
55 // newly created pop up windows, for example) and in that case the request and
56 // the client callbacks will be deferred the request until a client is ready.
57 class IoThreadClientThrottle : public content::ResourceThrottle {
58  public:
59   IoThreadClientThrottle(int render_process_id,
60                          int render_frame_id,
61                          net::URLRequest* request);
62   virtual ~IoThreadClientThrottle();
63
64   // From content::ResourceThrottle
65   void WillStartRequest(bool* defer) override;
66   void WillRedirectRequest(const GURL& new_url, bool* defer) override;
67   const char* GetNameForLogging() const override;
68
69   bool MaybeDeferRequest(bool* defer);
70   void OnIoThreadClientReady(int new_render_process_id,
71                              int new_render_frame_id);
72   bool MaybeBlockRequest();
73   bool ShouldBlockRequest();
74   int render_process_id() const { return render_process_id_; }
75   int render_frame_id() const { return render_frame_id_; }
76
77  private:
78   int render_process_id_;
79   int render_frame_id_;
80   net::URLRequest* request_;
81 };
82
83 IoThreadClientThrottle::IoThreadClientThrottle(int render_process_id,
84                                                int render_frame_id,
85                                                net::URLRequest* request)
86     : render_process_id_(render_process_id),
87       render_frame_id_(render_frame_id),
88       request_(request) { }
89
90 IoThreadClientThrottle::~IoThreadClientThrottle() {
91   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
92   static_cast<RuntimeResourceDispatcherHostDelegateAndroid*>(
93       XWalkContentBrowserClient::Get()->resource_dispatcher_host_delegate())->
94       RemovePendingThrottleOnIoThread(this);
95 }
96
97 void IoThreadClientThrottle::WillStartRequest(bool* defer) {
98   if (render_frame_id_ < 1) {
99     // OPTIONS is used for preflighted requests which are generated internally.
100     DCHECK_EQ("OPTIONS", request_->method());
101     return;
102   }
103   DCHECK(render_process_id_);
104   if (!MaybeDeferRequest(defer)) {
105     MaybeBlockRequest();
106   }
107 }
108
109 void IoThreadClientThrottle::WillRedirectRequest(const GURL& new_url,
110                                                  bool* defer) {
111   WillStartRequest(defer);
112 }
113
114 const char* IoThreadClientThrottle::GetNameForLogging() const {
115   return "IoThreadClientThrottle";
116 }
117
118 bool IoThreadClientThrottle::MaybeDeferRequest(bool* defer) {
119   *defer = false;
120
121   // Defer all requests of a pop up that is still not associated with Java
122   // client so that the client will get a chance to override requests.
123   scoped_ptr<XWalkContentsIoThreadClient> io_client =
124       XWalkContentsIoThreadClient::FromID(render_process_id_, render_frame_id_);
125   if (io_client && io_client->PendingAssociation()) {
126     *defer = true;
127     RuntimeResourceDispatcherHostDelegateAndroid::AddPendingThrottle(
128         render_process_id_, render_frame_id_, this);
129   }
130   return *defer;
131 }
132
133 void IoThreadClientThrottle::OnIoThreadClientReady(int new_render_process_id,
134                                                    int new_render_frame_id) {
135   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
136
137   if (!MaybeBlockRequest()) {
138     controller()->Resume();
139   }
140 }
141
142 bool IoThreadClientThrottle::MaybeBlockRequest() {
143   if (ShouldBlockRequest()) {
144     controller()->CancelWithError(net::ERR_ACCESS_DENIED);
145     return true;
146   }
147   return false;
148 }
149
150 bool IoThreadClientThrottle::ShouldBlockRequest() {
151   scoped_ptr<XWalkContentsIoThreadClient> io_client =
152       XWalkContentsIoThreadClient::FromID(render_process_id_, render_frame_id_);
153   DCHECK(io_client.get());
154
155   // Part of implementation of WebSettings.allowContentAccess.
156   if (request_->url().SchemeIs(xwalk::kContentScheme) &&
157       io_client->ShouldBlockContentUrls()) {
158     return true;
159   }
160
161   // Part of implementation of WebSettings.allowFileAccess.
162   if (request_->url().SchemeIsFile() &&
163       io_client->ShouldBlockFileUrls()) {
164     const GURL& url = request_->url();
165     if (!url.has_path() ||
166         // Application's assets and resources are always available.
167         (url.path().find(xwalk::kAndroidResourcePath) != 0 &&
168          url.path().find(xwalk::kAndroidAssetPath) != 0)) {
169       return true;
170     }
171   }
172
173   if (io_client->ShouldBlockNetworkLoads()) {
174     if (request_->url().SchemeIs(url::kFtpScheme)) {
175       return true;
176     }
177     SetCacheControlFlag(request_, net::LOAD_ONLY_FROM_CACHE);
178   } else {
179     XWalkContentsIoThreadClient::CacheMode cache_mode =
180         io_client->GetCacheMode();
181     switch (cache_mode) {
182       case XWalkContentsIoThreadClient::LOAD_CACHE_ELSE_NETWORK:
183         SetCacheControlFlag(request_, net::LOAD_PREFERRING_CACHE);
184         break;
185       case XWalkContentsIoThreadClient::LOAD_NO_CACHE:
186         SetCacheControlFlag(request_, net::LOAD_BYPASS_CACHE);
187         break;
188       case XWalkContentsIoThreadClient::LOAD_CACHE_ONLY:
189         SetCacheControlFlag(request_, net::LOAD_ONLY_FROM_CACHE);
190         break;
191       default:
192         break;
193     }
194   }
195   return false;
196 }
197
198 RuntimeResourceDispatcherHostDelegateAndroid::
199     RuntimeResourceDispatcherHostDelegateAndroid() {
200 }
201
202 RuntimeResourceDispatcherHostDelegateAndroid::
203     ~RuntimeResourceDispatcherHostDelegateAndroid() {
204 }
205
206 void RuntimeResourceDispatcherHostDelegateAndroid::RequestBeginning(
207     net::URLRequest* request,
208     content::ResourceContext* resource_context,
209     content::AppCacheService* appcache_service,
210     content::ResourceType resource_type,
211     ScopedVector<content::ResourceThrottle>* throttles) {
212   const content::ResourceRequestInfo* request_info =
213       content::ResourceRequestInfo::ForRequest(request);
214
215   // We allow intercepting only navigations within main frames. This
216   // is used to post onPageStarted. We handle shouldOverrideUrlLoading
217   // via a sync IPC for url loading in iframe.
218   if (resource_type == content::RESOURCE_TYPE_MAIN_FRAME) {
219     throttles->push_back(InterceptNavigationDelegate::CreateThrottleFor(
220         request));
221   }
222
223   // If io_client is NULL, then the browser side objects have already been
224   // destroyed, so do not do anything to the request. Conversely if the
225   // request relates to a not-yet-created popup window, then the client will
226   // be non-NULL but PopupPendingAssociation() will be set.
227   scoped_ptr<XWalkContentsIoThreadClient> io_client =
228       XWalkContentsIoThreadClient::FromID(
229           request_info->GetChildID(), request_info->GetRenderFrameID());
230   if (!io_client)
231     return;
232
233   throttles->push_back(new IoThreadClientThrottle(
234       request_info->GetChildID(), request_info->GetRenderFrameID(), request));
235 }
236
237 void RuntimeResourceDispatcherHostDelegateAndroid::DownloadStarting(
238     net::URLRequest* request,
239     content::ResourceContext* resource_context,
240     int child_id,
241     int route_id,
242     int request_id,
243     bool is_content_initiated,
244     bool must_download,
245     ScopedVector<content::ResourceThrottle>* throttles) {
246   GURL url(request->url());
247   std::string user_agent;
248   std::string content_disposition;
249   std::string mime_type;
250   int64 content_length = request->GetExpectedContentSize();
251
252   if (!request->extra_request_headers().GetHeader(
253       net::HttpRequestHeaders::kUserAgent, &user_agent))
254     user_agent = xwalk::GetUserAgent();
255
256   net::HttpResponseHeaders* response_headers = request->response_headers();
257   if (response_headers) {
258     response_headers->GetNormalizedHeader("content-disposition",
259         &content_disposition);
260     response_headers->GetMimeType(&mime_type);
261   }
262
263   request->Cancel();
264
265   const content::ResourceRequestInfo* request_info =
266       content::ResourceRequestInfo::ForRequest(request);
267
268   scoped_ptr<XWalkContentsIoThreadClient> io_client =
269       XWalkContentsIoThreadClient::FromID(
270           child_id, request_info->GetRenderFrameID());
271
272   // POST request cannot be repeated in general, so prevent client from
273   // retrying the same request, even if it is with a GET.
274   if ("GET" == request->method() && io_client) {
275     io_client->NewDownload(url,
276                            user_agent,
277                            content_disposition,
278                            mime_type,
279                            content_length);
280   }
281 }
282
283 content::ResourceDispatcherHostLoginDelegate*
284     RuntimeResourceDispatcherHostDelegateAndroid::CreateLoginDelegate(
285         net::AuthChallengeInfo* auth_info,
286         net::URLRequest* request) {
287   return new XWalkLoginDelegate(auth_info, request);
288 }
289
290 bool RuntimeResourceDispatcherHostDelegateAndroid::HandleExternalProtocol(
291     const GURL& url,
292     int child_id,
293     int route_id) {
294   // On Android, there are many Uris need to be handled differently.
295   // e.g: sms:, tel:, mailto: and etc.
296   // So here return false to let embedders to decide which protocol
297   // to be handled.
298   return false;
299 }
300
301 void RuntimeResourceDispatcherHostDelegateAndroid::OnResponseStarted(
302     net::URLRequest* request,
303     content::ResourceContext* resource_context,
304     content::ResourceResponse* response,
305     IPC::Sender* sender) {
306   const content::ResourceRequestInfo* request_info =
307       content::ResourceRequestInfo::ForRequest(request);
308   if (!request_info) {
309     DLOG(FATAL) << "Started request without associated info: " <<
310         request->url();
311     return;
312   }
313
314   if (request_info->GetResourceType() == content::RESOURCE_TYPE_MAIN_FRAME) {
315     // Check for x-auto-login header.
316     auto_login_parser::HeaderData header_data;
317     if (auto_login_parser::ParserHeaderInResponse(
318             request, auto_login_parser::ALLOW_ANY_REALM, &header_data)) {
319       scoped_ptr<XWalkContentsIoThreadClient> io_client =
320           XWalkContentsIoThreadClient::FromID(request_info->GetChildID(),
321                                               request_info->GetRenderFrameID());
322       if (io_client) {
323         io_client->NewLoginRequest(
324             header_data.realm, header_data.account, header_data.args);
325       }
326     }
327   }
328 }
329
330 void RuntimeResourceDispatcherHostDelegateAndroid::
331 RemovePendingThrottleOnIoThread(
332     IoThreadClientThrottle* throttle) {
333   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
334   PendingThrottleMap::iterator it = pending_throttles_.find(
335       FrameRouteIDPair(throttle->render_process_id(),
336                        throttle->render_frame_id()));
337   if (it != pending_throttles_.end()) {
338     pending_throttles_.erase(it);
339   }
340 }
341
342 // static
343 void RuntimeResourceDispatcherHostDelegateAndroid::OnIoThreadClientReady(
344     int new_render_process_id,
345     int new_render_frame_id) {
346   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
347       base::Bind(
348           &RuntimeResourceDispatcherHostDelegateAndroid::
349           OnIoThreadClientReadyInternal,
350           base::Unretained(
351               static_cast<RuntimeResourceDispatcherHostDelegateAndroid*>(
352                   XWalkContentBrowserClient::Get()->
353                       resource_dispatcher_host_delegate())),
354           new_render_process_id, new_render_frame_id));
355 }
356
357 // static
358 void RuntimeResourceDispatcherHostDelegateAndroid::AddPendingThrottle(
359     int render_process_id,
360     int render_frame_id,
361     IoThreadClientThrottle* pending_throttle) {
362   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
363       base::Bind(
364           &RuntimeResourceDispatcherHostDelegateAndroid::
365               AddPendingThrottleOnIoThread,
366           base::Unretained(
367               static_cast<RuntimeResourceDispatcherHostDelegateAndroid*>(
368                   XWalkContentBrowserClient::Get()->
369                       resource_dispatcher_host_delegate())),
370           render_process_id, render_frame_id, pending_throttle));
371 }
372
373 void RuntimeResourceDispatcherHostDelegateAndroid::
374     AddPendingThrottleOnIoThread(
375         int render_process_id,
376         int render_frame_id,
377         IoThreadClientThrottle* pending_throttle) {
378   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
379   pending_throttles_.insert(
380       std::pair<FrameRouteIDPair, IoThreadClientThrottle*>(
381           FrameRouteIDPair(render_process_id, render_frame_id),
382           pending_throttle));
383 }
384
385 void RuntimeResourceDispatcherHostDelegateAndroid::
386 OnIoThreadClientReadyInternal(
387     int new_render_process_id,
388     int new_render_frame_id) {
389   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
390   PendingThrottleMap::iterator it = pending_throttles_.find(
391       FrameRouteIDPair(new_render_process_id, new_render_frame_id));
392
393   if (it != pending_throttles_.end()) {
394     IoThreadClientThrottle* throttle = it->second;
395     throttle->OnIoThreadClientReady(new_render_process_id,
396                                     new_render_frame_id);
397     pending_throttles_.erase(it);
398   }
399 }
400
401 }  // namespace xwalk