intercept_navigation_throttle.cc 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  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. #include "components/navigation_interception/intercept_navigation_throttle.h"
  5. #include "base/bind.h"
  6. #include "base/threading/thread_task_runner_handle.h"
  7. #include "content/public/browser/navigation_handle.h"
  8. #include "url/gurl.h"
  9. namespace navigation_interception {
  10. // Note: this feature is a no-op on non-Android platforms.
  11. const base::Feature InterceptNavigationThrottle::kAsyncCheck{
  12. "AsyncNavigationIntercept", base::FEATURE_ENABLED_BY_DEFAULT};
  13. InterceptNavigationThrottle::InterceptNavigationThrottle(
  14. content::NavigationHandle* navigation_handle,
  15. CheckCallback should_ignore_callback,
  16. SynchronyMode async_mode)
  17. : content::NavigationThrottle(navigation_handle),
  18. should_ignore_callback_(should_ignore_callback),
  19. ui_task_runner_(base::ThreadTaskRunnerHandle::Get()),
  20. mode_(async_mode) {}
  21. InterceptNavigationThrottle::~InterceptNavigationThrottle() = default;
  22. content::NavigationThrottle::ThrottleCheckResult
  23. InterceptNavigationThrottle::WillStartRequest() {
  24. DCHECK(!should_ignore_);
  25. DCHECK(!navigation_handle()->WasServerRedirect());
  26. return CheckIfShouldIgnoreNavigation();
  27. }
  28. content::NavigationThrottle::ThrottleCheckResult
  29. InterceptNavigationThrottle::WillRedirectRequest() {
  30. if (should_ignore_)
  31. return content::NavigationThrottle::CANCEL_AND_IGNORE;
  32. DCHECK(navigation_handle()->WasServerRedirect());
  33. return CheckIfShouldIgnoreNavigation();
  34. }
  35. content::NavigationThrottle::ThrottleCheckResult
  36. InterceptNavigationThrottle::WillProcessResponse() {
  37. DCHECK(!deferring_);
  38. if (should_ignore_)
  39. return content::NavigationThrottle::CANCEL_AND_IGNORE;
  40. if (pending_checks_ > 0) {
  41. deferring_ = true;
  42. return content::NavigationThrottle::DEFER;
  43. }
  44. return content::NavigationThrottle::PROCEED;
  45. }
  46. const char* InterceptNavigationThrottle::GetNameForLogging() {
  47. return "InterceptNavigationThrottle";
  48. }
  49. content::NavigationThrottle::ThrottleCheckResult
  50. InterceptNavigationThrottle::CheckIfShouldIgnoreNavigation() {
  51. if (ShouldCheckAsynchronously()) {
  52. pending_checks_++;
  53. ui_task_runner_->PostTask(
  54. FROM_HERE, base::BindOnce(&InterceptNavigationThrottle::RunCheckAsync,
  55. weak_factory_.GetWeakPtr()));
  56. return content::NavigationThrottle::PROCEED;
  57. }
  58. // No need to set |should_ignore_| since if it is true, we'll cancel the
  59. // navigation immediately.
  60. return should_ignore_callback_.Run(navigation_handle())
  61. ? content::NavigationThrottle::CANCEL_AND_IGNORE
  62. : content::NavigationThrottle::PROCEED;
  63. // Careful, |this| can be deleted at this point.
  64. }
  65. void InterceptNavigationThrottle::RunCheckAsync() {
  66. DCHECK(base::FeatureList::IsEnabled(kAsyncCheck));
  67. DCHECK_GT(pending_checks_, 0);
  68. pending_checks_--;
  69. bool final_deferred_check = deferring_ && pending_checks_ == 0;
  70. auto weak_this = weak_factory_.GetWeakPtr();
  71. bool should_ignore = should_ignore_callback_.Run(navigation_handle());
  72. if (!weak_this)
  73. return;
  74. should_ignore_ |= should_ignore;
  75. if (!final_deferred_check)
  76. return;
  77. if (should_ignore) {
  78. CancelDeferredNavigation(content::NavigationThrottle::CANCEL_AND_IGNORE);
  79. } else {
  80. Resume();
  81. }
  82. }
  83. bool InterceptNavigationThrottle::ShouldCheckAsynchronously() const {
  84. // Do not apply the async optimization for:
  85. // - Throttles in non-async mode.
  86. // - POST navigations, to ensure we aren't violating idempotency.
  87. // - Subframe navigations, which aren't observed on Android, and should be
  88. // fast on other platforms.
  89. // - non-http/s URLs, which are more likely to be intercepted.
  90. return mode_ == SynchronyMode::kAsync &&
  91. navigation_handle()->IsInMainFrame() &&
  92. !navigation_handle()->IsPost() &&
  93. navigation_handle()->GetURL().SchemeIsHTTPOrHTTPS() &&
  94. base::FeatureList::IsEnabled(kAsyncCheck);
  95. }
  96. } // namespace navigation_interception