1 // Copyright 2013 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 5 #include "components/autofill/content/browser/autocheckout_manager.h" 6 7 #include "base/basictypes.h" 8 #include "base/bind.h" 9 #include "base/strings/utf_string_conversions.h" 10 #include "components/autofill/content/browser/autocheckout_request_manager.h" 11 #include "components/autofill/content/browser/autocheckout_statistic.h" 12 #include "components/autofill/content/browser/autocheckout_steps.h" 13 #include "components/autofill/core/browser/autofill_country.h" 14 #include "components/autofill/core/browser/autofill_field.h" 15 #include "components/autofill/core/browser/autofill_manager.h" 16 #include "components/autofill/core/browser/autofill_metrics.h" 17 #include "components/autofill/core/browser/autofill_profile.h" 18 #include "components/autofill/core/browser/autofill_type.h" 19 #include "components/autofill/core/browser/credit_card.h" 20 #include "components/autofill/core/browser/form_structure.h" 21 #include "components/autofill/core/common/autofill_messages.h" 22 #include "components/autofill/core/common/form_data.h" 23 #include "components/autofill/core/common/form_field_data.h" 24 #include "components/autofill/core/common/web_element_descriptor.h" 25 #include "content/public/browser/browser_context.h" 26 #include "content/public/browser/browser_thread.h" 27 #include "content/public/browser/render_view_host.h" 28 #include "content/public/browser/web_contents.h" 29 #include "net/cookies/cookie_options.h" 30 #include "net/cookies/cookie_store.h" 31 #include "net/url_request/url_request_context.h" 32 #include "net/url_request/url_request_context_getter.h" 33 #include "ui/gfx/rect.h" 34 #include "url/gurl.h" 35 36 using content::RenderViewHost; 37 using content::WebContents; 38 39 namespace autofill { 40 41 namespace { 42 43 const char kGoogleAccountsUrl[] = "https://accounts.google.com/"; 44 45 // Build FormFieldData based on the supplied |autocomplete_attribute|. Will 46 // fill rest of properties with default values. 47 FormFieldData BuildField(const std::string& autocomplete_attribute) { 48 FormFieldData field; 49 field.name = base::string16(); 50 field.value = base::string16(); 51 field.autocomplete_attribute = autocomplete_attribute; 52 field.form_control_type = "text"; 53 return field; 54 } 55 56 // Build Autocheckout specific form data to be consumed by 57 // AutofillDialogController to show the Autocheckout specific UI. 58 FormData BuildAutocheckoutFormData() { 59 FormData formdata; 60 formdata.fields.push_back(BuildField("email")); 61 formdata.fields.push_back(BuildField("cc-name")); 62 formdata.fields.push_back(BuildField("cc-number")); 63 formdata.fields.push_back(BuildField("cc-exp-month")); 64 formdata.fields.push_back(BuildField("cc-exp-year")); 65 formdata.fields.push_back(BuildField("cc-csc")); 66 formdata.fields.push_back(BuildField("billing address-line1")); 67 formdata.fields.push_back(BuildField("billing address-line2")); 68 formdata.fields.push_back(BuildField("billing locality")); 69 formdata.fields.push_back(BuildField("billing region")); 70 formdata.fields.push_back(BuildField("billing country")); 71 formdata.fields.push_back(BuildField("billing postal-code")); 72 formdata.fields.push_back(BuildField("billing tel")); 73 formdata.fields.push_back(BuildField("shipping name")); 74 formdata.fields.push_back(BuildField("shipping address-line1")); 75 formdata.fields.push_back(BuildField("shipping address-line2")); 76 formdata.fields.push_back(BuildField("shipping locality")); 77 formdata.fields.push_back(BuildField("shipping region")); 78 formdata.fields.push_back(BuildField("shipping country")); 79 formdata.fields.push_back(BuildField("shipping postal-code")); 80 formdata.fields.push_back(BuildField("shipping tel")); 81 return formdata; 82 } 83 84 AutofillMetrics::AutocheckoutBuyFlowMetric AutocheckoutStatusToUmaMetric( 85 AutocheckoutStatus status) { 86 switch (status) { 87 case SUCCESS: 88 return AutofillMetrics::AUTOCHECKOUT_BUY_FLOW_SUCCESS; 89 case MISSING_FIELDMAPPING: 90 return AutofillMetrics::AUTOCHECKOUT_BUY_FLOW_MISSING_FIELDMAPPING; 91 case MISSING_CLICK_ELEMENT_BEFORE_FORM_FILLING: 92 return AutofillMetrics:: 93 AUTOCHECKOUT_BUY_FLOW_MISSING_CLICK_ELEMENT_BEFORE_FORM_FILLING; 94 case MISSING_CLICK_ELEMENT_AFTER_FORM_FILLING: 95 return AutofillMetrics:: 96 AUTOCHECKOUT_BUY_FLOW_MISSING_CLICK_ELEMENT_AFTER_FORM_FILLING; 97 case MISSING_ADVANCE: 98 return AutofillMetrics::AUTOCHECKOUT_BUY_FLOW_MISSING_ADVANCE_ELEMENT; 99 case CANNOT_PROCEED: 100 return AutofillMetrics::AUTOCHECKOUT_BUY_FLOW_CANNOT_PROCEED; 101 case AUTOCHECKOUT_STATUS_NUM_STATUS: 102 NOTREACHED(); 103 } 104 105 NOTREACHED(); 106 return AutofillMetrics::NUM_AUTOCHECKOUT_BUY_FLOW_METRICS; 107 } 108 109 // Callback for retrieving Google Account cookies. |callback| is passed the 110 // retrieved cookies and posted back to the UI thread. |cookies| is any Google 111 // Account cookies. 112 void GetGoogleCookiesCallback( 113 const base::Callback<void(const std::string&)>& callback, 114 const std::string& cookies) { 115 content::BrowserThread::PostTask(content::BrowserThread::UI, 116 FROM_HERE, 117 base::Bind(callback, cookies)); 118 } 119 120 // Gets Google Account cookies. Must be called on the IO thread. 121 // |request_context_getter| is a getter for the current request context. 122 // |callback| is called when retrieving cookies is completed. 123 void GetGoogleCookies( 124 scoped_refptr<net::URLRequestContextGetter> request_context_getter, 125 const base::Callback<void(const std::string&)>& callback) { 126 net::URLRequestContext* url_request_context = 127 request_context_getter->GetURLRequestContext(); 128 if (!url_request_context) 129 return; 130 131 net::CookieStore* cookie_store = url_request_context->cookie_store(); 132 133 base::Callback<void(const std::string&)> cookie_callback = base::Bind( 134 &GetGoogleCookiesCallback, 135 callback); 136 137 net::CookieOptions cookie_options; 138 cookie_options.set_include_httponly(); 139 cookie_store->GetCookiesWithOptionsAsync(GURL(kGoogleAccountsUrl), 140 cookie_options, 141 cookie_callback); 142 } 143 144 bool IsBillingGroup(FieldTypeGroup group) { 145 return group == ADDRESS_BILLING || 146 group == PHONE_BILLING || 147 group == NAME_BILLING; 148 } 149 150 const char kTransactionIdNotSet[] = "transaction id not set"; 151 152 } // namespace 153 154 AutocheckoutManager::AutocheckoutManager(AutofillManager* autofill_manager) 155 : autofill_manager_(autofill_manager), 156 metric_logger_(new AutofillMetrics), 157 should_show_bubble_(true), 158 is_autocheckout_bubble_showing_(false), 159 in_autocheckout_flow_(false), 160 should_preserve_dialog_(false), 161 google_transaction_id_(kTransactionIdNotSet), 162 weak_ptr_factory_(this) {} 163 164 AutocheckoutManager::~AutocheckoutManager() { 165 } 166 167 void AutocheckoutManager::FillForms() { 168 // |page_meta_data_| should have been set by OnLoadedPageMetaData. 169 DCHECK(page_meta_data_); 170 171 // Fill the forms on the page with data given by user. 172 std::vector<FormData> filled_forms; 173 const std::vector<FormStructure*>& form_structures = 174 autofill_manager_->GetFormStructures(); 175 for (std::vector<FormStructure*>::const_iterator iter = 176 form_structures.begin(); iter != form_structures.end(); ++iter) { 177 FormStructure* form_structure = *iter; 178 form_structure->set_filled_by_autocheckout(true); 179 FormData form = form_structure->ToFormData(); 180 DCHECK_EQ(form_structure->field_count(), form.fields.size()); 181 182 for (size_t i = 0; i < form_structure->field_count(); ++i) { 183 const AutofillField* field = form_structure->field(i); 184 SetValue(*field, &form.fields[i]); 185 } 186 187 filled_forms.push_back(form); 188 } 189 190 // Send filled forms along with proceed descriptor to renderer. 191 RenderViewHost* host = 192 autofill_manager_->GetWebContents()->GetRenderViewHost(); 193 if (!host) 194 return; 195 196 host->Send(new AutofillMsg_FillFormsAndClick( 197 host->GetRoutingID(), 198 filled_forms, 199 page_meta_data_->click_elements_before_form_fill, 200 page_meta_data_->click_elements_after_form_fill, 201 page_meta_data_->proceed_element_descriptor)); 202 // Record time taken for navigating current page. 203 RecordTimeTaken(page_meta_data_->current_page_number); 204 } 205 206 void AutocheckoutManager::OnAutocheckoutPageCompleted( 207 AutocheckoutStatus status) { 208 if (!in_autocheckout_flow_) 209 return; 210 211 DVLOG(2) << "OnAutocheckoutPageCompleted, page_no: " 212 << page_meta_data_->current_page_number 213 << " status: " 214 << status; 215 216 DCHECK_NE(MISSING_FIELDMAPPING, status); 217 218 SetStepProgressForPage( 219 page_meta_data_->current_page_number, 220 (status == SUCCESS) ? AUTOCHECKOUT_STEP_COMPLETED : 221 AUTOCHECKOUT_STEP_FAILED); 222 223 if (page_meta_data_->IsEndOfAutofillableFlow() || status != SUCCESS) 224 EndAutocheckout(status); 225 } 226 227 void AutocheckoutManager::OnLoadedPageMetaData( 228 scoped_ptr<AutocheckoutPageMetaData> page_meta_data) { 229 scoped_ptr<AutocheckoutPageMetaData> old_meta_data = page_meta_data_.Pass(); 230 page_meta_data_ = page_meta_data.Pass(); 231 232 // If there is no click element in the last page, then it's the real last page 233 // of the flow, and the dialog will be closed when the page navigates. 234 // Otherwise, the dialog should be preserved for the page loaded by the click 235 // element on the last page of the flow. 236 // Note, |should_preserve_dialog_| has to be computed at this point because 237 // |in_autocheckout_flow_| may change after |OnLoadedPageMetaData| is called. 238 should_preserve_dialog_ = in_autocheckout_flow_ || 239 (old_meta_data.get() && 240 old_meta_data->IsEndOfAutofillableFlow() && 241 old_meta_data->proceed_element_descriptor.retrieval_method != 242 WebElementDescriptor::NONE); 243 244 // Don't log that the bubble could be displayed if the user entered an 245 // Autocheckout flow and sees the first page of the flow again due to an 246 // error. 247 if (IsStartOfAutofillableFlow() && !in_autocheckout_flow_) { 248 metric_logger_->LogAutocheckoutBubbleMetric( 249 AutofillMetrics::BUBBLE_COULD_BE_DISPLAYED); 250 } 251 252 // On the first page of an Autocheckout flow, when this function is called the 253 // user won't have opted into the flow yet. 254 if (!in_autocheckout_flow_) 255 return; 256 257 AutocheckoutStatus status = SUCCESS; 258 259 // Missing Autofill server results. 260 if (!page_meta_data_.get()) { 261 status = MISSING_FIELDMAPPING; 262 } else if (IsStartOfAutofillableFlow()) { 263 // Not possible unless Autocheckout failed to proceed. 264 status = CANNOT_PROCEED; 265 } else if (!page_meta_data_->IsInAutofillableFlow()) { 266 // Missing Autocheckout meta data in the Autofill server results. 267 status = MISSING_FIELDMAPPING; 268 } else if (page_meta_data_->current_page_number <= 269 old_meta_data->current_page_number) { 270 // Not possible unless Autocheckout failed to proceed. 271 status = CANNOT_PROCEED; 272 } 273 274 // Encountered an error during the Autocheckout flow, probably to 275 // do with a problem on the previous page. 276 if (status != SUCCESS) { 277 SetStepProgressForPage(old_meta_data->current_page_number, 278 AUTOCHECKOUT_STEP_FAILED); 279 EndAutocheckout(status); 280 return; 281 } 282 283 SetStepProgressForPage(page_meta_data_->current_page_number, 284 AUTOCHECKOUT_STEP_STARTED); 285 286 FillForms(); 287 } 288 289 void AutocheckoutManager::OnFormsSeen() { 290 should_show_bubble_ = true; 291 } 292 293 bool AutocheckoutManager::ShouldIgnoreAjax() { 294 return in_autocheckout_flow_ && page_meta_data_->ignore_ajax; 295 } 296 297 void AutocheckoutManager::MaybeShowAutocheckoutBubble( 298 const GURL& frame_url, 299 const gfx::RectF& bounding_box) { 300 if (!should_show_bubble_ || 301 is_autocheckout_bubble_showing_ || 302 !IsStartOfAutofillableFlow()) 303 return; 304 305 base::Callback<void(const std::string&)> callback = base::Bind( 306 &AutocheckoutManager::ShowAutocheckoutBubble, 307 weak_ptr_factory_.GetWeakPtr(), 308 frame_url, 309 bounding_box); 310 311 content::WebContents* web_contents = autofill_manager_->GetWebContents(); 312 if (!web_contents) 313 return; 314 315 content::BrowserContext* browser_context = web_contents->GetBrowserContext(); 316 if(!browser_context) 317 return; 318 319 scoped_refptr<net::URLRequestContextGetter> request_context = 320 scoped_refptr<net::URLRequestContextGetter>( 321 browser_context->GetRequestContext()); 322 323 if (!request_context.get()) 324 return; 325 326 base::Closure task = base::Bind(&GetGoogleCookies, request_context, callback); 327 328 content::BrowserThread::PostTask(content::BrowserThread::IO, 329 FROM_HERE, 330 task); 331 } 332 333 void AutocheckoutManager::ReturnAutocheckoutData( 334 const FormStructure* result, 335 const std::string& google_transaction_id) { 336 if (!result) { 337 // When user cancels the dialog, |result| is NULL. 338 // TODO(): add AutocheckoutStatus.USER_CANCELLED, and call 339 // EndAutocheckout(USER_CANCELLED) instead. 340 in_autocheckout_flow_ = false; 341 return; 342 } 343 344 latency_statistics_.clear(); 345 last_step_completion_timestamp_ = base::TimeTicks().Now(); 346 google_transaction_id_ = google_transaction_id; 347 in_autocheckout_flow_ = true; 348 should_preserve_dialog_ = true; 349 metric_logger_->LogAutocheckoutBuyFlowMetric( 350 AutofillMetrics::AUTOCHECKOUT_BUY_FLOW_STARTED); 351 352 profile_.reset(new AutofillProfile()); 353 credit_card_.reset(new CreditCard()); 354 billing_address_.reset(new AutofillProfile()); 355 356 for (size_t i = 0; i < result->field_count(); ++i) { 357 const AutofillType& type = result->field(i)->Type(); 358 const base::string16& value = result->field(i)->value; 359 ServerFieldType server_type = type.GetStorableType(); 360 if (server_type == CREDIT_CARD_VERIFICATION_CODE) { 361 cvv_ = result->field(i)->value; 362 continue; 363 } 364 FieldTypeGroup group = type.group(); 365 if (group == CREDIT_CARD) { 366 credit_card_->SetRawInfo(server_type, value); 367 // TODO(dgwallinga): Find a way of cleanly deprecating CREDIT_CARD_NAME. 368 // code.google.com/p/chromium/issues/detail?id=263498 369 if (server_type == CREDIT_CARD_NAME) 370 billing_address_->SetRawInfo(NAME_BILLING_FULL, value); 371 } else if (server_type == ADDRESS_HOME_COUNTRY) { 372 if (IsBillingGroup(group)) 373 billing_address_->SetInfo(type, value, autofill_manager_->app_locale()); 374 else 375 profile_->SetInfo(type, value, autofill_manager_->app_locale()); 376 } else if (IsBillingGroup(group)) { 377 billing_address_->SetRawInfo(server_type, value); 378 } else { 379 profile_->SetRawInfo(server_type, value); 380 } 381 } 382 383 // Page types only available in first-page meta data, so save 384 // them for use later as we navigate. 385 page_types_ = page_meta_data_->page_types; 386 SetStepProgressForPage(page_meta_data_->current_page_number, 387 AUTOCHECKOUT_STEP_STARTED); 388 389 FillForms(); 390 } 391 392 void AutocheckoutManager::set_metric_logger( 393 scoped_ptr<AutofillMetrics> metric_logger) { 394 metric_logger_ = metric_logger.Pass(); 395 } 396 397 void AutocheckoutManager::MaybeShowAutocheckoutDialog( 398 const GURL& frame_url, 399 AutocheckoutBubbleState state) { 400 is_autocheckout_bubble_showing_ = false; 401 402 // User has taken action on the bubble, don't offer bubble again. 403 if (state != AUTOCHECKOUT_BUBBLE_IGNORED) 404 should_show_bubble_ = false; 405 406 if (state != AUTOCHECKOUT_BUBBLE_ACCEPTED) 407 return; 408 409 base::Callback<void(const FormStructure*, const std::string&)> callback = 410 base::Bind(&AutocheckoutManager::ReturnAutocheckoutData, 411 weak_ptr_factory_.GetWeakPtr()); 412 autofill_manager_->ShowRequestAutocompleteDialog(BuildAutocheckoutFormData(), 413 frame_url, 414 DIALOG_TYPE_AUTOCHECKOUT, 415 callback); 416 417 for (std::map<int, std::vector<AutocheckoutStepType> >::const_iterator 418 it = page_meta_data_->page_types.begin(); 419 it != page_meta_data_->page_types.end(); ++it) { 420 for (size_t i = 0; i < it->second.size(); ++i) { 421 autofill_manager_->delegate()->AddAutocheckoutStep(it->second[i]); 422 } 423 } 424 } 425 426 void AutocheckoutManager::ShowAutocheckoutBubble( 427 const GURL& frame_url, 428 const gfx::RectF& bounding_box, 429 const std::string& cookies) { 430 DCHECK(thread_checker_.CalledOnValidThread()); 431 432 base::Callback<void(AutocheckoutBubbleState)> callback = base::Bind( 433 &AutocheckoutManager::MaybeShowAutocheckoutDialog, 434 weak_ptr_factory_.GetWeakPtr(), 435 frame_url); 436 is_autocheckout_bubble_showing_ = 437 autofill_manager_->delegate()->ShowAutocheckoutBubble( 438 bounding_box, 439 cookies.find("LSID") != std::string::npos, 440 callback); 441 } 442 443 bool AutocheckoutManager::IsStartOfAutofillableFlow() const { 444 return page_meta_data_ && page_meta_data_->IsStartOfAutofillableFlow(); 445 } 446 447 bool AutocheckoutManager::IsInAutofillableFlow() const { 448 return page_meta_data_ && page_meta_data_->IsInAutofillableFlow(); 449 } 450 451 void AutocheckoutManager::SetValue(const AutofillField& field, 452 FormFieldData* field_to_fill) { 453 // No-op if Autofill server doesn't know about the field. 454 if (field.server_type() == NO_SERVER_DATA) 455 return; 456 457 const AutofillType& type = field.Type(); 458 459 ServerFieldType server_type = type.GetStorableType(); 460 if (server_type == FIELD_WITH_DEFAULT_VALUE) { 461 // For a form with radio buttons, like: 462 // <form> 463 // <input type="radio" name="sex" value="male">Male<br> 464 // <input type="radio" name="sex" value="female">Female 465 // </form> 466 // If the default value specified at the server is "female", then 467 // Autofill server responds back with following field mappings 468 // (fieldtype: FIELD_WITH_DEFAULT_VALUE, value: "female") 469 // (fieldtype: FIELD_WITH_DEFAULT_VALUE, value: "female") 470 // Note that, the field mapping is repeated twice to respond to both the 471 // input elements with the same name/signature in the form. 472 // 473 // FIELD_WITH_DEFAULT_VALUE can also be used for selects, the correspondent 474 // example of the radio buttons example above is: 475 // <SELECT name="sex"> 476 // <OPTION value="female">Female</OPTION> 477 // <OPTION value="male">Male</OPTION> 478 // </SELECT> 479 base::string16 default_value = UTF8ToUTF16(field.default_value()); 480 if (field.is_checkable) { 481 // Mark the field checked if server says the default value of the field 482 // to be this field's value. 483 field_to_fill->is_checked = (field.value == default_value); 484 } else if (field.form_control_type == "select-one") { 485 field_to_fill->value = default_value; 486 } else { 487 // FIELD_WITH_DEFAULT_VALUE should not be used for other type of fields. 488 NOTREACHED(); 489 } 490 return; 491 } 492 493 // Handle verification code directly. 494 if (server_type == CREDIT_CARD_VERIFICATION_CODE) { 495 field_to_fill->value = cvv_; 496 return; 497 } 498 499 if (type.group() == CREDIT_CARD) { 500 credit_card_->FillFormField( 501 field, 0, autofill_manager_->app_locale(), field_to_fill); 502 } else if (IsBillingGroup(type.group())) { 503 billing_address_->FillFormField( 504 field, 0, autofill_manager_->app_locale(), field_to_fill); 505 } else { 506 profile_->FillFormField( 507 field, 0, autofill_manager_->app_locale(), field_to_fill); 508 } 509 } 510 511 void AutocheckoutManager::SendAutocheckoutStatus(AutocheckoutStatus status) { 512 // To ensure stale data isn't being sent. 513 DCHECK_NE(kTransactionIdNotSet, google_transaction_id_); 514 515 AutocheckoutRequestManager::CreateForBrowserContext( 516 autofill_manager_->GetWebContents()->GetBrowserContext()); 517 AutocheckoutRequestManager* autocheckout_request_manager = 518 AutocheckoutRequestManager::FromBrowserContext( 519 autofill_manager_->GetWebContents()->GetBrowserContext()); 520 // It is assumed that the domain Autocheckout starts on does not change 521 // during the flow. If this proves to be incorrect, the |source_url| from 522 // AutofillDialogControllerImpl will need to be provided in its callback in 523 // addition to the Google transaction id. 524 autocheckout_request_manager->SendAutocheckoutStatus( 525 status, 526 autofill_manager_->GetWebContents()->GetURL(), 527 latency_statistics_, 528 google_transaction_id_); 529 530 // Log the result of this Autocheckout flow to UMA. 531 metric_logger_->LogAutocheckoutBuyFlowMetric( 532 AutocheckoutStatusToUmaMetric(status)); 533 534 google_transaction_id_ = kTransactionIdNotSet; 535 } 536 537 void AutocheckoutManager::SetStepProgressForPage( 538 int page_number, 539 AutocheckoutStepStatus status) { 540 if (page_types_.count(page_number) == 1) { 541 for (size_t i = 0; i < page_types_[page_number].size(); ++i) { 542 autofill_manager_->delegate()->UpdateAutocheckoutStep( 543 page_types_[page_number][i], status); 544 } 545 } 546 } 547 548 void AutocheckoutManager::RecordTimeTaken(int page_number) { 549 AutocheckoutStatistic statistic; 550 statistic.page_number = page_number; 551 if (page_types_.count(page_number) == 1) { 552 for (size_t i = 0; i < page_types_[page_number].size(); ++i) { 553 statistic.steps.push_back(page_types_[page_number][i]); 554 } 555 } 556 557 statistic.time_taken = 558 base::TimeTicks().Now() - last_step_completion_timestamp_; 559 latency_statistics_.push_back(statistic); 560 561 // Reset timestamp. 562 last_step_completion_timestamp_ = base::TimeTicks().Now(); 563 } 564 565 void AutocheckoutManager::EndAutocheckout(AutocheckoutStatus status) { 566 DCHECK(in_autocheckout_flow_); 567 568 DVLOG(2) << "EndAutocheckout at step: " 569 << page_meta_data_->current_page_number 570 << " with status: " 571 << status; 572 573 SendAutocheckoutStatus(status); 574 if (status == SUCCESS) 575 autofill_manager_->delegate()->OnAutocheckoutSuccess(); 576 else 577 autofill_manager_->delegate()->OnAutocheckoutError(); 578 in_autocheckout_flow_ = false; 579 } 580 581 } // namespace autofill 582