Fix crash in CefResourceDispatcherHostDelegate::HandleExternalProtocol when destroying a browser during redirect (issue #1941)

This commit is contained in:
Marshall Greenblatt 2016-07-08 15:28:53 -04:00
parent 9d8b8dd8c6
commit ec3e9ed7fe
2 changed files with 69 additions and 5 deletions

View File

@ -86,10 +86,12 @@ bool CefResourceDispatcherHostDelegate::HandleExternalProtocol(
bool has_user_gesture) { bool has_user_gesture) {
if (CEF_CURRENTLY_ON_UIT()) { if (CEF_CURRENTLY_ON_UIT()) {
content::WebContents* web_contents = web_contents_getter.Run(); content::WebContents* web_contents = web_contents_getter.Run();
if (web_contents) {
CefRefPtr<CefBrowserHostImpl> browser = CefRefPtr<CefBrowserHostImpl> browser =
CefBrowserHostImpl::GetBrowserForContents(web_contents); CefBrowserHostImpl::GetBrowserForContents(web_contents);
if (browser.get()) if (browser.get())
browser->HandleExternalProtocol(url); browser->HandleExternalProtocol(url);
}
} else { } else {
CEF_POST_TASK(CEF_UIT, CEF_POST_TASK(CEF_UIT,
base::Bind(base::IgnoreResult(&CefResourceDispatcherHostDelegate:: base::Bind(base::IgnoreResult(&CefResourceDispatcherHostDelegate::

View File

@ -713,7 +713,12 @@ class RedirectSchemeHandler : public CefResourceHandler {
class RedirectSchemeHandlerFactory : public CefSchemeHandlerFactory { class RedirectSchemeHandlerFactory : public CefSchemeHandlerFactory {
public: public:
RedirectSchemeHandlerFactory() {} RedirectSchemeHandlerFactory() {
g_got_nav1_request = false;
g_got_nav3_request = false;
g_got_nav4_request = false;
g_got_invalid_request = false;
}
CefRefPtr<CefResourceHandler> Create( CefRefPtr<CefResourceHandler> Create(
CefRefPtr<CefBrowser> browser, CefRefPtr<CefBrowser> browser,
@ -829,6 +834,41 @@ class RedirectTestHandler : public TestHandler {
IMPLEMENT_REFCOUNTING(RedirectTestHandler); IMPLEMENT_REFCOUNTING(RedirectTestHandler);
}; };
// Like above but destroy the WebContents while the redirect is in-progress.
class RedirectDestroyTestHandler : public TestHandler {
public:
RedirectDestroyTestHandler() {}
void RunTest() override {
// Create the browser.
CreateBrowser(kRNav1);
// Time out the test after a reasonable period of time.
SetTestTimeout();
}
void OnResourceRedirect(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request,
CefString& new_url) override {
const std::string& old_url = request->GetURL();
if (old_url == kRNav1 && new_url == kRNav2) {
// Called due to the nav1 redirect response.
got_nav1_redirect_.yes();
new_url = "about:blank";
// Destroy the test (and the underlying WebContents) while the redirect
// is still pending.
DestroyTest();
}
}
TrackCallback got_nav1_redirect_;
IMPLEMENT_REFCOUNTING(RedirectDestroyTestHandler);
};
} // namespace } // namespace
// Verify frame names and identifiers. // Verify frame names and identifiers.
@ -864,6 +904,28 @@ TEST(NavigationTest, Redirect) {
ReleaseAndWaitForDestructor(handler); ReleaseAndWaitForDestructor(handler);
} }
// Verify that destroying the WebContents while the redirect is in-progress does
// not result in a crash.
TEST(NavigationTest, RedirectDestroy) {
CefRegisterSchemeHandlerFactory("http", "tests",
new RedirectSchemeHandlerFactory());
WaitForIOThread();
CefRefPtr<RedirectDestroyTestHandler> handler =
new RedirectDestroyTestHandler();
handler->ExecuteTest();
CefClearSchemeHandlerFactories();
WaitForIOThread();
ASSERT_TRUE(handler->got_nav1_redirect_);
ASSERT_TRUE(g_got_nav1_request);
ASSERT_FALSE(g_got_nav3_request);
ASSERT_FALSE(g_got_nav4_request);
ASSERT_FALSE(g_got_invalid_request);
ReleaseAndWaitForDestructor(handler);
}
namespace { namespace {