Index: content/browser/service_worker/service_worker_client_utils.cc |
diff --git a/content/browser/service_worker/service_worker_client_navigation_utils.cc b/content/browser/service_worker/service_worker_client_utils.cc |
similarity index 55% |
rename from content/browser/service_worker/service_worker_client_navigation_utils.cc |
rename to content/browser/service_worker/service_worker_client_utils.cc |
index 5147bd12dcabdcce324dc21dabe31aeac8d04a17..26ef4d35f181bd9a43c4bb5922c5698da78e6aa3 100644 |
--- a/content/browser/service_worker/service_worker_client_navigation_utils.cc |
+++ b/content/browser/service_worker/service_worker_client_utils.cc |
@@ -2,15 +2,19 @@ |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
-#include "content/browser/service_worker/service_worker_client_navigation_utils.h" |
+#include "content/browser/service_worker/service_worker_client_utils.h" |
+ |
+#include <algorithm> |
#include "base/macros.h" |
#include "content/browser/frame_host/frame_tree_node.h" |
#include "content/browser/frame_host/render_frame_host_impl.h" |
#include "content/browser/service_worker/service_worker_context_core.h" |
#include "content/browser/service_worker/service_worker_context_wrapper.h" |
+#include "content/browser/service_worker/service_worker_version.h" |
#include "content/browser/storage_partition_impl.h" |
#include "content/common/service_worker/service_worker_client_info.h" |
+#include "content/common/service_worker/service_worker_types.h" |
#include "content/public/browser/browser_thread.h" |
#include "content/public/browser/content_browser_client.h" |
#include "content/public/browser/page_navigator.h" |
@@ -20,11 +24,13 @@ |
#include "url/gurl.h" |
namespace content { |
-namespace service_worker_client_navigation_utils { |
+namespace service_worker_client_utils { |
namespace { |
using OpenURLCallback = base::Callback<void(int, int)>; |
+using GetWindowClientsCallback = |
+ base::Callback<void(scoped_ptr<ServiceWorkerClients>)>; |
// The OpenURLObserver class is a WebContentsObserver that will wait for a |
// WebContents to be initialized, run the |callback| passed to its constructor |
@@ -200,6 +206,141 @@ void DidNavigate(const base::WeakPtr<ServiceWorkerContextCore>& context, |
callback.Run(SERVICE_WORKER_OK, std::string(), ServiceWorkerClientInfo()); |
} |
+void AddWindowClient( |
+ ServiceWorkerProviderHost* host, |
+ std::vector<base::Tuple<int, int, std::string>>* client_info) { |
+ if (host->client_type() != blink::WebServiceWorkerClientTypeWindow) |
+ return; |
+ client_info->push_back(base::MakeTuple(host->process_id(), host->frame_id(), |
+ host->client_uuid())); |
+} |
+ |
+void AddNonWindowClient(ServiceWorkerProviderHost* host, |
+ const ServiceWorkerClientQueryOptions& options, |
+ ServiceWorkerClients* clients) { |
+ blink::WebServiceWorkerClientType host_client_type = host->client_type(); |
+ if (host_client_type == blink::WebServiceWorkerClientTypeWindow) |
+ return; |
+ if (options.client_type != blink::WebServiceWorkerClientTypeAll && |
+ options.client_type != host_client_type) |
+ return; |
+ |
+ ServiceWorkerClientInfo client_info(blink::WebPageVisibilityStateHidden, |
+ false, // is_focused |
+ host->document_url(), |
+ REQUEST_CONTEXT_FRAME_TYPE_NONE, |
+ base::TimeTicks(), host_client_type); |
+ client_info.client_uuid = host->client_uuid(); |
+ clients->push_back(client_info); |
+} |
+ |
+void OnGetWindowClientsOnUI( |
+ // The tuple contains process_id, frame_id, client_uuid. |
+ const std::vector<base::Tuple<int, int, std::string>>& clients_info, |
+ const GURL& script_url, |
+ const GetWindowClientsCallback& callback) { |
+ scoped_ptr<ServiceWorkerClients> clients(new ServiceWorkerClients); |
+ |
+ for (const auto& it : clients_info) { |
+ ServiceWorkerClientInfo info = |
+ ServiceWorkerProviderHost::GetWindowClientInfoOnUI(base::get<0>(it), |
+ base::get<1>(it)); |
+ |
+ // If the request to the provider_host returned an empty |
+ // ServiceWorkerClientInfo, that means that it wasn't possible to associate |
+ // it with a valid RenderFrameHost. It might be because the frame was killed |
+ // or navigated in between. |
+ if (info.IsEmpty()) |
+ continue; |
+ |
+ // We can get info for a frame that was navigating end ended up with a |
+ // different URL than expected. In such case, we should make sure to not |
+ // expose cross-origin WindowClient. |
+ if (info.url.GetOrigin() != script_url.GetOrigin()) |
+ continue; |
+ |
+ info.client_uuid = base::get<2>(it); |
+ clients->push_back(info); |
+ } |
+ |
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
+ base::Bind(callback, base::Passed(&clients))); |
+} |
+ |
+struct ServiceWorkerClientInfoSortMRU { |
+ bool operator()(const ServiceWorkerClientInfo& a, |
+ const ServiceWorkerClientInfo& b) const { |
+ return a.last_focus_time > b.last_focus_time; |
+ } |
+}; |
+ |
+void DidGetClients(const ClientsCallback& callback, |
+ ServiceWorkerClients* clients) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::IO); |
+ |
+ // Sort clients so that the most recently active tab is in the front. |
+ std::sort(clients->begin(), clients->end(), ServiceWorkerClientInfoSortMRU()); |
+ |
+ callback.Run(clients); |
+} |
+ |
+void GetNonWindowClients(const base::WeakPtr<ServiceWorkerVersion>& controller, |
+ const ServiceWorkerClientQueryOptions& options, |
+ ServiceWorkerClients* clients) { |
+ if (!options.include_uncontrolled) { |
+ for (auto& controllee : controller->controllee_map()) |
+ AddNonWindowClient(controllee.second, options, clients); |
+ } else if (controller->context()) { |
+ GURL origin = controller->script_url().GetOrigin(); |
+ for (auto it = controller->context()->GetClientProviderHostIterator(origin); |
+ !it->IsAtEnd(); it->Advance()) { |
+ AddNonWindowClient(it->GetProviderHost(), options, clients); |
+ } |
+ } |
+} |
+ |
+void DidGetWindowClients(const base::WeakPtr<ServiceWorkerVersion>& controller, |
+ const ServiceWorkerClientQueryOptions& options, |
+ const ClientsCallback& callback, |
+ scoped_ptr<ServiceWorkerClients> clients) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::IO); |
+ if (options.client_type == blink::WebServiceWorkerClientTypeAll) |
+ GetNonWindowClients(controller, options, clients.get()); |
+ DidGetClients(callback, clients.get()); |
+} |
+ |
+void GetWindowClients(const base::WeakPtr<ServiceWorkerVersion>& controller, |
+ const ServiceWorkerClientQueryOptions& options, |
+ const ClientsCallback& callback) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::IO); |
+ DCHECK(options.client_type == blink::WebServiceWorkerClientTypeWindow || |
+ options.client_type == blink::WebServiceWorkerClientTypeAll); |
+ |
+ std::vector<base::Tuple<int, int, std::string>> clients_info; |
+ if (!options.include_uncontrolled) { |
+ for (auto& controllee : controller->controllee_map()) |
+ AddWindowClient(controllee.second, &clients_info); |
+ } else if (controller->context()) { |
+ GURL origin = controller->script_url().GetOrigin(); |
+ for (auto it = controller->context()->GetClientProviderHostIterator(origin); |
+ !it->IsAtEnd(); it->Advance()) { |
+ AddWindowClient(it->GetProviderHost(), &clients_info); |
+ } |
+ } |
+ |
+ if (clients_info.empty()) { |
+ DidGetWindowClients(controller, options, callback, |
+ make_scoped_ptr(new ServiceWorkerClients)); |
+ return; |
+ } |
+ |
+ BrowserThread::PostTask( |
+ BrowserThread::UI, FROM_HERE, |
+ base::Bind( |
+ &OnGetWindowClientsOnUI, clients_info, controller->script_url(), |
+ base::Bind(&DidGetWindowClients, controller, options, callback))); |
+} |
+ |
} // namespace |
void OpenWindow(const GURL& url, |
@@ -230,5 +371,27 @@ void NavigateClient(const GURL& url, |
base::Bind(&DidNavigate, context, script_url.GetOrigin(), callback))); |
} |
-} // namespace service_worker_client_navigation_utils |
+void GetClients(const base::WeakPtr<ServiceWorkerVersion>& controller, |
+ const ServiceWorkerClientQueryOptions& options, |
+ const ClientsCallback& callback) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::IO); |
+ |
+ ServiceWorkerClients clients; |
+ if (!controller->HasControllee() && !options.include_uncontrolled) { |
+ DidGetClients(callback, &clients); |
+ return; |
+ } |
+ |
+ // For Window clients we want to query the info on the UI thread first. |
+ if (options.client_type == blink::WebServiceWorkerClientTypeWindow || |
+ options.client_type == blink::WebServiceWorkerClientTypeAll) { |
+ GetWindowClients(controller, options, callback); |
+ return; |
+ } |
+ |
+ GetNonWindowClients(controller, options, &clients); |
+ DidGetClients(callback, &clients); |
+} |
+ |
+} // namespace service_worker_client_utils |
} // namespace content |