| 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/android/contextualsearch/contextual_search_delegate.h" | 5 #include "chrome/browser/android/contextualsearch/contextual_search_delegate.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/base64.h" | 9 #include "base/base64.h" |
| 10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
| (...skipping 23 matching lines...) Expand all Loading... |
| 34 const char kContextualSearchSurroundingSizeParamName[] = "surrounding_size"; | 34 const char kContextualSearchSurroundingSizeParamName[] = "surrounding_size"; |
| 35 const char kContextualSearchIcingSurroundingSizeParamName[] = | 35 const char kContextualSearchIcingSurroundingSizeParamName[] = |
| 36 "icing_surrounding_size"; | 36 "icing_surrounding_size"; |
| 37 const char kContextualSearchResolverURLParamName[] = "resolver_url"; | 37 const char kContextualSearchResolverURLParamName[] = "resolver_url"; |
| 38 const char kContextualSearchDoNotSendURLParamName[] = "do_not_send_url"; | 38 const char kContextualSearchDoNotSendURLParamName[] = "do_not_send_url"; |
| 39 const char kContextualSearchResponseDisplayTextParam[] = "display_text"; | 39 const char kContextualSearchResponseDisplayTextParam[] = "display_text"; |
| 40 const char kContextualSearchResponseSelectedTextParam[] = "selected_text"; | 40 const char kContextualSearchResponseSelectedTextParam[] = "selected_text"; |
| 41 const char kContextualSearchResponseSearchTermParam[] = "search_term"; | 41 const char kContextualSearchResponseSearchTermParam[] = "search_term"; |
| 42 const char kContextualSearchResponseResolvedTermParam[] = "resolved_term"; | 42 const char kContextualSearchResponseResolvedTermParam[] = "resolved_term"; |
| 43 const char kContextualSearchPreventPreload[] = "prevent_preload"; | 43 const char kContextualSearchPreventPreload[] = "prevent_preload"; |
| 44 const char kContextualSearchMentions[] = "mentions"; |
| 44 const char kContextualSearchServerEndpoint[] = "_/contextualsearch?"; | 45 const char kContextualSearchServerEndpoint[] = "_/contextualsearch?"; |
| 45 const int kContextualSearchRequestVersion = 2; | 46 const int kContextualSearchRequestVersion = 2; |
| 46 const char kContextualSearchResolverUrl[] = | 47 const char kContextualSearchResolverUrl[] = |
| 47 "contextual-search-resolver-url"; | 48 "contextual-search-resolver-url"; |
| 48 // The default size of the content surrounding the selection to gather, allowing | 49 // The default size of the content surrounding the selection to gather, allowing |
| 49 // room for other parameters. | 50 // room for other parameters. |
| 50 const int kContextualSearchDefaultContentSize = 1536; | 51 const int kContextualSearchDefaultContentSize = 1536; |
| 51 const int kContextualSearchDefaultIcingSurroundingSize = 400; | 52 const int kContextualSearchDefaultIcingSurroundingSize = 400; |
| 53 const int kContextualSearchMaxSelection = 100; |
| 52 // The maximum length of a URL to build. | 54 // The maximum length of a URL to build. |
| 53 const int kMaxURLSize = 2048; | 55 const int kMaxURLSize = 2048; |
| 54 const char kXssiEscape[] = ")]}'\n"; | 56 const char kXssiEscape[] = ")]}'\n"; |
| 55 const char kDiscourseContextHeaderPrefix[] = "X-Additional-Discourse-Context: "; | 57 const char kDiscourseContextHeaderPrefix[] = "X-Additional-Discourse-Context: "; |
| 56 const char kDoPreventPreloadValue[] = "1"; | 58 const char kDoPreventPreloadValue[] = "1"; |
| 57 | 59 |
| 58 // The number of characters that should be shown on each side of the selected | 60 // The number of characters that should be shown on each side of the selected |
| 59 // expression. | 61 // expression. |
| 60 const int kSurroundingSizeForUI = 30; | 62 const int kSurroundingSizeForUI = 30; |
| 61 | 63 |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 135 } | 137 } |
| 136 | 138 |
| 137 void ContextualSearchDelegate::OnURLFetchComplete( | 139 void ContextualSearchDelegate::OnURLFetchComplete( |
| 138 const net::URLFetcher* source) { | 140 const net::URLFetcher* source) { |
| 139 DCHECK(source == search_term_fetcher_.get()); | 141 DCHECK(source == search_term_fetcher_.get()); |
| 140 int response_code = source->GetResponseCode(); | 142 int response_code = source->GetResponseCode(); |
| 141 std::string search_term; | 143 std::string search_term; |
| 142 std::string display_text; | 144 std::string display_text; |
| 143 std::string alternate_term; | 145 std::string alternate_term; |
| 144 std::string prevent_preload; | 146 std::string prevent_preload; |
| 147 int mention_start = 0; |
| 148 int mention_end = 0; |
| 149 int start_adjust = 0; |
| 150 int end_adjust = 0; |
| 145 | 151 |
| 146 if (source->GetStatus().is_success() && response_code == 200) { | 152 if (source->GetStatus().is_success() && response_code == 200) { |
| 147 std::string response; | 153 std::string response; |
| 148 bool has_string_response = source->GetResponseAsString(&response); | 154 bool has_string_response = source->GetResponseAsString(&response); |
| 149 DCHECK(has_string_response); | 155 DCHECK(has_string_response); |
| 150 if (has_string_response) { | 156 if (has_string_response) { |
| 151 DecodeSearchTermsFromJsonResponse(response, &search_term, &display_text, | 157 DecodeSearchTermsFromJsonResponse(response, &search_term, &display_text, |
| 152 &alternate_term, &prevent_preload); | 158 &alternate_term, &prevent_preload, |
| 159 &mention_start, &mention_end); |
| 160 if (mention_start != 0 || mention_end != 0) { |
| 161 // Sanity check that our selection is non-zero and it is less than |
| 162 // 100 characters as that would make contextual search bar hide. |
| 163 // We also check that there is at least one character overlap between |
| 164 // the new and old selection. |
| 165 if (mention_start >= mention_end |
| 166 || (mention_end - mention_start) > kContextualSearchMaxSelection |
| 167 || mention_end <= context_->start_offset |
| 168 || mention_start >= context_->end_offset) { |
| 169 start_adjust = 0; |
| 170 end_adjust = 0; |
| 171 } else { |
| 172 start_adjust = mention_start - context_->start_offset; |
| 173 end_adjust = mention_end - context_->end_offset; |
| 174 } |
| 175 } |
| 153 } | 176 } |
| 154 } | 177 } |
| 155 bool is_invalid = response_code == net::URLFetcher::RESPONSE_CODE_INVALID; | 178 bool is_invalid = response_code == net::URLFetcher::RESPONSE_CODE_INVALID; |
| 156 search_term_callback_.Run( | 179 search_term_callback_.Run( |
| 157 is_invalid, response_code, search_term, display_text, alternate_term, | 180 is_invalid, response_code, search_term, display_text, alternate_term, |
| 158 prevent_preload == kDoPreventPreloadValue); | 181 prevent_preload == kDoPreventPreloadValue, start_adjust, end_adjust); |
| 159 | 182 |
| 160 // The ContextualSearchContext is consumed once the request has completed. | 183 // The ContextualSearchContext is consumed once the request has completed. |
| 161 context_.reset(); | 184 context_.reset(); |
| 162 } | 185 } |
| 163 | 186 |
| 164 // TODO(jeremycho): Remove selected_text and base_page_url CGI parameters. | 187 // TODO(jeremycho): Remove selected_text and base_page_url CGI parameters. |
| 165 GURL ContextualSearchDelegate::BuildRequestUrl() { | 188 GURL ContextualSearchDelegate::BuildRequestUrl() { |
| 166 // TODO(jeremycho): Confirm this is the right way to handle TemplateURL fails. | 189 // TODO(jeremycho): Confirm this is the right way to handle TemplateURL fails. |
| 167 if (!template_url_service_ || | 190 if (!template_url_service_ || |
| 168 !template_url_service_->GetDefaultSearchProvider()) { | 191 !template_url_service_->GetDefaultSearchProvider()) { |
| (...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 392 return true; | 415 return true; |
| 393 } | 416 } |
| 394 | 417 |
| 395 // Decodes the given response from the search term resolution request and sets | 418 // Decodes the given response from the search term resolution request and sets |
| 396 // the value of the given parameters. | 419 // the value of the given parameters. |
| 397 void ContextualSearchDelegate::DecodeSearchTermsFromJsonResponse( | 420 void ContextualSearchDelegate::DecodeSearchTermsFromJsonResponse( |
| 398 const std::string& response, | 421 const std::string& response, |
| 399 std::string* search_term, | 422 std::string* search_term, |
| 400 std::string* display_text, | 423 std::string* display_text, |
| 401 std::string* alternate_term, | 424 std::string* alternate_term, |
| 402 std::string* prevent_preload) { | 425 std::string* prevent_preload, |
| 426 int* mention_start, |
| 427 int* mention_end) { |
| 403 bool contains_xssi_escape = response.find(kXssiEscape) == 0; | 428 bool contains_xssi_escape = response.find(kXssiEscape) == 0; |
| 404 const std::string& proper_json = | 429 const std::string& proper_json = |
| 405 contains_xssi_escape ? response.substr(strlen(kXssiEscape)) : response; | 430 contains_xssi_escape ? response.substr(strlen(kXssiEscape)) : response; |
| 406 JSONStringValueDeserializer deserializer(proper_json); | 431 JSONStringValueDeserializer deserializer(proper_json); |
| 407 scoped_ptr<base::Value> root(deserializer.Deserialize(NULL, NULL)); | 432 scoped_ptr<base::Value> root(deserializer.Deserialize(NULL, NULL)); |
| 408 | 433 |
| 409 if (root.get() != NULL && root->IsType(base::Value::TYPE_DICTIONARY)) { | 434 if (root.get() != NULL && root->IsType(base::Value::TYPE_DICTIONARY)) { |
| 410 base::DictionaryValue* dict = | 435 base::DictionaryValue* dict = |
| 411 static_cast<base::DictionaryValue*>(root.get()); | 436 static_cast<base::DictionaryValue*>(root.get()); |
| 412 dict->GetString(kContextualSearchPreventPreload, prevent_preload); | 437 dict->GetString(kContextualSearchPreventPreload, prevent_preload); |
| 413 dict->GetString(kContextualSearchResponseSearchTermParam, search_term); | 438 dict->GetString(kContextualSearchResponseSearchTermParam, search_term); |
| 414 // For the display_text, if not present fall back to the "search_term". | 439 // For the display_text, if not present fall back to the "search_term". |
| 415 if (!dict->GetString(kContextualSearchResponseDisplayTextParam, | 440 if (!dict->GetString(kContextualSearchResponseDisplayTextParam, |
| 416 display_text)) { | 441 display_text)) { |
| 417 *display_text = *search_term; | 442 *display_text = *search_term; |
| 418 } | 443 } |
| 444 // Extract mentions for selection expansion. |
| 445 base::ListValue* mentions_list; |
| 446 dict->GetList(kContextualSearchMentions, &mentions_list); |
| 447 if (mentions_list != NULL && mentions_list->GetSize() >= 2) |
| 448 ExtractMentionsStartEnd(*mentions_list, mention_start, mention_end); |
| 419 // If either the selected text or the resolved term is not the search term, | 449 // If either the selected text or the resolved term is not the search term, |
| 420 // use it as the alternate term. | 450 // use it as the alternate term. |
| 421 std::string selected_text; | 451 std::string selected_text; |
| 422 dict->GetString(kContextualSearchResponseSelectedTextParam, &selected_text); | 452 dict->GetString(kContextualSearchResponseSelectedTextParam, &selected_text); |
| 423 if (selected_text != *search_term) { | 453 if (selected_text != *search_term) { |
| 424 *alternate_term = selected_text; | 454 *alternate_term = selected_text; |
| 425 } else { | 455 } else { |
| 426 std::string resolved_term; | 456 std::string resolved_term; |
| 427 dict->GetString(kContextualSearchResponseResolvedTermParam, | 457 dict->GetString(kContextualSearchResponseResolvedTermParam, |
| 428 &resolved_term); | 458 &resolved_term); |
| 429 if (resolved_term != *search_term) { | 459 if (resolved_term != *search_term) { |
| 430 *alternate_term = resolved_term; | 460 *alternate_term = resolved_term; |
| 431 } | 461 } |
| 432 } | 462 } |
| 433 } | 463 } |
| 434 } | 464 } |
| 435 | 465 |
| 436 // Returns the size of the surroundings to be sent to the server for search term | 466 // Returns the size of the surroundings to be sent to the server for search term |
| 437 // resolution. | 467 // resolution. |
| 438 int ContextualSearchDelegate::GetSearchTermSurroundingSize() { | 468 int ContextualSearchDelegate::GetSearchTermSurroundingSize() { |
| 439 const std::string param_value = variations::GetVariationParamValue( | 469 const std::string param_value = variations::GetVariationParamValue( |
| 440 kContextualSearchFieldTrialName, | 470 kContextualSearchFieldTrialName, |
| 441 kContextualSearchSurroundingSizeParamName); | 471 kContextualSearchSurroundingSizeParamName); |
| 442 int param_length; | 472 int param_length; |
| 443 if (!param_value.empty() && base::StringToInt(param_value, ¶m_length)) | 473 if (!param_value.empty() && base::StringToInt(param_value, ¶m_length)) |
| 444 return param_length; | 474 return param_length; |
| 445 return kContextualSearchDefaultContentSize; | 475 return kContextualSearchDefaultContentSize; |
| 446 } | 476 } |
| 447 | 477 |
| 478 // Extract the Start/End of the mentions in the surrounding text |
| 479 // for selection-expansion. |
| 480 void ContextualSearchDelegate::ExtractMentionsStartEnd( |
| 481 const base::ListValue& mentions_list, |
| 482 int* startResult, |
| 483 int* endResult) { |
| 484 int int_value; |
| 485 if (mentions_list.GetInteger(0, &int_value)) |
| 486 *startResult = std::max(0, int_value); |
| 487 if (mentions_list.GetInteger(1, &int_value)) |
| 488 *endResult = std::max(0, int_value); |
| 489 } |
| 490 |
| 448 // Returns the size of the surroundings to be sent to Icing. | 491 // Returns the size of the surroundings to be sent to Icing. |
| 449 int ContextualSearchDelegate::GetIcingSurroundingSize() { | 492 int ContextualSearchDelegate::GetIcingSurroundingSize() { |
| 450 std::string param_string = variations::GetVariationParamValue( | 493 std::string param_string = variations::GetVariationParamValue( |
| 451 kContextualSearchFieldTrialName, | 494 kContextualSearchFieldTrialName, |
| 452 kContextualSearchIcingSurroundingSizeParamName); | 495 kContextualSearchIcingSurroundingSizeParamName); |
| 453 if (base::CommandLine::ForCurrentProcess()->HasSwitch( | 496 if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 454 kContextualSearchIcingSurroundingSizeParamName)) { | 497 kContextualSearchIcingSurroundingSizeParamName)) { |
| 455 param_string = base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( | 498 param_string = base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
| 456 kContextualSearchIcingSurroundingSizeParamName); | 499 kContextualSearchIcingSurroundingSizeParamName); |
| 457 } | 500 } |
| (...skipping 23 matching lines...) Expand all Loading... |
| 481 end_offset -= trim; | 524 end_offset -= trim; |
| 482 } | 525 } |
| 483 if (result_text.length() > end_offset + padding_each_side_pinned) { | 526 if (result_text.length() > end_offset + padding_each_side_pinned) { |
| 484 // Trim the end. | 527 // Trim the end. |
| 485 result_text = result_text.substr(0, end_offset + padding_each_side_pinned); | 528 result_text = result_text.substr(0, end_offset + padding_each_side_pinned); |
| 486 } | 529 } |
| 487 *start = start_offset; | 530 *start = start_offset; |
| 488 *end = end_offset; | 531 *end = end_offset; |
| 489 return result_text; | 532 return result_text; |
| 490 } | 533 } |
| OLD | NEW |