OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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 "content/browser/service_worker/service_worker_client_navigation_utils.
h" | 5 #include "content/browser/service_worker/service_worker_client_utils.h" |
| 6 |
| 7 #include <algorithm> |
6 | 8 |
7 #include "base/macros.h" | 9 #include "base/macros.h" |
8 #include "content/browser/frame_host/frame_tree_node.h" | 10 #include "content/browser/frame_host/frame_tree_node.h" |
9 #include "content/browser/frame_host/render_frame_host_impl.h" | 11 #include "content/browser/frame_host/render_frame_host_impl.h" |
10 #include "content/browser/service_worker/service_worker_context_core.h" | 12 #include "content/browser/service_worker/service_worker_context_core.h" |
11 #include "content/browser/service_worker/service_worker_context_wrapper.h" | 13 #include "content/browser/service_worker/service_worker_context_wrapper.h" |
| 14 #include "content/browser/service_worker/service_worker_version.h" |
12 #include "content/browser/storage_partition_impl.h" | 15 #include "content/browser/storage_partition_impl.h" |
13 #include "content/common/service_worker/service_worker_client_info.h" | 16 #include "content/common/service_worker/service_worker_client_info.h" |
| 17 #include "content/common/service_worker/service_worker_types.h" |
14 #include "content/public/browser/browser_thread.h" | 18 #include "content/public/browser/browser_thread.h" |
15 #include "content/public/browser/content_browser_client.h" | 19 #include "content/public/browser/content_browser_client.h" |
16 #include "content/public/browser/page_navigator.h" | 20 #include "content/public/browser/page_navigator.h" |
17 #include "content/public/browser/web_contents.h" | 21 #include "content/public/browser/web_contents.h" |
18 #include "content/public/browser/web_contents_observer.h" | 22 #include "content/public/browser/web_contents_observer.h" |
19 #include "content/public/common/child_process_host.h" | 23 #include "content/public/common/child_process_host.h" |
20 #include "url/gurl.h" | 24 #include "url/gurl.h" |
21 | 25 |
22 namespace content { | 26 namespace content { |
23 namespace service_worker_client_navigation_utils { | 27 namespace service_worker_client_utils { |
24 | 28 |
25 namespace { | 29 namespace { |
26 | 30 |
27 using OpenURLCallback = base::Callback<void(int, int)>; | 31 using OpenURLCallback = base::Callback<void(int, int)>; |
| 32 using GetWindowClientsCallback = |
| 33 base::Callback<void(scoped_ptr<ServiceWorkerClients>)>; |
28 | 34 |
29 // The OpenURLObserver class is a WebContentsObserver that will wait for a | 35 // The OpenURLObserver class is a WebContentsObserver that will wait for a |
30 // WebContents to be initialized, run the |callback| passed to its constructor | 36 // WebContents to be initialized, run the |callback| passed to its constructor |
31 // then self destroy. | 37 // then self destroy. |
32 // The callback will receive the process and frame ids. If something went wrong | 38 // The callback will receive the process and frame ids. If something went wrong |
33 // those will be (kInvalidUniqueID, MSG_ROUTING_NONE). | 39 // those will be (kInvalidUniqueID, MSG_ROUTING_NONE). |
34 // The callback will be called in the IO thread. | 40 // The callback will be called in the IO thread. |
35 class OpenURLObserver : public WebContentsObserver { | 41 class OpenURLObserver : public WebContentsObserver { |
36 public: | 42 public: |
37 OpenURLObserver(WebContents* web_contents, | 43 OpenURLObserver(WebContents* web_contents, |
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
193 provider_host->GetWindowClientInfo( | 199 provider_host->GetWindowClientInfo( |
194 base::Bind(callback, SERVICE_WORKER_OK, provider_host->client_uuid())); | 200 base::Bind(callback, SERVICE_WORKER_OK, provider_host->client_uuid())); |
195 return; | 201 return; |
196 } | 202 } |
197 | 203 |
198 // If here, it means that no provider_host was found, in which case, the | 204 // If here, it means that no provider_host was found, in which case, the |
199 // renderer should still be informed that the window was opened. | 205 // renderer should still be informed that the window was opened. |
200 callback.Run(SERVICE_WORKER_OK, std::string(), ServiceWorkerClientInfo()); | 206 callback.Run(SERVICE_WORKER_OK, std::string(), ServiceWorkerClientInfo()); |
201 } | 207 } |
202 | 208 |
| 209 void AddWindowClient( |
| 210 ServiceWorkerProviderHost* host, |
| 211 std::vector<base::Tuple<int, int, std::string>>* client_info) { |
| 212 if (host->client_type() != blink::WebServiceWorkerClientTypeWindow) |
| 213 return; |
| 214 client_info->push_back(base::MakeTuple(host->process_id(), host->frame_id(), |
| 215 host->client_uuid())); |
| 216 } |
| 217 |
| 218 void AddNonWindowClient(ServiceWorkerProviderHost* host, |
| 219 const ServiceWorkerClientQueryOptions& options, |
| 220 ServiceWorkerClients* clients) { |
| 221 blink::WebServiceWorkerClientType host_client_type = host->client_type(); |
| 222 if (host_client_type == blink::WebServiceWorkerClientTypeWindow) |
| 223 return; |
| 224 if (options.client_type != blink::WebServiceWorkerClientTypeAll && |
| 225 options.client_type != host_client_type) |
| 226 return; |
| 227 |
| 228 ServiceWorkerClientInfo client_info(blink::WebPageVisibilityStateHidden, |
| 229 false, // is_focused |
| 230 host->document_url(), |
| 231 REQUEST_CONTEXT_FRAME_TYPE_NONE, |
| 232 base::TimeTicks(), host_client_type); |
| 233 client_info.client_uuid = host->client_uuid(); |
| 234 clients->push_back(client_info); |
| 235 } |
| 236 |
| 237 void OnGetWindowClientsOnUI( |
| 238 // The tuple contains process_id, frame_id, client_uuid. |
| 239 const std::vector<base::Tuple<int, int, std::string>>& clients_info, |
| 240 const GURL& script_url, |
| 241 const GetWindowClientsCallback& callback) { |
| 242 scoped_ptr<ServiceWorkerClients> clients(new ServiceWorkerClients); |
| 243 |
| 244 for (const auto& it : clients_info) { |
| 245 ServiceWorkerClientInfo info = |
| 246 ServiceWorkerProviderHost::GetWindowClientInfoOnUI(base::get<0>(it), |
| 247 base::get<1>(it)); |
| 248 |
| 249 // If the request to the provider_host returned an empty |
| 250 // ServiceWorkerClientInfo, that means that it wasn't possible to associate |
| 251 // it with a valid RenderFrameHost. It might be because the frame was killed |
| 252 // or navigated in between. |
| 253 if (info.IsEmpty()) |
| 254 continue; |
| 255 |
| 256 // We can get info for a frame that was navigating end ended up with a |
| 257 // different URL than expected. In such case, we should make sure to not |
| 258 // expose cross-origin WindowClient. |
| 259 if (info.url.GetOrigin() != script_url.GetOrigin()) |
| 260 continue; |
| 261 |
| 262 info.client_uuid = base::get<2>(it); |
| 263 clients->push_back(info); |
| 264 } |
| 265 |
| 266 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
| 267 base::Bind(callback, base::Passed(&clients))); |
| 268 } |
| 269 |
| 270 struct ServiceWorkerClientInfoSortMRU { |
| 271 bool operator()(const ServiceWorkerClientInfo& a, |
| 272 const ServiceWorkerClientInfo& b) const { |
| 273 return a.last_focus_time > b.last_focus_time; |
| 274 } |
| 275 }; |
| 276 |
| 277 void DidGetClients(const ClientsCallback& callback, |
| 278 ServiceWorkerClients* clients) { |
| 279 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 280 |
| 281 // Sort clients so that the most recently active tab is in the front. |
| 282 std::sort(clients->begin(), clients->end(), ServiceWorkerClientInfoSortMRU()); |
| 283 |
| 284 callback.Run(clients); |
| 285 } |
| 286 |
| 287 void GetNonWindowClients(const base::WeakPtr<ServiceWorkerVersion>& controller, |
| 288 const ServiceWorkerClientQueryOptions& options, |
| 289 ServiceWorkerClients* clients) { |
| 290 if (!options.include_uncontrolled) { |
| 291 for (auto& controllee : controller->controllee_map()) |
| 292 AddNonWindowClient(controllee.second, options, clients); |
| 293 } else if (controller->context()) { |
| 294 GURL origin = controller->script_url().GetOrigin(); |
| 295 for (auto it = controller->context()->GetClientProviderHostIterator(origin); |
| 296 !it->IsAtEnd(); it->Advance()) { |
| 297 AddNonWindowClient(it->GetProviderHost(), options, clients); |
| 298 } |
| 299 } |
| 300 } |
| 301 |
| 302 void DidGetWindowClients(const base::WeakPtr<ServiceWorkerVersion>& controller, |
| 303 const ServiceWorkerClientQueryOptions& options, |
| 304 const ClientsCallback& callback, |
| 305 scoped_ptr<ServiceWorkerClients> clients) { |
| 306 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 307 if (options.client_type == blink::WebServiceWorkerClientTypeAll) |
| 308 GetNonWindowClients(controller, options, clients.get()); |
| 309 DidGetClients(callback, clients.get()); |
| 310 } |
| 311 |
| 312 void GetWindowClients(const base::WeakPtr<ServiceWorkerVersion>& controller, |
| 313 const ServiceWorkerClientQueryOptions& options, |
| 314 const ClientsCallback& callback) { |
| 315 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 316 DCHECK(options.client_type == blink::WebServiceWorkerClientTypeWindow || |
| 317 options.client_type == blink::WebServiceWorkerClientTypeAll); |
| 318 |
| 319 std::vector<base::Tuple<int, int, std::string>> clients_info; |
| 320 if (!options.include_uncontrolled) { |
| 321 for (auto& controllee : controller->controllee_map()) |
| 322 AddWindowClient(controllee.second, &clients_info); |
| 323 } else if (controller->context()) { |
| 324 GURL origin = controller->script_url().GetOrigin(); |
| 325 for (auto it = controller->context()->GetClientProviderHostIterator(origin); |
| 326 !it->IsAtEnd(); it->Advance()) { |
| 327 AddWindowClient(it->GetProviderHost(), &clients_info); |
| 328 } |
| 329 } |
| 330 |
| 331 if (clients_info.empty()) { |
| 332 DidGetWindowClients(controller, options, callback, |
| 333 make_scoped_ptr(new ServiceWorkerClients)); |
| 334 return; |
| 335 } |
| 336 |
| 337 BrowserThread::PostTask( |
| 338 BrowserThread::UI, FROM_HERE, |
| 339 base::Bind( |
| 340 &OnGetWindowClientsOnUI, clients_info, controller->script_url(), |
| 341 base::Bind(&DidGetWindowClients, controller, options, callback))); |
| 342 } |
| 343 |
203 } // namespace | 344 } // namespace |
204 | 345 |
205 void OpenWindow(const GURL& url, | 346 void OpenWindow(const GURL& url, |
206 const GURL& script_url, | 347 const GURL& script_url, |
207 int worker_process_id, | 348 int worker_process_id, |
208 const base::WeakPtr<ServiceWorkerContextCore>& context, | 349 const base::WeakPtr<ServiceWorkerContextCore>& context, |
209 const NavigationCallback& callback) { | 350 const NavigationCallback& callback) { |
210 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 351 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
211 BrowserThread::PostTask( | 352 BrowserThread::PostTask( |
212 BrowserThread::UI, FROM_HERE, | 353 BrowserThread::UI, FROM_HERE, |
(...skipping 10 matching lines...) Expand all Loading... |
223 const base::WeakPtr<ServiceWorkerContextCore>& context, | 364 const base::WeakPtr<ServiceWorkerContextCore>& context, |
224 const NavigationCallback& callback) { | 365 const NavigationCallback& callback) { |
225 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 366 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
226 BrowserThread::PostTask( | 367 BrowserThread::PostTask( |
227 BrowserThread::UI, FROM_HERE, | 368 BrowserThread::UI, FROM_HERE, |
228 base::Bind( | 369 base::Bind( |
229 &NavigateClientOnUI, url, script_url, process_id, frame_id, | 370 &NavigateClientOnUI, url, script_url, process_id, frame_id, |
230 base::Bind(&DidNavigate, context, script_url.GetOrigin(), callback))); | 371 base::Bind(&DidNavigate, context, script_url.GetOrigin(), callback))); |
231 } | 372 } |
232 | 373 |
233 } // namespace service_worker_client_navigation_utils | 374 void GetClients(const base::WeakPtr<ServiceWorkerVersion>& controller, |
| 375 const ServiceWorkerClientQueryOptions& options, |
| 376 const ClientsCallback& callback) { |
| 377 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 378 |
| 379 ServiceWorkerClients clients; |
| 380 if (!controller->HasControllee() && !options.include_uncontrolled) { |
| 381 DidGetClients(callback, &clients); |
| 382 return; |
| 383 } |
| 384 |
| 385 // For Window clients we want to query the info on the UI thread first. |
| 386 if (options.client_type == blink::WebServiceWorkerClientTypeWindow || |
| 387 options.client_type == blink::WebServiceWorkerClientTypeAll) { |
| 388 GetWindowClients(controller, options, callback); |
| 389 return; |
| 390 } |
| 391 |
| 392 GetNonWindowClients(controller, options, &clients); |
| 393 DidGetClients(callback, &clients); |
| 394 } |
| 395 |
| 396 } // namespace service_worker_client_utils |
234 } // namespace content | 397 } // namespace content |
OLD | NEW |