Index: content/browser/service_worker/service_worker_version.cc |
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc |
index 9d232d518e710ab0fc8674e80cd8f2ded4e8f0f6..4ff04c857432753bc401bbddd9d79c32c7117b1a 100644 |
--- a/content/browser/service_worker/service_worker_version.cc |
+++ b/content/browser/service_worker/service_worker_version.cc |
@@ -8,6 +8,7 @@ |
#include <string> |
#include "base/command_line.h" |
+#include "base/guid.h" |
#include "base/location.h" |
#include "base/memory/ref_counted.h" |
#include "base/metrics/histogram_macros.h" |
@@ -176,21 +177,18 @@ void RunErrorServicePortConnectCallback( |
base::string16()); |
} |
-using WindowOpenedCallback = base::Callback<void(int, int)>; |
+using OpenURLCallback = base::Callback<void(int, int)>; |
-// The WindowOpenedObserver class is a WebContentsObserver that will wait for a |
-// new Window's WebContents to be initialized, run the |callback| passed to its |
-// constructor then self destroy. |
+// The OpenURLObserver class is a WebContentsObserver that will wait for a |
+// WebContents to be initialized, run the |callback| passed to its constructor |
+// then self destroy. |
// The callback will receive the process and frame ids. If something went wrong |
// those will be (kInvalidUniqueID, MSG_ROUTING_NONE). |
// The callback will be called in the IO thread. |
-class WindowOpenedObserver : public WebContentsObserver { |
+class OpenURLObserver : public WebContentsObserver { |
public: |
- WindowOpenedObserver(WebContents* web_contents, |
- const WindowOpenedCallback& callback) |
- : WebContentsObserver(web_contents), |
- callback_(callback) |
- {} |
+ OpenURLObserver(WebContents* web_contents, const OpenURLCallback& callback) |
+ : WebContentsObserver(web_contents), callback_(callback) {} |
void DidCommitProvisionalLoadForFrame( |
RenderFrameHost* render_frame_host, |
@@ -228,16 +226,44 @@ class WindowOpenedObserver : public WebContentsObserver { |
base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); |
} |
- const WindowOpenedCallback callback_; |
+ const OpenURLCallback callback_; |
- DISALLOW_COPY_AND_ASSIGN(WindowOpenedObserver); |
+ DISALLOW_COPY_AND_ASSIGN(OpenURLObserver); |
}; |
-void DidOpenURL(const WindowOpenedCallback& callback, |
- WebContents* web_contents) { |
+void DidOpenURL(const OpenURLCallback& callback, WebContents* web_contents) { |
DCHECK(web_contents); |
- new WindowOpenedObserver(web_contents, callback); |
+ new OpenURLObserver(web_contents, callback); |
+} |
+ |
+void NavigateClientOnUI(const GURL& url, |
+ const GURL& script_url, |
+ int process_id, |
+ int frame_id, |
+ const OpenURLCallback& callback) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::UI); |
+ |
+ RenderFrameHost* render_frame_host = |
+ RenderFrameHost::FromID(process_id, frame_id); |
+ WebContents* web_contents = |
+ WebContents::FromRenderFrameHost(render_frame_host); |
+ |
+ if (!render_frame_host || !web_contents) { |
+ BrowserThread::PostTask( |
+ BrowserThread::IO, FROM_HERE, |
+ base::Bind(callback, ChildProcessHost::kInvalidUniqueID, |
+ MSG_ROUTING_NONE)); |
+ return; |
+ } |
+ |
+ OpenURLParams params( |
+ url, Referrer::SanitizeForRequest( |
+ url, Referrer(script_url, blink::WebReferrerPolicyDefault)), |
+ CURRENT_TAB, ui::PAGE_TRANSITION_AUTO_TOPLEVEL, |
+ true /* is_renderer_initiated */); |
+ web_contents->OpenURL(params); |
+ DidOpenURL(callback, web_contents); |
} |
void OpenWindowOnUI( |
@@ -245,7 +271,7 @@ void OpenWindowOnUI( |
const GURL& script_url, |
int process_id, |
const scoped_refptr<ServiceWorkerContextWrapper>& context_wrapper, |
- const WindowOpenedCallback& callback) { |
+ const OpenURLCallback& callback) { |
DCHECK_CURRENTLY_ON(BrowserThread::UI); |
BrowserContext* browser_context = context_wrapper->storage_partition() |
@@ -1187,6 +1213,7 @@ bool ServiceWorkerVersion::OnMessageReceived(const IPC::Message& message) { |
OnPostMessageToClient) |
IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_FocusClient, |
OnFocusClient) |
+ IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_NavigateClient, OnNavigateClient) |
IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SkipWaiting, |
OnSkipWaiting) |
IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ClaimClients, |
@@ -1646,6 +1673,105 @@ void ServiceWorkerVersion::OnFocusClientFinished( |
request_id, client_info)); |
} |
+void ServiceWorkerVersion::OnNavigateClient(int request_id, |
+ const std::string& client_uuid, |
+ const GURL& url) { |
+ if (!context_) |
+ return; |
+ |
+ TRACE_EVENT2("ServiceWorker", "ServiceWorkerVersion::OnNavigateClient", |
+ "Request id", request_id, "Client id", client_uuid); |
+ |
+ if (!url.is_valid() || !base::IsValidGUID(client_uuid)) { |
+ DVLOG(1) << "Received unexpected invalid URL/UUID from renderer process."; |
+ BrowserThread::PostTask( |
+ BrowserThread::UI, FROM_HERE, |
+ base::Bind(&KillEmbeddedWorkerProcess, embedded_worker_->process_id(), |
+ RESULT_CODE_KILLED_BAD_MESSAGE)); |
+ return; |
+ } |
+ |
+ // Reject requests for URLs that the process is not allowed to access. It's |
+ // possible to receive such requests since the renderer-side checks are |
+ // slightly different. For example, the view-source scheme will not be |
+ // filtered out by Blink. |
+ if (!ChildProcessSecurityPolicyImpl::GetInstance()->CanRequestURL( |
+ embedded_worker_->process_id(), url)) { |
+ embedded_worker_->SendMessage( |
+ ServiceWorkerMsg_NavigateClientError(request_id, url)); |
+ return; |
+ } |
+ |
+ ServiceWorkerProviderHost* provider_host = |
+ context_->GetProviderHostByClientID(client_uuid); |
+ if (!provider_host || provider_host->active_version() != this) { |
+ embedded_worker_->SendMessage( |
+ ServiceWorkerMsg_NavigateClientError(request_id, url)); |
+ return; |
+ } |
+ |
+ BrowserThread::PostTask( |
+ BrowserThread::UI, FROM_HERE, |
+ base::Bind(&NavigateClientOnUI, url, script_url_, |
+ provider_host->process_id(), provider_host->frame_id(), |
+ base::Bind(&ServiceWorkerVersion::DidNavigateClient, |
+ weak_factory_.GetWeakPtr(), request_id))); |
+} |
+ |
+void ServiceWorkerVersion::DidNavigateClient(int request_id, |
+ int render_process_id, |
+ int render_frame_id) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::IO); |
+ |
+ if (running_status() != RUNNING) |
+ return; |
+ |
+ if (render_process_id == ChildProcessHost::kInvalidUniqueID && |
+ render_frame_id == MSG_ROUTING_NONE) { |
+ embedded_worker_->SendMessage( |
+ ServiceWorkerMsg_NavigateClientError(request_id, GURL())); |
+ return; |
+ } |
+ |
+ for (auto it = |
+ context_->GetClientProviderHostIterator(script_url_.GetOrigin()); |
+ !it->IsAtEnd(); it->Advance()) { |
+ ServiceWorkerProviderHost* provider_host = it->GetProviderHost(); |
+ if (provider_host->process_id() != render_process_id || |
+ provider_host->frame_id() != render_frame_id) { |
+ continue; |
+ } |
+ provider_host->GetWindowClientInfo(base::Bind( |
+ &ServiceWorkerVersion::OnNavigateClientFinished, |
+ weak_factory_.GetWeakPtr(), request_id, provider_host->client_uuid())); |
+ return; |
+ } |
+ |
+ OnNavigateClientFinished(request_id, std::string(), |
+ ServiceWorkerClientInfo()); |
+} |
+ |
+void ServiceWorkerVersion::OnNavigateClientFinished( |
+ int request_id, |
+ const std::string& client_uuid, |
+ const ServiceWorkerClientInfo& client_info) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::IO); |
+ |
+ if (running_status() != RUNNING) |
+ return; |
+ |
+ ServiceWorkerClientInfo client(client_info); |
+ |
+ // If the |client_info| is empty, it means that the navigated client wasn't |
+ // controlled but the action still succeeded. The renderer process is |
+ // expecting an empty client in such case. |
+ if (!client.IsEmpty()) |
+ client.client_uuid = client_uuid; |
+ |
+ embedded_worker_->SendMessage( |
+ ServiceWorkerMsg_NavigateClientResponse(request_id, client)); |
+} |
+ |
void ServiceWorkerVersion::OnSkipWaiting(int request_id) { |
skip_waiting_ = true; |
if (status_ != INSTALLED) |