| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "content/browser/service_worker/service_worker_client_navigation_utils.
h" | |
| 6 | |
| 7 #include "base/macros.h" | |
| 8 #include "content/browser/frame_host/frame_tree_node.h" | |
| 9 #include "content/browser/frame_host/render_frame_host_impl.h" | |
| 10 #include "content/browser/service_worker/service_worker_context_core.h" | |
| 11 #include "content/browser/service_worker/service_worker_context_wrapper.h" | |
| 12 #include "content/browser/storage_partition_impl.h" | |
| 13 #include "content/common/service_worker/service_worker_client_info.h" | |
| 14 #include "content/public/browser/browser_thread.h" | |
| 15 #include "content/public/browser/content_browser_client.h" | |
| 16 #include "content/public/browser/page_navigator.h" | |
| 17 #include "content/public/browser/web_contents.h" | |
| 18 #include "content/public/browser/web_contents_observer.h" | |
| 19 #include "content/public/common/child_process_host.h" | |
| 20 #include "url/gurl.h" | |
| 21 | |
| 22 namespace content { | |
| 23 namespace service_worker_client_navigation_utils { | |
| 24 | |
| 25 namespace { | |
| 26 | |
| 27 using OpenURLCallback = base::Callback<void(int, int)>; | |
| 28 | |
| 29 // The OpenURLObserver class is a WebContentsObserver that will wait for a | |
| 30 // WebContents to be initialized, run the |callback| passed to its constructor | |
| 31 // then self destroy. | |
| 32 // The callback will receive the process and frame ids. If something went wrong | |
| 33 // those will be (kInvalidUniqueID, MSG_ROUTING_NONE). | |
| 34 // The callback will be called in the IO thread. | |
| 35 class OpenURLObserver : public WebContentsObserver { | |
| 36 public: | |
| 37 OpenURLObserver(WebContents* web_contents, | |
| 38 int frame_tree_node_id, | |
| 39 const OpenURLCallback& callback) | |
| 40 : WebContentsObserver(web_contents), | |
| 41 frame_tree_node_id_(frame_tree_node_id), | |
| 42 callback_(callback) {} | |
| 43 | |
| 44 void DidCommitProvisionalLoadForFrame( | |
| 45 RenderFrameHost* render_frame_host, | |
| 46 const GURL& validated_url, | |
| 47 ui::PageTransition transition_type) override { | |
| 48 DCHECK(web_contents()); | |
| 49 | |
| 50 RenderFrameHostImpl* rfhi = | |
| 51 static_cast<RenderFrameHostImpl*>(render_frame_host); | |
| 52 if (rfhi->frame_tree_node()->frame_tree_node_id() != frame_tree_node_id_) | |
| 53 return; | |
| 54 | |
| 55 RunCallback(render_frame_host->GetProcess()->GetID(), | |
| 56 render_frame_host->GetRoutingID()); | |
| 57 } | |
| 58 | |
| 59 void RenderProcessGone(base::TerminationStatus status) override { | |
| 60 RunCallback(ChildProcessHost::kInvalidUniqueID, MSG_ROUTING_NONE); | |
| 61 } | |
| 62 | |
| 63 void WebContentsDestroyed() override { | |
| 64 RunCallback(ChildProcessHost::kInvalidUniqueID, MSG_ROUTING_NONE); | |
| 65 } | |
| 66 | |
| 67 private: | |
| 68 void RunCallback(int render_process_id, int render_frame_id) { | |
| 69 // After running the callback, |this| will stop observing, thus | |
| 70 // web_contents() should return nullptr and |RunCallback| should no longer | |
| 71 // be called. Then, |this| will self destroy. | |
| 72 DCHECK(web_contents()); | |
| 73 | |
| 74 BrowserThread::PostTask( | |
| 75 BrowserThread::IO, FROM_HERE, | |
| 76 base::Bind(callback_, render_process_id, render_frame_id)); | |
| 77 Observe(nullptr); | |
| 78 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); | |
| 79 } | |
| 80 | |
| 81 int frame_tree_node_id_; | |
| 82 const OpenURLCallback callback_; | |
| 83 | |
| 84 DISALLOW_COPY_AND_ASSIGN(OpenURLObserver); | |
| 85 }; | |
| 86 | |
| 87 // This is only called for main frame navigations in OpenWindowOnUI(). | |
| 88 void DidOpenURL(const OpenURLCallback& callback, WebContents* web_contents) { | |
| 89 DCHECK(web_contents); | |
| 90 | |
| 91 RenderFrameHostImpl* rfhi = | |
| 92 static_cast<RenderFrameHostImpl*>(web_contents->GetMainFrame()); | |
| 93 new OpenURLObserver(web_contents, | |
| 94 rfhi->frame_tree_node()->frame_tree_node_id(), callback); | |
| 95 } | |
| 96 | |
| 97 void OpenWindowOnUI( | |
| 98 const GURL& url, | |
| 99 const GURL& script_url, | |
| 100 int worker_process_id, | |
| 101 const scoped_refptr<ServiceWorkerContextWrapper>& context_wrapper, | |
| 102 const OpenURLCallback& callback) { | |
| 103 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 104 | |
| 105 BrowserContext* browser_context = | |
| 106 context_wrapper->storage_partition() | |
| 107 ? context_wrapper->storage_partition()->browser_context() | |
| 108 : nullptr; | |
| 109 // We are shutting down. | |
| 110 if (!browser_context) | |
| 111 return; | |
| 112 | |
| 113 RenderProcessHost* render_process_host = | |
| 114 RenderProcessHost::FromID(worker_process_id); | |
| 115 if (render_process_host->IsForGuestsOnly()) { | |
| 116 BrowserThread::PostTask( | |
| 117 BrowserThread::IO, FROM_HERE, | |
| 118 base::Bind(callback, ChildProcessHost::kInvalidUniqueID, | |
| 119 MSG_ROUTING_NONE)); | |
| 120 return; | |
| 121 } | |
| 122 | |
| 123 OpenURLParams params( | |
| 124 url, Referrer::SanitizeForRequest( | |
| 125 url, Referrer(script_url, blink::WebReferrerPolicyDefault)), | |
| 126 NEW_FOREGROUND_TAB, ui::PAGE_TRANSITION_AUTO_TOPLEVEL, | |
| 127 true /* is_renderer_initiated */); | |
| 128 | |
| 129 GetContentClient()->browser()->OpenURL(browser_context, params, | |
| 130 base::Bind(&DidOpenURL, callback)); | |
| 131 } | |
| 132 | |
| 133 void NavigateClientOnUI(const GURL& url, | |
| 134 const GURL& script_url, | |
| 135 int process_id, | |
| 136 int frame_id, | |
| 137 const OpenURLCallback& callback) { | |
| 138 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 139 | |
| 140 RenderFrameHostImpl* rfhi = RenderFrameHostImpl::FromID(process_id, frame_id); | |
| 141 WebContents* web_contents = WebContents::FromRenderFrameHost(rfhi); | |
| 142 | |
| 143 if (!rfhi || !web_contents) { | |
| 144 BrowserThread::PostTask( | |
| 145 BrowserThread::IO, FROM_HERE, | |
| 146 base::Bind(callback, ChildProcessHost::kInvalidUniqueID, | |
| 147 MSG_ROUTING_NONE)); | |
| 148 return; | |
| 149 } | |
| 150 | |
| 151 ui::PageTransition transition = rfhi->GetParent() | |
| 152 ? ui::PAGE_TRANSITION_AUTO_SUBFRAME | |
| 153 : ui::PAGE_TRANSITION_AUTO_TOPLEVEL; | |
| 154 int frame_tree_node_id = rfhi->frame_tree_node()->frame_tree_node_id(); | |
| 155 | |
| 156 OpenURLParams params( | |
| 157 url, Referrer::SanitizeForRequest( | |
| 158 url, Referrer(script_url, blink::WebReferrerPolicyDefault)), | |
| 159 frame_tree_node_id, CURRENT_TAB, transition, | |
| 160 true /* is_renderer_initiated */); | |
| 161 web_contents->OpenURL(params); | |
| 162 new OpenURLObserver(web_contents, frame_tree_node_id, callback); | |
| 163 } | |
| 164 | |
| 165 void DidNavigate(const base::WeakPtr<ServiceWorkerContextCore>& context, | |
| 166 const GURL& origin, | |
| 167 const NavigationCallback& callback, | |
| 168 int render_process_id, | |
| 169 int render_frame_id) { | |
| 170 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 171 | |
| 172 if (!context) { | |
| 173 callback.Run(SERVICE_WORKER_ERROR_ABORT, std::string(), | |
| 174 ServiceWorkerClientInfo()); | |
| 175 return; | |
| 176 } | |
| 177 | |
| 178 if (render_process_id == ChildProcessHost::kInvalidUniqueID && | |
| 179 render_frame_id == MSG_ROUTING_NONE) { | |
| 180 callback.Run(SERVICE_WORKER_ERROR_FAILED, std::string(), | |
| 181 ServiceWorkerClientInfo()); | |
| 182 return; | |
| 183 } | |
| 184 | |
| 185 for (scoped_ptr<ServiceWorkerContextCore::ProviderHostIterator> it = | |
| 186 context->GetClientProviderHostIterator(origin); | |
| 187 !it->IsAtEnd(); it->Advance()) { | |
| 188 ServiceWorkerProviderHost* provider_host = it->GetProviderHost(); | |
| 189 if (provider_host->process_id() != render_process_id || | |
| 190 provider_host->frame_id() != render_frame_id) { | |
| 191 continue; | |
| 192 } | |
| 193 provider_host->GetWindowClientInfo( | |
| 194 base::Bind(callback, SERVICE_WORKER_OK, provider_host->client_uuid())); | |
| 195 return; | |
| 196 } | |
| 197 | |
| 198 // 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. | |
| 200 callback.Run(SERVICE_WORKER_OK, std::string(), ServiceWorkerClientInfo()); | |
| 201 } | |
| 202 | |
| 203 } // namespace | |
| 204 | |
| 205 void OpenWindow(const GURL& url, | |
| 206 const GURL& script_url, | |
| 207 int worker_process_id, | |
| 208 const base::WeakPtr<ServiceWorkerContextCore>& context, | |
| 209 const NavigationCallback& callback) { | |
| 210 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 211 BrowserThread::PostTask( | |
| 212 BrowserThread::UI, FROM_HERE, | |
| 213 base::Bind( | |
| 214 &OpenWindowOnUI, url, script_url, worker_process_id, | |
| 215 make_scoped_refptr(context->wrapper()), | |
| 216 base::Bind(&DidNavigate, context, script_url.GetOrigin(), callback))); | |
| 217 } | |
| 218 | |
| 219 void NavigateClient(const GURL& url, | |
| 220 const GURL& script_url, | |
| 221 int process_id, | |
| 222 int frame_id, | |
| 223 const base::WeakPtr<ServiceWorkerContextCore>& context, | |
| 224 const NavigationCallback& callback) { | |
| 225 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 226 BrowserThread::PostTask( | |
| 227 BrowserThread::UI, FROM_HERE, | |
| 228 base::Bind( | |
| 229 &NavigateClientOnUI, url, script_url, process_id, frame_id, | |
| 230 base::Bind(&DidNavigate, context, script_url.GetOrigin(), callback))); | |
| 231 } | |
| 232 | |
| 233 } // namespace service_worker_client_navigation_utils | |
| 234 } // namespace content | |
| OLD | NEW |