Chromium Code Reviews| 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 530c7ab85e63f05cf305849cdb9945c5b22fc698..5e62c7f57b8ab88e27ab32d4f891bb7211b2f100 100644 |
| --- a/content/browser/service_worker/service_worker_version.cc |
| +++ b/content/browser/service_worker/service_worker_version.cc |
| @@ -13,11 +13,22 @@ |
| #include "content/browser/service_worker/embedded_worker_instance.h" |
| #include "content/browser/service_worker/embedded_worker_registry.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_registration.h" |
| #include "content/browser/service_worker/service_worker_utils.h" |
| +#include "content/browser/storage_partition_impl.h" |
| #include "content/common/service_worker/service_worker_messages.h" |
| #include "content/public/browser/browser_thread.h" |
| +#include "content/public/browser/content_browser_client.h" |
| +#include "content/public/browser/page_navigator.h" |
| +#include "content/public/browser/render_frame_host.h" |
| +#include "content/public/browser/render_process_host.h" |
| +#include "content/public/browser/web_contents.h" |
| +#include "content/public/browser/web_contents_observer.h" |
| +#include "content/public/common/child_process_host.h" |
| +#include "content/public/common/content_client.h" |
| #include "content/public/common/content_switches.h" |
| +#include "content/public/common/result_codes.h" |
| namespace content { |
| @@ -143,6 +154,93 @@ void RunErrorCrossOriginConnectCallback( |
| callback.Run(status, false); |
| } |
| +using WindowOpenedCallback = 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 callback will receive the process and frame ids. If something went wrong |
| +// those will be (kInvalidUniqueID,MSG_ROUTING_NONE). |
| +class WindowOpenedObserver : public WebContentsObserver { |
| + public: |
| + WindowOpenedObserver(WebContents* web_contents, |
| + const WindowOpenedCallback& callback) |
| + : WebContentsObserver(web_contents) |
| + , callback_(callback) |
| + {} |
| + |
| + void DocumentAvailableInMainFrame() override { |
|
jochen (gone - plz use gerrit)
2015/01/26 15:43:53
any reason you're waiting until the document is pa
mlamouri (slow - plz ping)
2015/01/26 16:01:41
The document needs to be controlled which will hap
|
| + DCHECK(web_contents()); |
| + |
| + RenderFrameHost* render_frame_host = web_contents()->GetMainFrame(); |
| + DCHECK(render_frame_host); |
| + |
| + RunCallback(render_frame_host->GetProcess()->GetID(), |
| + render_frame_host->GetRoutingID()); |
| + } |
| + |
| + void RenderProcessGone(base::TerminationStatus status) override { |
| + RunCallback(ChildProcessHost::kInvalidUniqueID, MSG_ROUTING_NONE); |
| + } |
| + |
| + void WebContentsDestroyed() override { |
| + RunCallback(ChildProcessHost::kInvalidUniqueID, MSG_ROUTING_NONE); |
| + } |
| + |
| + private: |
| + void RunCallback(int render_process_id, int render_frame_id) { |
| + // After running the callback, |this| will stop observing, thus |
| + // web_contents() should return nullptr and |RunCallback| should no longer |
| + // be called. Then, |this| will self destroy. |
| + DCHECK(web_contents()); |
| + |
| + BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
| + base::Bind(callback_, |
| + render_process_id, |
| + render_frame_id)); |
| + Observe(nullptr); |
| + base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); |
| + } |
| + |
| + const WindowOpenedCallback callback_; |
| +}; |
|
jochen (gone - plz use gerrit)
2015/01/26 15:43:53
disallow copy/assign
jochen (gone - plz use gerrit)
2015/01/26 15:43:53
disallow copy/assign
mlamouri (slow - plz ping)
2015/01/26 16:01:41
Done.
|
| + |
| +void OpenWindowOnUI( |
| + const GURL& url, |
| + const GURL& script_url, |
| + const scoped_refptr<ServiceWorkerContextWrapper>& context_wrapper, |
| + const WindowOpenedCallback& callback) { |
| + DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| + |
| + BrowserContext* browser_context = context_wrapper->storage_partition() |
| + ? context_wrapper->storage_partition()->browser_context() |
| + : nullptr; |
|
jochen (gone - plz use gerrit)
2015/01/26 15:43:53
can you also bail out if the process is an isolate
mlamouri (slow - plz ping)
2015/01/26 16:01:41
Done. Though, the issue isn't really storage parti
|
| + // We are shutting down. |
| + if (!browser_context) |
| + return; |
| + |
| + OpenURLParams params(url, |
| + Referrer(script_url, blink::WebReferrerPolicyDefault), |
| + NEW_FOREGROUND_TAB, |
| + ui::PAGE_TRANSITION_AUTO_TOPLEVEL, |
| + false); |
| + |
| + WebContents* web_contents = |
| + GetContentClient()->browser()->OpenURL(browser_context, params); |
| + DCHECK(web_contents); |
| + |
| + new WindowOpenedObserver(web_contents, callback); |
| +} |
| + |
| +void KillEmbeddedWorkerProcess(int process_id, ResultCode code) { |
| + DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| + |
| + RenderProcessHost* render_process_host = |
| + RenderProcessHost::FromID(process_id); |
| + if (render_process_host->GetHandle() != base::kNullProcessHandle) |
|
jochen (gone - plz use gerrit)
2015/01/26 15:43:53
should be render_process_host->ReceivedBadMessage(
mlamouri (slow - plz ping)
2015/01/26 16:01:41
Done.
|
| + render_process_host->Shutdown(code, false); |
| +} |
| + |
| } // namespace |
| ServiceWorkerVersion::ServiceWorkerVersion( |
| @@ -787,6 +885,8 @@ bool ServiceWorkerVersion::OnMessageReceived(const IPC::Message& message) { |
| OnGeofencingEventFinished) |
| IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_CrossOriginConnectEventFinished, |
| OnCrossOriginConnectEventFinished) |
| + IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_OpenWindow, |
| + OnOpenWindow) |
| IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PostMessageToDocument, |
| OnPostMessageToDocument) |
| IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_FocusClient, |
| @@ -1006,6 +1106,88 @@ void ServiceWorkerVersion::OnCrossOriginConnectEventFinished( |
| RemoveCallbackAndStopIfDoomed(&cross_origin_connect_callbacks_, request_id); |
| } |
| +void ServiceWorkerVersion::OnOpenWindow(int request_id, const GURL& url) { |
| + // Just abort if we are shutting down. |
| + if (!context_) |
| + return; |
| + |
| + if (url.GetOrigin() != script_url_.GetOrigin()) { |
| + // There should be a same origin check by Blink, if the request is still not |
| + // same origin, the process might be compromised and should be eliminated. |
| + DVLOG(1) << "Received a cross origin openWindow() request from a service " |
| + "worker. Killing associated process."; |
| + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| + base::Bind(&KillEmbeddedWorkerProcess, |
| + embedded_worker_->process_id(), |
| + RESULT_CODE_KILLED_BAD_MESSAGE)); |
| + return; |
| + } |
| + |
| + BrowserThread::PostTask( |
| + BrowserThread::UI, FROM_HERE, |
| + base::Bind(&OpenWindowOnUI, |
| + url, |
| + script_url_, |
| + make_scoped_refptr(context_->wrapper()), |
| + base::Bind(&ServiceWorkerVersion::DidOpenWindow, |
| + weak_factory_.GetWeakPtr(), |
| + request_id))); |
| +} |
| + |
| +void ServiceWorkerVersion::DidOpenWindow(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_OpenWindowError(request_id)); |
| + return; |
| + } |
| + |
| + for (const auto& it : controllee_map_) { |
| + const ServiceWorkerProviderHost* provider_host = it.first; |
| + if (provider_host->process_id() != render_process_id || |
| + provider_host->frame_id() != render_frame_id) { |
| + continue; |
| + } |
| + |
| + // it.second is the client_id associated with the provider_host. |
| + provider_host->GetClientInfo( |
| + base::Bind(&ServiceWorkerVersion::OnOpenWindowFinished, |
| + weak_factory_.GetWeakPtr(), request_id, it.second)); |
| + return; |
| + } |
| + |
| + // If here, it means that no provider_host was found, in which case, the |
| + // renderer should still be informed that the window was opened. |
| + OnOpenWindowFinished(request_id, 0, ServiceWorkerClientInfo()); |
| +} |
| + |
| +void ServiceWorkerVersion::OnOpenWindowFinished( |
| + int request_id, |
| + int client_id, |
| + 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 opened window wasn't |
| + // controlled but the action still succeeded. The renderer process is |
| + // expecting an empty client in such case. |
| + if (!client.IsEmpty()) |
| + client.SetClientID(client_id); |
| + |
| + embedded_worker_->SendMessage(ServiceWorkerMsg_OpenWindowResponse( |
| + request_id, client)); |
| +} |
| + |
| void ServiceWorkerVersion::OnPostMessageToDocument( |
| int client_id, |
| const base::string16& message, |