Chromium Code Reviews| Index: content/browser/frame_host/navigation_handle_impl.cc |
| diff --git a/content/browser/frame_host/navigation_handle_impl.cc b/content/browser/frame_host/navigation_handle_impl.cc |
| index fda35af58e877586b5736f89e81dd4ea45c01606..b9cdeb6bf4a57287e75248d8fedbaf9f2df5435a 100644 |
| --- a/content/browser/frame_host/navigation_handle_impl.cc |
| +++ b/content/browser/frame_host/navigation_handle_impl.cc |
| @@ -54,6 +54,33 @@ void NotifyAbandonedTransferNavigation(const GlobalRequestID& id) { |
| rdh->CancelRequest(id.child_id, id.request_id); |
| } |
| +// This is a helper method used in IsSelfReferentialURL. It checks if two |
| +// URLs are identical when the URL fragments are removed. |
| +bool EqualIgnoringFragmentIdentifier(const GURL& a, const GURL& b) { |
|
nasko
2017/02/07 19:51:20
This is actually being implemented in GURL itself
davidsac (gone - try alexmos)
2017/02/10 18:44:26
Acknowledged.
|
| + // Compute the length of each URL without its ref. Note that the reference |
| + // begin (if it exists) points to the character *after* the '#', so we need |
| + // to subtract one. |
| + int aLength = a.spec().length(); |
| + if (a.parsed_for_possibly_invalid_spec().ref.len >= 0) |
| + aLength = a.parsed_for_possibly_invalid_spec().ref.begin - 1; |
| + |
| + int bLength = b.spec().length(); |
| + if (b.parsed_for_possibly_invalid_spec().ref.len >= 0) |
| + bLength = b.parsed_for_possibly_invalid_spec().ref.begin - 1; |
| + |
| + if (aLength != bLength) |
| + return false; |
| + |
| + const std::string& aString = a.spec(); |
| + const std::string& bString = b.spec(); |
| + // FIXME: Abstraction this into a function in WTFString.h. |
| + for (int i = 0; i < aLength; ++i) { |
| + if (aString[i] != bString[i]) |
| + return false; |
| + } |
| + return true; |
| +} |
| + |
| } // namespace |
| // static |
| @@ -507,6 +534,12 @@ void NavigationHandleImpl::WillStartRequest( |
| state_ = WILL_SEND_REQUEST; |
| complete_callback_ = callback; |
| + if (IsSelfReferentialURL()) { |
| + state_ = CANCELING; |
| + RunCompleteCallback(NavigationThrottle::CANCEL); |
| + return; |
| + } |
| + |
| RegisterNavigationThrottles(); |
| if (IsBrowserSideNavigationEnabled()) |
| @@ -549,6 +582,12 @@ void NavigationHandleImpl::WillRedirectRequest( |
| state_ = WILL_REDIRECT_REQUEST; |
| complete_callback_ = callback; |
| + if (IsSelfReferentialURL()) { |
| + state_ = CANCELING; |
| + RunCompleteCallback(NavigationThrottle::CANCEL); |
| + return; |
| + } |
| + |
| // Notify each throttle of the request. |
| NavigationThrottle::ThrottleCheckResult result = CheckWillRedirectRequest(); |
| @@ -885,4 +924,29 @@ void NavigationHandleImpl::RegisterNavigationThrottles() { |
| std::make_move_iterator(throttles_to_register.end())); |
| } |
| +bool NavigationHandleImpl::IsSelfReferentialURL() { |
| + // about: URLs should be exempted since they are reserved for other purposes |
| + // and cannot be the source of infinite recursion. See |
| + // https://crbug.com/341858 . |
| + if (url_.SchemeIs("about")) |
| + return false; |
| + |
| + // Browser-triggered navigations should be exempted. |
| + if (!is_renderer_initiated_) |
| + return false; |
| + |
| + // We allow one level of self-reference because some sites depend on that, |
| + // but we don't allow more than one. |
| + bool found_self_reference = false; |
| + for (const FrameTreeNode* node = frame_tree_node_->parent(); node; |
| + node = node->parent()) { |
| + if (EqualIgnoringFragmentIdentifier(node->current_url(), url_)) { |
| + if (found_self_reference) |
| + return true; |
| + found_self_reference = true; |
| + } |
| + } |
| + return false; |
| +} |
| + |
| } // namespace content |