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 |