| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/ui/search/search.h" | 5 #include "chrome/browser/ui/search/search.h" |
| 6 | 6 |
| 7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
| 8 #include "base/metrics/field_trial.h" | 8 #include "base/metrics/field_trial.h" |
| 9 #include "base/string_split.h" | 9 #include "base/string_split.h" |
| 10 #include "base/string_util.h" | |
| 11 #include "base/strings/string_number_conversions.h" | 10 #include "base/strings/string_number_conversions.h" |
| 11 #include "chrome/browser/instant/instant_service.h" |
| 12 #include "chrome/browser/instant/instant_service_factory.h" |
| 12 #include "chrome/browser/profiles/profile.h" | 13 #include "chrome/browser/profiles/profile.h" |
| 14 #include "chrome/browser/search_engines/template_url_service.h" |
| 15 #include "chrome/browser/search_engines/template_url_service_factory.h" |
| 13 #include "chrome/common/chrome_switches.h" | 16 #include "chrome/common/chrome_switches.h" |
| 14 #include "chrome/common/chrome_version_info.h" | 17 #include "chrome/common/url_constants.h" |
| 15 #include "content/public/browser/navigation_entry.h" | 18 #include "content/public/browser/navigation_entry.h" |
| 16 | 19 #include "content/public/browser/render_process_host.h" |
| 17 #if !defined(OS_ANDROID) | 20 #include "content/public/browser/web_contents.h" |
| 18 #include "chrome/browser/themes/theme_service.h" | |
| 19 #include "chrome/browser/themes/theme_service_factory.h" | |
| 20 #endif | |
| 21 | 21 |
| 22 namespace { | 22 namespace { |
| 23 | 23 |
| 24 // Configuration options for Embedded Search. | 24 // Configuration options for Embedded Search. |
| 25 // InstantExtended field trials are named in such a way that we can parse out | 25 // InstantExtended field trials are named in such a way that we can parse out |
| 26 // the experiment configuration from the trial's group name in order to give | 26 // the experiment configuration from the trial's group name in order to give |
| 27 // us maximum flexability in running experiments. | 27 // us maximum flexability in running experiments. |
| 28 // Field trials should be named things like "Group7 espv:2 themes:0". | 28 // Field trial groups should be named things like "Group7 espv:2 instant:1". |
| 29 // The first token is always GroupN for some integer N, followed by a | 29 // The first token is always GroupN for some integer N, followed by a |
| 30 // space-delimited list of key:value pairs which correspond to these flags: | 30 // space-delimited list of key:value pairs which correspond to these flags: |
| 31 const char kEnableOnThemesFlagName[] = "themes"; | |
| 32 const bool kEnableOnThemesDefault = false; | |
| 33 | |
| 34 const char kEmbeddedPageVersionFlagName[] = "espv"; | 31 const char kEmbeddedPageVersionFlagName[] = "espv"; |
| 35 const int kEmbeddedPageVersionDefault = 1; | 32 const int kEmbeddedPageVersionDefault = 1; |
| 36 | 33 |
| 37 const char kInstantExtendedActivationName[] = "instant"; | 34 const char kInstantExtendedActivationName[] = "instant"; |
| 38 const chrome::search::InstantExtendedDefault kInstantExtendedActivationDefault = | 35 const chrome::search::InstantExtendedDefault kInstantExtendedActivationDefault = |
| 39 chrome::search::INSTANT_USE_EXISTING; | 36 chrome::search::INSTANT_USE_EXISTING; |
| 40 | 37 |
| 41 // Constants for the field trial name and group prefix. | 38 // Constants for the field trial name and group prefix. |
| 42 const char kInstantExtendedFieldTrialName[] = "InstantExtended"; | 39 const char kInstantExtendedFieldTrialName[] = "InstantExtended"; |
| 43 const char kGroupNumberPrefix[] = "Group"; | 40 const char kGroupNumberPrefix[] = "Group"; |
| 44 | 41 |
| 45 // If the field trial's group name ends with this string its configuration will | 42 // If the field trial's group name ends with this string its configuration will |
| 46 // be ignored and Instant Extended will not be enabled by default. | 43 // be ignored and Instant Extended will not be enabled by default. |
| 47 const char kDisablingSuffix[] = "DISABLED"; | 44 const char kDisablingSuffix[] = "DISABLED"; |
| 48 | 45 |
| 46 chrome::search::InstantExtendedDefault InstantExtendedDefaultFromInt64( |
| 47 int64 default_value) { |
| 48 switch (default_value) { |
| 49 case 0: return chrome::search::INSTANT_DEFAULT_ON; |
| 50 case 1: return chrome::search::INSTANT_USE_EXISTING; |
| 51 case 2: return chrome::search::INSTANT_DEFAULT_OFF; |
| 52 default: return chrome::search::INSTANT_USE_EXISTING; |
| 53 } |
| 54 } |
| 55 |
| 56 TemplateURL* GetDefaultSearchProviderTemplateURL(Profile* profile) { |
| 57 TemplateURLService* template_url_service = |
| 58 TemplateURLServiceFactory::GetForProfile(profile); |
| 59 if (template_url_service) |
| 60 return template_url_service->GetDefaultSearchProvider(); |
| 61 return NULL; |
| 62 } |
| 63 |
| 64 GURL TemplateURLRefToGURL(const TemplateURLRef& ref) { |
| 65 return GURL( |
| 66 ref.ReplaceSearchTerms(TemplateURLRef::SearchTermsArgs(string16()))); |
| 67 } |
| 68 |
| 69 bool MatchesOriginAndPath(const GURL& my_url, const GURL& other_url) { |
| 70 return my_url.host() == other_url.host() && |
| 71 my_url.port() == other_url.port() && |
| 72 my_url.path() == other_url.path() && |
| 73 (my_url.scheme() == other_url.scheme() || |
| 74 (my_url.SchemeIs(chrome::kHttpsScheme) && |
| 75 other_url.SchemeIs(chrome::kHttpScheme))); |
| 76 } |
| 77 |
| 78 bool IsCommandLineInstantURL(const GURL& url) { |
| 79 const CommandLine* cl = CommandLine::ForCurrentProcess(); |
| 80 GURL instant_url(cl->GetSwitchValueASCII(switches::kInstantURL)); |
| 81 return instant_url.is_valid() && MatchesOriginAndPath(url, instant_url); |
| 82 } |
| 83 |
| 84 // Coerces the commandline Instant URL to look like a template URL, so that we |
| 85 // can extract search terms from it. |
| 86 GURL CoerceCommandLineURLToTemplateURL(const GURL& instant_url, |
| 87 const TemplateURLRef& ref) { |
| 88 GURL search_url = TemplateURLRefToGURL(ref); |
| 89 |
| 90 GURL::Replacements replacements; |
| 91 replacements.SetSchemeStr(chrome::kHttpsScheme); |
| 92 replacements.SetHostStr(search_url.host()); |
| 93 replacements.SetPortStr(search_url.port()); |
| 94 replacements.SetPathStr(search_url.path()); |
| 95 |
| 96 return instant_url.ReplaceComponents(replacements); |
| 97 } |
| 98 |
| 99 bool MatchesAnySearchURL(const GURL& url, TemplateURL* template_url) { |
| 100 GURL search_url = TemplateURLRefToGURL(template_url->url_ref()); |
| 101 if (search_url.is_valid() && MatchesOriginAndPath(url, search_url)) |
| 102 return true; |
| 103 |
| 104 // "URLCount() - 1" because we already tested url_ref above. |
| 105 for (size_t i = 0; i < template_url->URLCount() - 1; ++i) { |
| 106 TemplateURLRef ref(template_url, i); |
| 107 search_url = TemplateURLRefToGURL(ref); |
| 108 if (search_url.is_valid() && MatchesOriginAndPath(url, search_url)) |
| 109 return true; |
| 110 } |
| 111 |
| 112 return false; |
| 113 } |
| 114 |
| 49 } // namespace | 115 } // namespace |
| 50 | 116 |
| 51 namespace chrome { | 117 namespace chrome { |
| 52 namespace search { | 118 namespace search { |
| 53 | 119 |
| 54 // static | |
| 55 const char kInstantExtendedSearchTermsKey[] = "search_terms"; | 120 const char kInstantExtendedSearchTermsKey[] = "search_terms"; |
| 56 | 121 |
| 57 InstantExtendedDefault InstantExtendedDefaultFromInt64(int64 default_value) { | 122 const char kLocalOmniboxPopupURL[] = |
| 58 switch (default_value) { | 123 "chrome://local-omnibox-popup/local-omnibox-popup.html"; |
| 59 case 0: return INSTANT_FORCE_ON; | |
| 60 case 1: return INSTANT_USE_EXISTING; | |
| 61 case 2: return INSTANT_FORCE_OFF; | |
| 62 default: return INSTANT_USE_EXISTING; | |
| 63 } | |
| 64 } | |
| 65 | 124 |
| 66 InstantExtendedDefault GetInstantExtendedDefaultSetting() { | 125 InstantExtendedDefault GetInstantExtendedDefaultSetting() { |
| 67 InstantExtendedDefault default_setting = INSTANT_USE_EXISTING; | |
| 68 | |
| 69 FieldTrialFlags flags; | 126 FieldTrialFlags flags; |
| 70 if (GetFieldTrialInfo( | 127 if (GetFieldTrialInfo( |
| 71 base::FieldTrialList::FindFullName(kInstantExtendedFieldTrialName), | 128 base::FieldTrialList::FindFullName(kInstantExtendedFieldTrialName), |
| 72 &flags, NULL)) { | 129 &flags, NULL)) { |
| 73 uint64 trial_default = GetUInt64ValueForFlagWithDefault( | 130 uint64 trial_default = GetUInt64ValueForFlagWithDefault( |
| 74 kInstantExtendedActivationName, | 131 kInstantExtendedActivationName, |
| 75 kInstantExtendedActivationDefault, | 132 kInstantExtendedActivationDefault, |
| 76 flags); | 133 flags); |
| 77 default_setting = InstantExtendedDefaultFromInt64(trial_default); | 134 return InstantExtendedDefaultFromInt64(trial_default); |
| 78 } | 135 } |
| 79 | 136 |
| 80 return default_setting; | 137 return INSTANT_USE_EXISTING; |
| 81 } | 138 } |
| 82 | 139 |
| 83 // Check whether or not the Extended API should be used on the given profile. | 140 bool IsInstantExtendedAPIEnabled(const Profile* profile) { |
| 84 bool IsInstantExtendedAPIEnabled(Profile* profile) { | |
| 85 return EmbeddedSearchPageVersion(profile) != 0; | 141 return EmbeddedSearchPageVersion(profile) != 0; |
| 86 } | 142 } |
| 87 | 143 |
| 88 // Determine what embedded search page version to request from the user's | 144 // Determine what embedded search page version to request from the user's |
| 89 // default search provider. If 0, the embedded search UI should not be enabled. | 145 // default search provider. If 0, the embedded search UI should not be enabled. |
| 90 // Note that the profile object here isn't const because we need to determine | 146 uint64 EmbeddedSearchPageVersion(const Profile* profile) { |
| 91 // whether or not the user has a theme installed as part of this check, and | |
| 92 // that logic requires a non-const profile for whatever reason. | |
| 93 uint64 EmbeddedSearchPageVersion(Profile* profile) { | |
| 94 // Incognito windows do not currently use the embedded search API. | |
| 95 if (!profile || profile->IsOffTheRecord()) | 147 if (!profile || profile->IsOffTheRecord()) |
| 96 return 0; | 148 return 0; |
| 97 | 149 |
| 98 // Check Finch field trials. | |
| 99 FieldTrialFlags flags; | 150 FieldTrialFlags flags; |
| 100 if (GetFieldTrialInfo( | 151 if (GetFieldTrialInfo( |
| 101 base::FieldTrialList::FindFullName(kInstantExtendedFieldTrialName), | 152 base::FieldTrialList::FindFullName(kInstantExtendedFieldTrialName), |
| 102 &flags, NULL)) { | 153 &flags, NULL)) { |
| 103 uint64 espv = GetUInt64ValueForFlagWithDefault( | 154 return GetUInt64ValueForFlagWithDefault(kEmbeddedPageVersionFlagName, |
| 104 kEmbeddedPageVersionFlagName, | 155 kEmbeddedPageVersionDefault, |
| 105 kEmbeddedPageVersionDefault, | 156 flags); |
| 106 flags); | 157 } |
| 107 | 158 |
| 108 // Check for themes. | 159 const CommandLine* cl = CommandLine::ForCurrentProcess(); |
| 109 bool has_theme = false; | 160 if (cl->HasSwitch(switches::kEnableInstantExtendedAPI)) { |
| 110 #if !defined(OS_ANDROID) | |
| 111 has_theme = | |
| 112 !ThemeServiceFactory::GetForProfile(profile)->UsingDefaultTheme(); | |
| 113 #endif | |
| 114 | |
| 115 bool enable_for_themes = | |
| 116 GetBoolValueForFlagWithDefault(kEnableOnThemesFlagName, | |
| 117 kEnableOnThemesDefault, | |
| 118 flags); | |
| 119 if (!has_theme || enable_for_themes) | |
| 120 return espv; | |
| 121 } | |
| 122 | |
| 123 if (CommandLine::ForCurrentProcess()->HasSwitch( | |
| 124 switches::kEnableInstantExtendedAPI)) { | |
| 125 // The user has manually flipped the about:flags switch - give the default | 161 // The user has manually flipped the about:flags switch - give the default |
| 126 // UI version. | 162 // UI version. |
| 127 return kEmbeddedPageVersionDefault; | 163 return kEmbeddedPageVersionDefault; |
| 128 } | 164 } |
| 165 |
| 129 return 0; | 166 return 0; |
| 130 } | 167 } |
| 131 | 168 |
| 132 void EnableInstantExtendedAPIForTesting() { | 169 bool IsQueryExtractionEnabled(const Profile* profile) { |
| 133 CommandLine::ForCurrentProcess()->AppendSwitch( | |
| 134 switches::kEnableInstantExtendedAPI); | |
| 135 } | |
| 136 | |
| 137 bool IsQueryExtractionEnabled(Profile* profile) { | |
| 138 #if defined(OS_IOS) | 170 #if defined(OS_IOS) |
| 139 return CommandLine::ForCurrentProcess()->HasSwitch( | 171 const CommandLine* cl = CommandLine::ForCurrentProcess(); |
| 140 switches::kEnableQueryExtraction); | 172 return cl->HasSwitch(switches::kEnableQueryExtraction); |
| 141 #else | |
| 142 if (!profile || profile->IsOffTheRecord()) | |
| 143 return false; | |
| 144 | |
| 145 // On desktop, query extraction is controlled by the instant-extended-api | |
| 146 // flag. | |
| 147 bool enabled = IsInstantExtendedAPIEnabled(profile); | |
| 148 | |
| 149 // Running with --enable-query-extraction but not | |
| 150 // --enable-instant-extended-api is an error. | |
| 151 DCHECK(!(CommandLine::ForCurrentProcess()->HasSwitch( | |
| 152 switches::kEnableQueryExtraction) && | |
| 153 !enabled)); | |
| 154 return enabled; | |
| 155 #endif | |
| 156 } | |
| 157 | |
| 158 void EnableQueryExtractionForTesting() { | |
| 159 #if defined(OS_IOS) | |
| 160 CommandLine::ForCurrentProcess()->AppendSwitch( | |
| 161 switches::kEnableQueryExtraction); | |
| 162 #else | 173 #else |
| 163 // On desktop, query extraction is controlled by the instant-extended-api | 174 // On desktop, query extraction is controlled by the instant-extended-api |
| 164 // flag. | 175 // flag. |
| 165 CommandLine::ForCurrentProcess()->AppendSwitch( | 176 return IsInstantExtendedAPIEnabled(profile); |
| 166 switches::kEnableInstantExtendedAPI); | |
| 167 #endif | 177 #endif |
| 168 } | 178 } |
| 169 | 179 |
| 170 string16 GetSearchTermsFromNavigationEntry( | 180 string16 GetSearchTermsFromNavigationEntry( |
| 171 const content::NavigationEntry* entry) { | 181 const content::NavigationEntry* entry) { |
| 172 string16 search_terms; | 182 string16 search_terms; |
| 173 entry->GetExtraData(kInstantExtendedSearchTermsKey, &search_terms); | 183 if (entry) |
| 184 entry->GetExtraData(kInstantExtendedSearchTermsKey, &search_terms); |
| 174 return search_terms; | 185 return search_terms; |
| 175 } | 186 } |
| 176 | 187 |
| 177 bool IsForcedInstantURL(const GURL& url) { | 188 string16 GetSearchTerms(const content::WebContents* contents) { |
| 178 CommandLine* command_line = CommandLine::ForCurrentProcess(); | 189 if (!contents) |
| 179 if (!command_line->HasSwitch(switches::kInstantURL)) | 190 return string16(); |
| 180 return false; | 191 |
| 181 | 192 Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext()); |
| 182 GURL instant_url(command_line->GetSwitchValueASCII(switches::kInstantURL)); | 193 if (!IsQueryExtractionEnabled(profile)) |
| 183 return url.scheme() == instant_url.scheme() && | 194 return string16(); |
| 184 url.host() == instant_url.host() && | 195 |
| 185 url.port() == instant_url.port() && | 196 // For security reasons, don't extract search terms if the page is not being |
| 186 url.path() == instant_url.path(); | 197 // rendered in the privileged Instant renderer process. This is to protect |
| 198 // against a malicious page somehow scripting the search results page and |
| 199 // faking search terms in the URL. Random pages can't get into the Instant |
| 200 // renderer and scripting doesn't work cross-process, so if the page is in |
| 201 // the Instant process, we know it isn't being exploited. |
| 202 const content::RenderProcessHost* process_host = |
| 203 contents->GetRenderProcessHost(); |
| 204 if (!process_host) |
| 205 return string16(); |
| 206 |
| 207 const InstantService* instant_service = |
| 208 InstantServiceFactory::GetForProfile(profile); |
| 209 if (!instant_service) |
| 210 return string16(); |
| 211 |
| 212 if (!instant_service->IsInstantProcess(process_host->GetID())) |
| 213 return string16(); |
| 214 |
| 215 // Check to see if search terms have already been extracted. |
| 216 const content::NavigationEntry* entry = |
| 217 contents->GetController().GetVisibleEntry(); |
| 218 if (!entry) |
| 219 return string16(); |
| 220 |
| 221 string16 search_terms = GetSearchTermsFromNavigationEntry(entry); |
| 222 if (!search_terms.empty()) |
| 223 return search_terms; |
| 224 |
| 225 // Otherwise, extract from the URL. |
| 226 TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile); |
| 227 if (!template_url) |
| 228 return string16(); |
| 229 |
| 230 GURL url = entry->GetVirtualURL(); |
| 231 |
| 232 if (IsCommandLineInstantURL(url)) |
| 233 url = CoerceCommandLineURLToTemplateURL(url, template_url->url_ref()); |
| 234 |
| 235 if (url.SchemeIsSecure() && template_url->HasSearchTermsReplacementKey(url)) |
| 236 template_url->ExtractSearchTermsFromURL(url, &search_terms); |
| 237 |
| 238 return search_terms; |
| 239 } |
| 240 |
| 241 bool ShouldAssignURLToInstantRenderer(const GURL& url, Profile* profile) { |
| 242 TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile); |
| 243 if (!template_url) |
| 244 return false; |
| 245 |
| 246 GURL effective_url = url; |
| 247 |
| 248 if (IsCommandLineInstantURL(url)) { |
| 249 const TemplateURLRef& instant_url_ref = template_url->instant_url_ref(); |
| 250 effective_url = CoerceCommandLineURLToTemplateURL(url, instant_url_ref); |
| 251 } |
| 252 |
| 253 return ShouldAssignURLToInstantRendererImpl( |
| 254 effective_url, |
| 255 IsInstantExtendedAPIEnabled(profile), |
| 256 template_url); |
| 257 } |
| 258 |
| 259 void EnableInstantExtendedAPIForTesting() { |
| 260 CommandLine* cl = CommandLine::ForCurrentProcess(); |
| 261 cl->AppendSwitch(switches::kEnableInstantExtendedAPI); |
| 262 } |
| 263 |
| 264 void EnableQueryExtractionForTesting() { |
| 265 #if defined(OS_IOS) |
| 266 CommandLine* cl = CommandLine::ForCurrentProcess(); |
| 267 cl->AppendSwitch(switches::kEnableQueryExtraction); |
| 268 #else |
| 269 EnableInstantExtendedAPIForTesting(); |
| 270 #endif |
| 271 } |
| 272 |
| 273 bool ShouldAssignURLToInstantRendererImpl(const GURL& url, |
| 274 bool extended_api_enabled, |
| 275 TemplateURL* template_url) { |
| 276 if (!url.is_valid()) |
| 277 return false; |
| 278 |
| 279 if (url.SchemeIs(chrome::kChromeSearchScheme)) |
| 280 return true; |
| 281 |
| 282 if (extended_api_enabled && url == GURL(kLocalOmniboxPopupURL)) |
| 283 return true; |
| 284 |
| 285 if (extended_api_enabled && !url.SchemeIsSecure()) |
| 286 return false; |
| 287 |
| 288 if (extended_api_enabled && !template_url->HasSearchTermsReplacementKey(url)) |
| 289 return false; |
| 290 |
| 291 GURL instant_url = TemplateURLRefToGURL(template_url->instant_url_ref()); |
| 292 if (!instant_url.is_valid()) |
| 293 return false; |
| 294 |
| 295 if (MatchesOriginAndPath(url, instant_url)) |
| 296 return true; |
| 297 |
| 298 if (extended_api_enabled && MatchesAnySearchURL(url, template_url)) |
| 299 return true; |
| 300 |
| 301 return false; |
| 187 } | 302 } |
| 188 | 303 |
| 189 bool GetFieldTrialInfo(const std::string& group_name, | 304 bool GetFieldTrialInfo(const std::string& group_name, |
| 190 FieldTrialFlags* flags, | 305 FieldTrialFlags* flags, |
| 191 uint64* group_number) { | 306 uint64* group_number) { |
| 192 if (EndsWith(group_name, kDisablingSuffix, true) || | 307 if (EndsWith(group_name, kDisablingSuffix, true) || |
| 193 !StartsWithASCII(group_name, kGroupNumberPrefix, true)) { | 308 !StartsWithASCII(group_name, kGroupNumberPrefix, true)) |
| 194 return false; | 309 return false; |
| 195 } | |
| 196 | 310 |
| 197 // We have a valid trial that starts with "Group" and isn't disabled. | 311 // We have a valid trial that starts with "Group" and isn't disabled. |
| 198 // First extract the flags. | 312 // First extract the flags. |
| 199 std::string group_prefix(group_name); | 313 std::string group_prefix(group_name); |
| 200 | 314 |
| 201 size_t first_space = group_name.find(" "); | 315 size_t first_space = group_name.find(" "); |
| 202 if (first_space != std::string::npos) { | 316 if (first_space != std::string::npos) { |
| 203 // There is a flags section of the group name. Split that out and parse | 317 // There is a flags section of the group name. Split that out and parse it. |
| 204 // it. | |
| 205 group_prefix = group_name.substr(0, first_space); | 318 group_prefix = group_name.substr(0, first_space); |
| 206 if (!base::SplitStringIntoKeyValuePairs(group_name.substr(first_space), | 319 if (!base::SplitStringIntoKeyValuePairs(group_name.substr(first_space), |
| 207 ':', ' ', flags)) { | 320 ':', ' ', flags)) { |
| 208 // Failed to parse the flags section. Assume the whole group name is | 321 // Failed to parse the flags section. Assume the whole group name is |
| 209 // invalid. | 322 // invalid. |
| 210 return false; | 323 return false; |
| 211 } | 324 } |
| 212 } | 325 } |
| 213 | 326 |
| 214 // Now extract the group number, making sure we get a non-zero value. | 327 // Now extract the group number, making sure we get a non-zero value. |
| 215 uint64 temp_group_number = 0; | 328 uint64 temp_group_number = 0; |
| 216 if (!base::StringToUint64(group_prefix.substr(strlen(kGroupNumberPrefix)), | 329 std::string group_suffix = group_prefix.substr(strlen(kGroupNumberPrefix)); |
| 217 &temp_group_number) || | 330 if (!base::StringToUint64(group_suffix, &temp_group_number) || |
| 218 temp_group_number == 0) { | 331 temp_group_number == 0) |
| 219 return false; | 332 return false; |
| 220 } | |
| 221 | 333 |
| 222 if (group_number) | 334 if (group_number) |
| 223 *group_number = temp_group_number; | 335 *group_number = temp_group_number; |
| 224 | 336 |
| 225 return true; | 337 return true; |
| 226 } | 338 } |
| 227 | 339 |
| 228 // Given a FieldTrialFlags object, returns the string value of the provided | 340 // Given a FieldTrialFlags object, returns the string value of the provided |
| 229 // flag. | 341 // flag. |
| 230 std::string GetStringValueForFlagWithDefault( | 342 std::string GetStringValueForFlagWithDefault(const std::string& flag, |
| 231 const std::string& flag, | 343 const std::string& default_value, |
| 232 const std::string& default_value, | 344 const FieldTrialFlags& flags) { |
| 233 FieldTrialFlags& flags) { | |
| 234 FieldTrialFlags::const_iterator i; | 345 FieldTrialFlags::const_iterator i; |
| 235 for (i = flags.begin(); i != flags.end(); i++) { | 346 for (i = flags.begin(); i != flags.end(); i++) { |
| 236 if (i->first == flag) | 347 if (i->first == flag) |
| 237 return i->second; | 348 return i->second; |
| 238 } | 349 } |
| 239 return default_value; | 350 return default_value; |
| 240 } | 351 } |
| 241 | 352 |
| 242 // Given a FieldTrialFlags object, returns the uint64 value of the provided | 353 // Given a FieldTrialFlags object, returns the uint64 value of the provided |
| 243 // flag. | 354 // flag. |
| 244 uint64 GetUInt64ValueForFlagWithDefault( | 355 uint64 GetUInt64ValueForFlagWithDefault(const std::string& flag, |
| 245 const std::string& flag, uint64 default_value, FieldTrialFlags& flags) { | 356 uint64 default_value, |
| 357 const FieldTrialFlags& flags) { |
| 246 uint64 value; | 358 uint64 value; |
| 247 if (!base::StringToUint64(GetStringValueForFlagWithDefault(flag, "", flags), | 359 std::string str_value = GetStringValueForFlagWithDefault(flag, "", flags); |
| 248 &value)) | 360 if (base::StringToUint64(str_value, &value)) |
| 249 return default_value; | 361 return value; |
| 250 return value; | 362 return default_value; |
| 251 } | 363 } |
| 252 | 364 |
| 253 // Given a FieldTrialFlags object, returns the boolean value of the provided | 365 // Given a FieldTrialFlags object, returns the boolean value of the provided |
| 254 // flag. | 366 // flag. |
| 255 bool GetBoolValueForFlagWithDefault( | 367 bool GetBoolValueForFlagWithDefault(const std::string& flag, |
| 256 const std::string& flag, bool default_value, FieldTrialFlags& flags) { | 368 bool default_value, |
| 369 const FieldTrialFlags& flags) { |
| 257 return !!GetUInt64ValueForFlagWithDefault(flag, default_value ? 1 : 0, flags); | 370 return !!GetUInt64ValueForFlagWithDefault(flag, default_value ? 1 : 0, flags); |
| 258 } | 371 } |
| 259 | 372 |
| 260 } // namespace search | 373 } // namespace search |
| 261 } // namespace chrome | 374 } // namespace chrome |
| OLD | NEW |