(Merging on behalf of mdw@)
Add UMA to count the number of Google CAPTCHA pages shown and solved by users.
This is intended to track down problems where a large number of mobile
users in certain countries are apparently seeing CAPTCHA pages.
(http://b2.corp.google.com/23081866 for context.)
I realize this may not be the ideal place for this code - happy for suggestions as to where else this might go.
BUG=552470
Review URL: https://codereview.chromium.org/1441393002
Cr-Commit-Position: refs/heads/master@{#360011}
(cherry picked from commit 71c7cacbdb9cd4fa161909a72a9157f574a2b775)
Review URL: https://codereview.chromium.org/1465533002 .
Cr-Commit-Position: refs/branch-heads/2564@{#58}
Cr-Branched-From: 1283eca15bd9f772387f75241576cde7bdec7f54-refs/heads/master@{#359700}
diff --git a/chrome/browser/page_load_metrics/observers/google_captcha_observer.cc b/chrome/browser/page_load_metrics/observers/google_captcha_observer.cc
new file mode 100644
index 0000000..dd746a6d
--- /dev/null
+++ b/chrome/browser/page_load_metrics/observers/google_captcha_observer.cc
@@ -0,0 +1,65 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/page_load_metrics/observers/google_captcha_observer.h"
+
+#include "base/metrics/histogram.h"
+#include "base/strings/string_util.h"
+#include "components/page_load_metrics/browser/page_load_metrics_macros.h"
+#include "components/page_load_metrics/common/page_load_timing.h"
+#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
+
+namespace google_captcha_observer {
+
+namespace {
+
+const char kGoogleCaptchaEvents[] = "PageLoad.Clients.GoogleCaptcha.Events";
+
+enum GoogleCaptchaEvent {
+ // A Google CAPTCHA page was shown to the user.
+ GOOGLE_CAPTCHA_SHOWN,
+ // A Google CAPTCHA page was solved by the user.
+ GOOGLE_CAPTCHA_SOLVED,
+ // Add new values before this final count.
+ GOOGLE_CAPTCHA_EVENT_BOUNDARY,
+};
+
+void RecordGoogleCaptchaEvent(GoogleCaptchaEvent event) {
+ UMA_HISTOGRAM_ENUMERATION(
+ kGoogleCaptchaEvents, event,
+ GOOGLE_CAPTCHA_EVENT_BOUNDARY);
+}
+
+} // namespace
+
+bool IsGoogleCaptcha(const GURL& url) {
+ return (base::StartsWith(url.host(), "ipv4.google.",
+ base::CompareCase::SENSITIVE)
+ || base::StartsWith(url.host(), "ipv6.google.",
+ base::CompareCase::SENSITIVE))
+ && base::StartsWith(url.path(), "/sorry", base::CompareCase::SENSITIVE);
+}
+
+GoogleCaptchaObserver::GoogleCaptchaObserver(
+ page_load_metrics::PageLoadMetricsObservable* metrics)
+ : metrics_(metrics) {}
+
+void GoogleCaptchaObserver::OnCommit(
+ content::NavigationHandle* navigation_handle) {
+ if (IsGoogleCaptcha(navigation_handle->GetURL()))
+ RecordGoogleCaptchaEvent(GOOGLE_CAPTCHA_SHOWN);
+}
+
+void GoogleCaptchaObserver::OnRedirect(
+ content::NavigationHandle* navigation_handle) {
+ if (IsGoogleCaptcha(navigation_handle->GetReferrer().url))
+ RecordGoogleCaptchaEvent(GOOGLE_CAPTCHA_SOLVED);
+}
+
+void GoogleCaptchaObserver::OnPageLoadMetricsGoingAway() {
+ metrics_->RemoveObserver(this);
+ delete this;
+}
+
+} // namespace google_captcha_observer
diff --git a/chrome/browser/page_load_metrics/observers/google_captcha_observer.h b/chrome/browser/page_load_metrics/observers/google_captcha_observer.h
new file mode 100644
index 0000000..4b0cfc52
--- /dev/null
+++ b/chrome/browser/page_load_metrics/observers/google_captcha_observer.h
@@ -0,0 +1,35 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_GOOGLE_CAPTCHA_OBSERVER_H_
+#define CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_GOOGLE_CAPTCHA_OBSERVER_H_
+
+#include "base/macros.h"
+#include "components/page_load_metrics/browser/page_load_metrics_observer.h"
+
+namespace google_captcha_observer {
+
+// Returns true if the given URL matches a Google CAPTCHA page.
+bool IsGoogleCaptcha(const GURL& url);
+
+class GoogleCaptchaObserver
+ : public page_load_metrics::PageLoadMetricsObserver {
+ public:
+ explicit GoogleCaptchaObserver(
+ page_load_metrics::PageLoadMetricsObservable* metrics);
+
+ // page_load_metrics::PageLoadMetricsObserver implementation:
+ void OnCommit(content::NavigationHandle* navigation_handle) override;
+ void OnRedirect(content::NavigationHandle* navigation_handle) override;
+ void OnPageLoadMetricsGoingAway() override;
+
+ private:
+ page_load_metrics::PageLoadMetricsObservable* const metrics_;
+ DISALLOW_COPY_AND_ASSIGN(GoogleCaptchaObserver);
+
+};
+
+} // namespace google_captcha_observer
+
+#endif // CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_GOOGLE_CAPTCHA_OBSERVER_H_
diff --git a/chrome/browser/page_load_metrics/observers/page_load_metrics_observers_unittest.cc b/chrome/browser/page_load_metrics/observers/page_load_metrics_observers_unittest.cc
index e6716ea..da6a7a443 100644
--- a/chrome/browser/page_load_metrics/observers/page_load_metrics_observers_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/page_load_metrics_observers_unittest.cc
@@ -5,6 +5,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/test/histogram_tester.h"
#include "chrome/browser/page_load_metrics/observers/from_gws_page_load_metrics_observer.h"
+#include "chrome/browser/page_load_metrics/observers/google_captcha_observer.h"
#include "chrome/test/base/chrome_render_view_host_test_harness.h"
#include "components/page_load_metrics/browser/metrics_web_contents_observer.h"
#include "components/page_load_metrics/common/page_load_metrics_messages.h"
@@ -230,3 +231,23 @@
NavigateAndCommit(GURL("https://www.google.com"));
histogram_tester_.ExpectTotalCount(kHistogramNameFromGWSFirstTextPaint, 0);
}
+
+TEST_F(PageLoadMetricsObserverTest, IsGoogleCaptcha) {
+ struct {
+ std::string url;
+ bool expected;
+ } test_cases[] = {
+ {"", false},
+ {"http://www.google.com/", false},
+ {"http://www.cnn.com/", false},
+ {"http://ipv4.google.com/", false},
+ {"https://ipv4.google.com/sorry/IndexRedirect?continue=http://a", true},
+ {"https://ipv6.google.com/sorry/IndexRedirect?continue=http://a", true},
+ {"https://ipv7.google.com/sorry/IndexRedirect?continue=http://a", false},
+ };
+ for (const auto& test : test_cases) {
+ EXPECT_EQ(test.expected,
+ google_captcha_observer::IsGoogleCaptcha(GURL(test.url)))
+ << "for URL: " << test.url;
+ }
+}
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc b/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc
index 1f92497..16542e41 100644
--- a/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc
+++ b/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc
@@ -6,7 +6,9 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/page_load_metrics/observers/from_gws_page_load_metrics_observer.h"
+#include "chrome/browser/page_load_metrics/observers/google_captcha_observer.h"
#include "chrome/browser/prerender/prerender_contents.h"
+#include "components/page_load_metrics/browser/metrics_web_contents_observer.h"
#include "components/rappor/rappor_service.h"
#include "content/public/browser/web_contents.h"
@@ -19,6 +21,8 @@
// This is a self-destruct class, and will delete itself when triggered by
// OnPageLoadMetricsGoingAway.
metrics->AddObserver(new FromGWSPageLoadMetricsObserver(metrics));
+ metrics->AddObserver(
+ new google_captcha_observer::GoogleCaptchaObserver(metrics));
}
} // namespace
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index d126685..7a71a70 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -678,6 +678,8 @@
'browser/net/predictor_tab_helper.h',
'browser/page_load_metrics/observers/from_gws_page_load_metrics_observer.cc',
'browser/page_load_metrics/observers/from_gws_page_load_metrics_observer.h',
+ 'browser/page_load_metrics/observers/google_captcha_observer.cc',
+ 'browser/page_load_metrics/observers/google_captcha_observer.h',
'browser/page_load_metrics/page_load_metrics_initialize.cc',
'browser/page_load_metrics/page_load_metrics_initialize.h',
'browser/performance_monitor/performance_monitor.cc',
diff --git a/components/page_load_metrics/browser/metrics_web_contents_observer.cc b/components/page_load_metrics/browser/metrics_web_contents_observer.cc
index 7e753bca..42503e2 100644
--- a/components/page_load_metrics/browser/metrics_web_contents_observer.cc
+++ b/components/page_load_metrics/browser/metrics_web_contents_observer.cc
@@ -7,6 +7,7 @@
#include "base/location.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
+#include "base/metrics/user_metrics.h"
#include "components/page_load_metrics/browser/page_load_metrics_macros.h"
#include "components/page_load_metrics/common/page_load_metrics_messages.h"
#include "components/page_load_metrics/common/page_load_timing.h"
@@ -160,6 +161,11 @@
OnCommit(navigation_handle));
}
+void PageLoadTracker::Redirect(content::NavigationHandle* navigation_handle) {
+ FOR_EACH_OBSERVER(PageLoadMetricsObserver, *observers_,
+ OnRedirect(navigation_handle));
+}
+
bool PageLoadTracker::UpdateTiming(const PageLoadTiming& new_timing) {
// Throw away IPCs that are not relevant to the current navigation.
// Two timing structures cannot refer to the same navigation if they indicate
@@ -487,6 +493,16 @@
committed_load_->Commit(navigation_handle);
}
+void MetricsWebContentsObserver::DidRedirectNavigation(
+ content::NavigationHandle* navigation_handle) {
+ if (!navigation_handle->IsInMainFrame())
+ return;
+ auto it = provisional_loads_.find(navigation_handle);
+ if (it == provisional_loads_.end())
+ return;
+ it->second->Redirect(navigation_handle);
+}
+
void MetricsWebContentsObserver::WasShown() {
in_foreground_ = true;
if (committed_load_)
diff --git a/components/page_load_metrics/browser/metrics_web_contents_observer.h b/components/page_load_metrics/browser/metrics_web_contents_observer.h
index e6fd36e..ae61708 100644
--- a/components/page_load_metrics/browser/metrics_web_contents_observer.h
+++ b/components/page_load_metrics/browser/metrics_web_contents_observer.h
@@ -180,6 +180,7 @@
PageLoadMetricsEmbedderInterface* embedder_interface,
base::ObserverList<PageLoadMetricsObserver, true>* observers);
~PageLoadTracker();
+ void Redirect(content::NavigationHandle* navigation_handle);
void Commit(content::NavigationHandle* navigation_handle);
void WebContentsHidden();
void WebContentsShown();
@@ -248,6 +249,8 @@
content::NavigationHandle* navigation_handle) override;
void DidFinishNavigation(
content::NavigationHandle* navigation_handle) override;
+ void DidRedirectNavigation(
+ content::NavigationHandle* navigation_handle) override;
void WasShown() override;
void WasHidden() override;
diff --git a/components/page_load_metrics/browser/page_load_metrics_observer.h b/components/page_load_metrics/browser/page_load_metrics_observer.h
index d181d14..08a35dd 100644
--- a/components/page_load_metrics/browser/page_load_metrics_observer.h
+++ b/components/page_load_metrics/browser/page_load_metrics_observer.h
@@ -40,6 +40,11 @@
public:
virtual ~PageLoadMetricsObserver() {}
+ // OnRedirect is triggered when a page load redirects to another URL.
+ // The navigation handle holds relevant data for the navigation, but will
+ // be destroyed soon after this call. Don't hold a reference to it.
+ virtual void OnRedirect(content::NavigationHandle* navigation_handle) {}
+
// OnCommit is triggered when a page load commits, i.e. when we receive the
// first data for the request. The navigation handle holds relevant data for
// the navigation, but will be destroyed soon after this call. Don't hold a
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index d76d7574..09bcfb8a 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -30806,6 +30806,12 @@
</summary>
</histogram>
+<histogram name="PageLoad.Clients.GoogleCaptcha.Events"
+ enum="GoogleCaptchaEvent">
+ <owner>mdw@chromium.org</owner>
+ <summary>Events related to Google CAPTCHA pages being seen by users.</summary>
+</histogram>
+
<histogram name="PageLoad.EventCounts" enum="PageLoadEvent">
<owner>csharrison@chromium.org</owner>
<owner>bmcquade@chromium.org</owner>
@@ -63416,6 +63422,11 @@
<int value="6" label="UNSET"/>
</enum>
+<enum name="GoogleCaptchaEvent" type="int">
+ <int value="0" label="Google CAPTCHA shown"/>
+ <int value="1" label="Google CAPTCHA solved"/>
+</enum>
+
<enum name="GoogleNowCardTypeId" type="int">
<summary>
Represents a card type ID. See cardTypeId in