OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/page_load_metrics/page_load_metrics_util.h" | 5 #include "chrome/browser/page_load_metrics/page_load_metrics_util.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "chrome/common/page_load_metrics/page_load_timing.h" | 9 #include "chrome/common/page_load_metrics/page_load_timing.h" |
10 | 10 |
(...skipping 23 matching lines...) Expand all Loading... |
34 return ABORT_STOP; | 34 return ABORT_STOP; |
35 case END_CLOSE: | 35 case END_CLOSE: |
36 return ABORT_CLOSE; | 36 return ABORT_CLOSE; |
37 case END_OTHER: | 37 case END_OTHER: |
38 return ABORT_OTHER; | 38 return ABORT_OTHER; |
39 default: | 39 default: |
40 return ABORT_NONE; | 40 return ABORT_NONE; |
41 } | 41 } |
42 } | 42 } |
43 | 43 |
| 44 // Common helper for QueryContainsComponent and QueryContainsComponentPrefix. |
| 45 bool QueryContainsComponentHelper(const base::StringPiece query, |
| 46 const base::StringPiece component, |
| 47 bool component_is_prefix) { |
| 48 if (query.empty() || component.empty() || |
| 49 component.length() > query.length()) { |
| 50 return false; |
| 51 } |
| 52 |
| 53 // Verify that the provided query string does not include the query or |
| 54 // fragment start character, as the logic below depends on this character not |
| 55 // being included. |
| 56 DCHECK(query[0] != '?' && query[0] != '#'); |
| 57 |
| 58 // We shouldn't try to find matches beyond the point where there aren't enough |
| 59 // characters left in query to fully match the component. |
| 60 const size_t last_search_start = query.length() - component.length(); |
| 61 |
| 62 // We need to search for matches in a loop, rather than stopping at the first |
| 63 // match, because we may initially match a substring that isn't a full query |
| 64 // string component. Consider, for instance, the query string 'ab=cd&b=c'. If |
| 65 // we search for component 'b=c', the first substring match will be characters |
| 66 // 1-3 (zero-based) in the query string. However, this isn't a full component |
| 67 // (the full component is ab=cd) so the match will fail. Thus, we must |
| 68 // continue our search to find the second substring match, which in the |
| 69 // example is at characters 6-8 (the end of the query string) and is a |
| 70 // successful component match. |
| 71 for (size_t start_offset = 0; start_offset <= last_search_start; |
| 72 start_offset += component.length()) { |
| 73 start_offset = query.find(component, start_offset); |
| 74 if (start_offset == std::string::npos) { |
| 75 // We searched to end of string and did not find a match. |
| 76 return false; |
| 77 } |
| 78 // Verify that the character prior to the component is valid (either we're |
| 79 // at the beginning of the query string, or are preceded by an ampersand). |
| 80 if (start_offset != 0 && query[start_offset - 1] != '&') { |
| 81 continue; |
| 82 } |
| 83 if (!component_is_prefix) { |
| 84 // Verify that the character after the component substring is valid |
| 85 // (either we're at the end of the query string, or are followed by an |
| 86 // ampersand). |
| 87 const size_t after_offset = start_offset + component.length(); |
| 88 if (after_offset < query.length() && query[after_offset] != '&') { |
| 89 continue; |
| 90 } |
| 91 } |
| 92 return true; |
| 93 } |
| 94 return false; |
| 95 } |
| 96 |
44 } // namespace | 97 } // namespace |
45 | 98 |
46 bool WasStartedInForegroundOptionalEventInForeground( | 99 bool WasStartedInForegroundOptionalEventInForeground( |
47 const base::Optional<base::TimeDelta>& event, | 100 const base::Optional<base::TimeDelta>& event, |
48 const PageLoadExtraInfo& info) { | 101 const PageLoadExtraInfo& info) { |
49 return info.started_in_foreground && event && | 102 return info.started_in_foreground && event && |
50 (!info.first_background_time || | 103 (!info.first_background_time || |
51 event.value() <= info.first_background_time.value()); | 104 event.value() <= info.first_background_time.value()); |
52 } | 105 } |
53 | 106 |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
103 bool DidObserveLoadingBehaviorInAnyFrame( | 156 bool DidObserveLoadingBehaviorInAnyFrame( |
104 const page_load_metrics::PageLoadExtraInfo& info, | 157 const page_load_metrics::PageLoadExtraInfo& info, |
105 blink::WebLoadingBehaviorFlag behavior) { | 158 blink::WebLoadingBehaviorFlag behavior) { |
106 const int all_frame_loading_behavior_flags = | 159 const int all_frame_loading_behavior_flags = |
107 info.main_frame_metadata.behavior_flags | | 160 info.main_frame_metadata.behavior_flags | |
108 info.subframe_metadata.behavior_flags; | 161 info.subframe_metadata.behavior_flags; |
109 | 162 |
110 return (all_frame_loading_behavior_flags & behavior) != 0; | 163 return (all_frame_loading_behavior_flags & behavior) != 0; |
111 } | 164 } |
112 | 165 |
| 166 bool IsGoogleSearchHostname(const GURL& url) { |
| 167 base::Optional<std::string> result = |
| 168 page_load_metrics::GetGoogleHostnamePrefix(url); |
| 169 return result && result.value() == "www"; |
| 170 } |
| 171 |
| 172 bool IsGoogleSearchResultUrl(const GURL& url) { |
| 173 // NOTE: we do not require 'q=' in the query, as AJAXy search may instead |
| 174 // store the query in the URL fragment. |
| 175 if (!IsGoogleSearchHostname(url)) { |
| 176 return false; |
| 177 } |
| 178 |
| 179 if (!QueryContainsComponentPrefix(url.query_piece(), "q=") && |
| 180 !QueryContainsComponentPrefix(url.ref_piece(), "q=")) { |
| 181 return false; |
| 182 } |
| 183 |
| 184 const base::StringPiece path = url.path_piece(); |
| 185 return path == "/search" || path == "/webhp" || path == "/custom" || |
| 186 path == "/"; |
| 187 } |
| 188 |
| 189 bool IsGoogleSearchRedirectorUrl(const GURL& url) { |
| 190 if (!IsGoogleSearchHostname(url)) |
| 191 return false; |
| 192 |
| 193 // The primary search redirector. Google search result redirects are |
| 194 // differentiated from other general google redirects by 'source=web' in the |
| 195 // query string. |
| 196 if (url.path_piece() == "/url" && url.has_query() && |
| 197 QueryContainsComponent(url.query_piece(), "source=web")) { |
| 198 return true; |
| 199 } |
| 200 |
| 201 // Intent-based navigations from search are redirected through a second |
| 202 // redirector, which receives its redirect URL in the fragment/hash/ref |
| 203 // portion of the URL (the portion after '#'). We don't check for the presence |
| 204 // of certain params in the ref since this redirector is only used for |
| 205 // redirects from search. |
| 206 return url.path_piece() == "/searchurl/r.html" && url.has_ref(); |
| 207 } |
| 208 |
| 209 bool QueryContainsComponent(const base::StringPiece query, |
| 210 const base::StringPiece component) { |
| 211 return QueryContainsComponentHelper(query, component, false); |
| 212 } |
| 213 |
| 214 bool QueryContainsComponentPrefix(const base::StringPiece query, |
| 215 const base::StringPiece component) { |
| 216 return QueryContainsComponentHelper(query, component, true); |
| 217 } |
| 218 |
113 } // namespace page_load_metrics | 219 } // namespace page_load_metrics |
OLD | NEW |