Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/browser/frame_host/navigation_controller_impl.h" | 5 #include "content/browser/frame_host/navigation_controller_impl.h" |
| 6 | 6 |
| 7 #include <stdint.h> | 7 #include <stdint.h> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| 11 #include "base/command_line.h" | 11 #include "base/command_line.h" |
| 12 #include "base/macros.h" | 12 #include "base/macros.h" |
| 13 #include "base/strings/stringprintf.h" | 13 #include "base/strings/stringprintf.h" |
| 14 #include "base/strings/utf_string_conversions.h" | 14 #include "base/strings/utf_string_conversions.h" |
| 15 #include "content/browser/frame_host/frame_navigation_entry.h" | 15 #include "content/browser/frame_host/frame_navigation_entry.h" |
| 16 #include "content/browser/frame_host/frame_tree.h" | 16 #include "content/browser/frame_host/frame_tree.h" |
| 17 #include "content/browser/frame_host/navigation_entry_impl.h" | 17 #include "content/browser/frame_host/navigation_entry_impl.h" |
| 18 #include "content/browser/loader/resource_dispatcher_host_impl.h" | 18 #include "content/browser/loader/resource_dispatcher_host_impl.h" |
| 19 #include "content/browser/web_contents/web_contents_impl.h" | 19 #include "content/browser/web_contents/web_contents_impl.h" |
| 20 #include "content/common/frame_messages.h" | 20 #include "content/common/frame_messages.h" |
| 21 #include "content/common/page_state_serialization.h" | 21 #include "content/common/page_state_serialization.h" |
| 22 #include "content/common/site_isolation_policy.h" | 22 #include "content/common/site_isolation_policy.h" |
| 23 #include "content/public/browser/navigation_handle.h" | 23 #include "content/public/browser/navigation_handle.h" |
| 24 #include "content/public/browser/render_view_host.h" | 24 #include "content/public/browser/render_view_host.h" |
| 25 #include "content/public/browser/resource_controller.h" | 25 #include "content/public/browser/resource_controller.h" |
| 26 #include "content/public/browser/resource_dispatcher_host.h" | 26 #include "content/public/browser/resource_dispatcher_host.h" |
| 27 #include "content/public/browser/resource_dispatcher_host_delegate.h" | 27 #include "content/public/browser/resource_dispatcher_host_delegate.h" |
| 28 #include "content/public/browser/resource_throttle.h" | 28 #include "content/public/browser/resource_throttle.h" |
| 29 #include "content/public/browser/web_contents.h" | 29 #include "content/public/browser/web_contents.h" |
| 30 #include "content/public/browser/web_contents_delegate.h" | |
| 30 #include "content/public/browser/web_contents_observer.h" | 31 #include "content/public/browser/web_contents_observer.h" |
| 31 #include "content/public/common/bindings_policy.h" | 32 #include "content/public/common/bindings_policy.h" |
| 32 #include "content/public/common/browser_side_navigation_policy.h" | 33 #include "content/public/common/browser_side_navigation_policy.h" |
| 33 #include "content/public/common/renderer_preferences.h" | 34 #include "content/public/common/renderer_preferences.h" |
| 34 #include "content/public/common/url_constants.h" | 35 #include "content/public/common/url_constants.h" |
| 35 #include "content/public/test/browser_test_utils.h" | 36 #include "content/public/test/browser_test_utils.h" |
| 36 #include "content/public/test/content_browser_test.h" | 37 #include "content/public/test/content_browser_test.h" |
| 37 #include "content/public/test/content_browser_test_utils.h" | 38 #include "content/public/test/content_browser_test_utils.h" |
| 38 #include "content/public/test/test_navigation_observer.h" | 39 #include "content/public/test/test_navigation_observer.h" |
| 39 #include "content/public/test/test_utils.h" | 40 #include "content/public/test/test_utils.h" |
| (...skipping 5921 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5961 } | 5962 } |
| 5962 | 5963 |
| 5963 // Verify the expected origin through JavaScript. It also has the additional | 5964 // Verify the expected origin through JavaScript. It also has the additional |
| 5964 // verification of the process also being still alive. | 5965 // verification of the process also being still alive. |
| 5965 std::string origin; | 5966 std::string origin; |
| 5966 EXPECT_TRUE(ExecuteScriptAndExtractString( | 5967 EXPECT_TRUE(ExecuteScriptAndExtractString( |
| 5967 web_contents, "domAutomationController.send(document.origin)", &origin)); | 5968 web_contents, "domAutomationController.send(document.origin)", &origin)); |
| 5968 EXPECT_EQ(start_url.GetOrigin().spec(), origin + "/"); | 5969 EXPECT_EQ(start_url.GetOrigin().spec(), origin + "/"); |
| 5969 } | 5970 } |
| 5970 | 5971 |
| 5971 // A BrowserMessageFilter that delays FrameHostMsg_DidCommitProvisionaLoad IPC | 5972 // A BrowserMessageFilter that delays FrameHostMsg_DidCommitProvisionalLoad IPC |
| 5972 // message for a specified URL, navigates the WebContents back and then | 5973 // message for a specified URL, navigates the WebContents back and then |
| 5973 // processes the commit message. | 5974 // processes the commit message. |
| 5974 class GoBackAndCommitFilter : public BrowserMessageFilter { | 5975 class GoBackAndCommitFilter : public BrowserMessageFilter { |
| 5975 public: | 5976 public: |
| 5976 GoBackAndCommitFilter(const GURL& url, WebContentsImpl* web_contents) | 5977 GoBackAndCommitFilter(const GURL& url, WebContentsImpl* web_contents) |
| 5977 : BrowserMessageFilter(FrameMsgStart), | 5978 : BrowserMessageFilter(FrameMsgStart), |
| 5978 url_(url), | 5979 url_(url), |
| 5979 web_contents_(web_contents) {} | 5980 web_contents_(web_contents) {} |
| 5980 | 5981 |
| 5981 protected: | 5982 protected: |
| 5982 ~GoBackAndCommitFilter() override {} | 5983 ~GoBackAndCommitFilter() override {} |
| 5983 | 5984 |
| 5984 private: | 5985 private: |
| 5985 static void NavigateBackAndCommit(const IPC::Message& message, | 5986 static void NavigateBackAndCommit(const IPC::Message& message, |
| 5986 WebContentsImpl* web_contents) { | 5987 WebContentsImpl* web_contents) { |
| 5987 web_contents->GetController().GoBack(); | 5988 web_contents->GetController().GoBack(); |
| 5988 | 5989 |
| 5989 RenderFrameHostImpl* rfh = web_contents->GetMainFrame(); | 5990 RenderFrameHostImpl* rfh = web_contents->GetMainFrame(); |
| 5990 DCHECK_EQ(rfh->routing_id(), message.routing_id()); | 5991 DCHECK_EQ(rfh->routing_id(), message.routing_id()); |
| 5991 rfh->OnMessageReceived(message); | 5992 rfh->OnMessageReceived(message); |
| 5992 } | 5993 } |
| 5993 | 5994 |
| 5994 // BrowserMessageFilter: | 5995 // BrowserMessageFilter: |
| 5995 bool OnMessageReceived(const IPC::Message& message) override { | 5996 bool OnMessageReceived(const IPC::Message& message) override { |
| 5996 if (message.type() != FrameHostMsg_DidCommitProvisionalLoad::ID) | 5997 if (message.type() != FrameHostMsg_DidCommitProvisionalLoad::ID) |
| 5997 return false; | 5998 return false; |
| 5998 | 5999 |
| 5999 // Parse the IPC message so the URL can be checked agains the expected one. | 6000 // Parse the IPC message so the URL can be checked against the expected one. |
| 6000 base::PickleIterator iter(message); | 6001 base::PickleIterator iter(message); |
| 6001 FrameHostMsg_DidCommitProvisionalLoad_Params validated_params; | 6002 FrameHostMsg_DidCommitProvisionalLoad_Params validated_params; |
| 6002 if (!IPC::ParamTraits<FrameHostMsg_DidCommitProvisionalLoad_Params>::Read( | 6003 if (!IPC::ParamTraits<FrameHostMsg_DidCommitProvisionalLoad_Params>::Read( |
| 6003 &message, &iter, &validated_params)) { | 6004 &message, &iter, &validated_params)) { |
| 6004 return false; | 6005 return false; |
| 6005 } | 6006 } |
| 6006 | 6007 |
| 6007 // Only handle the message if the URLs are matching. | 6008 // Only handle the message if the URLs are matching. |
| 6008 if (validated_params.url != url_) | 6009 if (validated_params.url != url_) |
| 6009 return false; | 6010 return false; |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6130 entry = controller.GetLastCommittedEntry(); | 6131 entry = controller.GetLastCommittedEntry(); |
| 6131 content::FaviconStatus& favicon_status2 = entry->GetFavicon(); | 6132 content::FaviconStatus& favicon_status2 = entry->GetFavicon(); |
| 6132 EXPECT_TRUE(favicon_status2.valid); | 6133 EXPECT_TRUE(favicon_status2.valid); |
| 6133 | 6134 |
| 6134 ASSERT_TRUE(RendererLocationReplace(shell(), GURL("data:text/html,page2"))); | 6135 ASSERT_TRUE(RendererLocationReplace(shell(), GURL("data:text/html,page2"))); |
| 6135 entry = controller.GetLastCommittedEntry(); | 6136 entry = controller.GetLastCommittedEntry(); |
| 6136 content::FaviconStatus& favicon_status3 = entry->GetFavicon(); | 6137 content::FaviconStatus& favicon_status3 = entry->GetFavicon(); |
| 6137 EXPECT_FALSE(favicon_status3.valid); | 6138 EXPECT_FALSE(favicon_status3.valid); |
| 6138 } | 6139 } |
| 6139 | 6140 |
| 6141 namespace { | |
| 6142 | |
| 6143 // A BrowserMessageFilter that delays the FrameHostMsg_RunJavaScriptMessage IPC | |
| 6144 // message until a commit happens on a given WebContents. This allows testing a | |
| 6145 // race condition. | |
| 6146 class AllowDialogIPCOnCommitFilter : public BrowserMessageFilter, | |
| 6147 public WebContentsDelegate { | |
| 6148 public: | |
| 6149 AllowDialogIPCOnCommitFilter(WebContents* web_contents) | |
| 6150 : BrowserMessageFilter(FrameMsgStart), | |
| 6151 render_frame_host_(web_contents->GetMainFrame()) { | |
| 6152 web_contents_observer_.Observe(web_contents); | |
| 6153 } | |
| 6154 | |
| 6155 protected: | |
| 6156 ~AllowDialogIPCOnCommitFilter() override {} | |
| 6157 | |
| 6158 private: | |
| 6159 // BrowserMessageFilter: | |
| 6160 bool OnMessageReceived(const IPC::Message& message) override { | |
| 6161 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 6162 if (message.type() != FrameHostMsg_RunJavaScriptMessage::ID) | |
| 6163 return false; | |
| 6164 | |
| 6165 // Suspend the message. | |
| 6166 web_contents_observer_.SetCallback( | |
| 6167 base::Bind(&RenderFrameHost::OnMessageReceived, | |
| 6168 base::Unretained(render_frame_host_), message)); | |
| 6169 return true; | |
| 6170 } | |
| 6171 | |
| 6172 // WebContentsDelegate: | |
| 6173 JavaScriptDialogManager* GetJavaScriptDialogManager( | |
| 6174 WebContents* source) override { | |
| 6175 CHECK(false); | |
| 6176 return nullptr; // agh compiler | |
| 6177 } | |
| 6178 | |
| 6179 // Separate because WebContentsObserver and BrowserMessageFilter each have an | |
| 6180 // OnMessageReceived function; this is the simplest way to disambiguate. | |
| 6181 class : public WebContentsObserver { | |
|
Charlie Reis
2016/09/28 17:14:16
Wow, I don't know that I've seen anonymous inner c
Avi (use Gerrit)
2016/09/28 17:46:16
Thanks! I'm not trying to be clever; this seems to
| |
| 6182 public: | |
| 6183 using Callback = base::Callback<bool()>; | |
| 6184 | |
| 6185 using WebContentsObserver::Observe; | |
|
Charlie Reis
2016/09/28 17:14:16
Is this needed? Seems like we should be able to r
Avi (use Gerrit)
2016/09/28 17:46:16
No, it's protected, and even though (I think) ther
| |
| 6186 | |
| 6187 void SetCallback(Callback callback) { callback_ = callback; } | |
| 6188 | |
| 6189 private: | |
| 6190 void DidNavigateAnyFrame(RenderFrameHost* render_frame_host, | |
| 6191 const LoadCommittedDetails& details, | |
| 6192 const FrameNavigateParams& params) override { | |
| 6193 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 6194 | |
| 6195 // Resume the message. | |
| 6196 callback_.Run(); | |
| 6197 } | |
| 6198 | |
| 6199 Callback callback_; | |
| 6200 } web_contents_observer_; | |
| 6201 | |
| 6202 RenderFrameHost* render_frame_host_; | |
| 6203 | |
| 6204 DISALLOW_COPY_AND_ASSIGN(AllowDialogIPCOnCommitFilter); | |
| 6205 }; | |
| 6206 | |
| 6207 } // namespace | |
| 6208 | |
| 6209 // Check that swapped out frames cannot spawn JavaScript dialogs. | |
| 6210 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, | |
| 6211 NoDialogsFromSwappedOutFrames) { | |
| 6212 // Start on a normal page. | |
| 6213 GURL url1 = embedded_test_server()->GetURL( | |
| 6214 "/navigation_controller/beforeunload_dialog.html"); | |
| 6215 EXPECT_TRUE(NavigateToURL(shell(), url1)); | |
| 6216 | |
| 6217 // Add a filter to allow us to force an IPC race. | |
| 6218 WebContents* web_contents = shell()->web_contents(); | |
| 6219 scoped_refptr<AllowDialogIPCOnCommitFilter> filter = | |
| 6220 new AllowDialogIPCOnCommitFilter(web_contents); | |
| 6221 web_contents->SetDelegate(filter.get()); | |
| 6222 web_contents->GetMainFrame()->GetProcess()->AddFilter(filter.get()); | |
| 6223 | |
| 6224 // Use a chrome:// url to force the second page to be in a different process. | |
| 6225 GURL url2(std::string(kChromeUIScheme) + url::kStandardSchemeSeparator + | |
| 6226 kChromeUIGpuHost); | |
| 6227 EXPECT_TRUE(NavigateToURL(shell(), url2)); | |
| 6228 | |
| 6229 // What happens now is that attempting to unload the first page will trigger a | |
| 6230 // JavaScript alert but allow navigation. The alert IPC will be suspended by | |
| 6231 // the message filter. The commit of the second page will unblock the IPC. If | |
| 6232 // the dialog IPC is allowed to spawn a dialog, the call by the WebContents to | |
| 6233 // its delegate to get the JavaScriptDialogManager will cause a CHECK and the | |
| 6234 // test will fail. | |
| 6235 } | |
| 6236 | |
| 6140 } // namespace content | 6237 } // namespace content |
| OLD | NEW |