Re-allow JavaScript dialogs with user navigation.

BUG=587922
TEST=as in bug

Review URL: https://codereview.chromium.org/1733763002

Cr-Commit-Position: refs/heads/master@{#377597}
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index d748d53..3103e95e 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -3153,6 +3153,11 @@
   if (!details.is_in_page)
     CancelActiveAndPendingDialogs();
 
+  // If this is a user-initiated navigation, start allowing JavaScript dialogs
+  // again.
+  if (params.gesture == NavigationGestureUser && dialog_manager_)
+    dialog_manager_->ResetDialogState(this);
+
   // Notify observers about navigation.
   FOR_EACH_OBSERVER(WebContentsObserver, observers_,
                     DidNavigateAnyFrame(render_frame_host, details, params));
@@ -4793,4 +4798,9 @@
   FOR_EACH_OBSERVER(WebContentsObserver, observers_, MediaStoppedPlaying(id));
 }
 
+void WebContentsImpl::SetJavaScriptDialogManagerForTesting(
+    JavaScriptDialogManager* dialog_manager) {
+  dialog_manager_ = dialog_manager;
+}
+
 }  // namespace content
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index 753c690..79c0c86e 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -744,6 +744,8 @@
                            LoadResourceFromMemoryCacheWithBadSecurityInfo);
   FRIEND_TEST_ALL_PREFIXES(WebContentsImplTest,
                            LoadResourceFromMemoryCacheWithEmptySecurityInfo);
+  FRIEND_TEST_ALL_PREFIXES(WebContentsImplTest,
+                           ResetJavaScriptDialogOnUserNavigate);
   FRIEND_TEST_ALL_PREFIXES(FormStructureBrowserTest, HTMLFiles);
   FRIEND_TEST_ALL_PREFIXES(NavigationControllerTest, HistoryNavigate);
   FRIEND_TEST_ALL_PREFIXES(RenderFrameHostManagerTest, PageDoesBackAndReload);
@@ -1028,6 +1030,9 @@
   // the main frame if empty).
   WebUI* CreateWebUI(const GURL& url, const std::string& frame_name);
 
+  void SetJavaScriptDialogManagerForTesting(
+      JavaScriptDialogManager* dialog_manager);
+
   // Data for core operation ---------------------------------------------------
 
   // Delegate for notifying our owner about stuff. Not owned by us.
diff --git a/content/browser/web_contents/web_contents_impl_unittest.cc b/content/browser/web_contents/web_contents_impl_unittest.cc
index 965da64..45d920b 100644
--- a/content/browser/web_contents/web_contents_impl_unittest.cc
+++ b/content/browser/web_contents/web_contents_impl_unittest.cc
@@ -28,6 +28,7 @@
 #include "content/common/view_messages.h"
 #include "content/public/browser/global_request_id.h"
 #include "content/public/browser/interstitial_page_delegate.h"
+#include "content/public/browser/javascript_dialog_manager.h"
 #include "content/public/browser/navigation_details.h"
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_source.h"
@@ -3384,4 +3385,69 @@
   EXPECT_TRUE(backend->HasAllowException(test_url.host()));
 }
 
+class TestJavaScriptDialogManager : public JavaScriptDialogManager {
+ public:
+  TestJavaScriptDialogManager() {}
+  ~TestJavaScriptDialogManager() override {}
+
+  size_t reset_count() { return reset_count_; }
+
+  // JavaScriptDialogManager
+
+  void RunJavaScriptDialog(WebContents* web_contents,
+                           const GURL& origin_url,
+                           const std::string& accept_lang,
+                           JavaScriptMessageType javascript_message_type,
+                           const base::string16& message_text,
+                           const base::string16& default_prompt_text,
+                           const DialogClosedCallback& callback,
+                           bool* did_suppress_message) override {
+    *did_suppress_message = true;
+  };
+
+  void RunBeforeUnloadDialog(WebContents* web_contents,
+                             const base::string16& message_text,
+                             bool is_reload,
+                             const DialogClosedCallback& callback) override {}
+
+  bool HandleJavaScriptDialog(WebContents* web_contents,
+                              bool accept,
+                              const base::string16* prompt_override) override {
+    return true;
+  }
+
+  void CancelActiveAndPendingDialogs(WebContents* web_contents) override {}
+
+  void ResetDialogState(WebContents* web_contents) override { ++reset_count_; }
+
+ private:
+  size_t reset_count_ = 0;
+
+  DISALLOW_COPY_AND_ASSIGN(TestJavaScriptDialogManager);
+};
+
+TEST_F(WebContentsImplTest, ResetJavaScriptDialogOnUserNavigate) {
+  scoped_ptr<TestJavaScriptDialogManager> delegate(
+      new TestJavaScriptDialogManager());
+  contents()->SetJavaScriptDialogManagerForTesting(delegate.get());
+
+  // A user-initiated navigation.
+
+  contents()->GetMainFrame()->PrepareForCommit();
+  contents()->TestDidNavigate(contents()->GetMainFrame(), 1, 0, true,
+                              GURL("about:whatever"),
+                              ui::PAGE_TRANSITION_TYPED);
+  EXPECT_EQ(1u, delegate->reset_count());
+
+  // An automatic navigation.
+
+  contents()->GetMainFrame()->PrepareForCommit();
+  contents()->GetMainFrame()->SendNavigateWithModificationCallback(
+      2, 0, true, GURL(url::kAboutBlankURL), base::Bind(SetAsNonUserGesture));
+
+  EXPECT_EQ(1u, delegate->reset_count());
+
+  contents()->SetJavaScriptDialogManagerForTesting(nullptr);
+}
+
 }  // namespace content