Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / components / autofill / content / renderer / password_autofill_agent.cc
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/renderer/password_autofill_agent.h"
6
7 #include "base/bind.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/metrics/histogram.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "components/autofill/content/common/autofill_messages.h"
13 #include "components/autofill/content/renderer/form_autofill_util.h"
14 #include "components/autofill/content/renderer/password_form_conversion_utils.h"
15 #include "components/autofill/content/renderer/renderer_save_password_progress_logger.h"
16 #include "components/autofill/core/common/form_field_data.h"
17 #include "components/autofill/core/common/password_autofill_util.h"
18 #include "components/autofill/core/common/password_form.h"
19 #include "components/autofill/core/common/password_form_fill_data.h"
20 #include "content/public/common/page_transition_types.h"
21 #include "content/public/renderer/document_state.h"
22 #include "content/public/renderer/navigation_state.h"
23 #include "content/public/renderer/render_view.h"
24 #include "third_party/WebKit/public/platform/WebVector.h"
25 #include "third_party/WebKit/public/web/WebAutofillClient.h"
26 #include "third_party/WebKit/public/web/WebDocument.h"
27 #include "third_party/WebKit/public/web/WebElement.h"
28 #include "third_party/WebKit/public/web/WebFormElement.h"
29 #include "third_party/WebKit/public/web/WebInputEvent.h"
30 #include "third_party/WebKit/public/web/WebLocalFrame.h"
31 #include "third_party/WebKit/public/web/WebNode.h"
32 #include "third_party/WebKit/public/web/WebNodeList.h"
33 #include "third_party/WebKit/public/web/WebSecurityOrigin.h"
34 #include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
35 #include "third_party/WebKit/public/web/WebView.h"
36 #include "ui/events/keycodes/keyboard_codes.h"
37 #include "url/gurl.h"
38
39 namespace autofill {
40 namespace {
41
42 // The size above which we stop triggering autocomplete.
43 static const size_t kMaximumTextSizeForAutocomplete = 1000;
44
45 // Maps element names to the actual elements to simplify form filling.
46 typedef std::map<base::string16, blink::WebInputElement> FormInputElementMap;
47
48 // Use the shorter name when referencing SavePasswordProgressLogger::StringID
49 // values to spare line breaks. The code provides enough context for that
50 // already.
51 typedef SavePasswordProgressLogger Logger;
52
53 // Utility struct for form lookup and autofill. When we parse the DOM to look up
54 // a form, in addition to action and origin URL's we have to compare all
55 // necessary form elements. To avoid having to look these up again when we want
56 // to fill the form, the FindFormElements function stores the pointers
57 // in a FormElements* result, referenced to ensure they are safe to use.
58 struct FormElements {
59   blink::WebFormElement form_element;
60   FormInputElementMap input_elements;
61 };
62
63 typedef std::vector<FormElements*> FormElementsList;
64
65 // Helper to search the given form element for the specified input elements
66 // in |data|, and add results to |result|.
67 static bool FindFormInputElements(blink::WebFormElement* fe,
68                                   const FormData& data,
69                                   FormElements* result) {
70   // Loop through the list of elements we need to find on the form in order to
71   // autofill it. If we don't find any one of them, abort processing this
72   // form; it can't be the right one.
73   for (size_t j = 0; j < data.fields.size(); j++) {
74     blink::WebVector<blink::WebNode> temp_elements;
75     fe->getNamedElements(data.fields[j].name, temp_elements);
76
77     // Match the first input element, if any.
78     // |getNamedElements| may return non-input elements where the names match,
79     // so the results are filtered for input elements.
80     // If more than one match is made, then we have ambiguity (due to misuse
81     // of "name" attribute) so is it considered not found.
82     bool found_input = false;
83     for (size_t i = 0; i < temp_elements.size(); ++i) {
84       if (temp_elements[i].to<blink::WebElement>().hasTagName("input")) {
85         // Check for a non-unique match.
86         if (found_input) {
87           found_input = false;
88           break;
89         }
90
91         // Only fill saved passwords into password fields and usernames into
92         // text fields.
93         blink::WebInputElement input_element =
94             temp_elements[i].to<blink::WebInputElement>();
95         if (input_element.isPasswordField() !=
96             (data.fields[j].form_control_type == "password"))
97           continue;
98
99         // This element matched, add it to our temporary result. It's possible
100         // there are multiple matches, but for purposes of identifying the form
101         // one suffices and if some function needs to deal with multiple
102         // matching elements it can get at them through the FormElement*.
103         // Note: This assignment adds a reference to the InputElement.
104         result->input_elements[data.fields[j].name] = input_element;
105         found_input = true;
106       }
107     }
108
109     // A required element was not found. This is not the right form.
110     // Make sure no input elements from a partially matched form in this
111     // iteration remain in the result set.
112     // Note: clear will remove a reference from each InputElement.
113     if (!found_input) {
114       result->input_elements.clear();
115       return false;
116     }
117   }
118   return true;
119 }
120
121 // Helper to locate form elements identified by |data|.
122 void FindFormElements(blink::WebView* view,
123                       const FormData& data,
124                       FormElementsList* results) {
125   DCHECK(view);
126   DCHECK(results);
127   blink::WebFrame* main_frame = view->mainFrame();
128   if (!main_frame)
129     return;
130
131   GURL::Replacements rep;
132   rep.ClearQuery();
133   rep.ClearRef();
134
135   // Loop through each frame.
136   for (blink::WebFrame* f = main_frame; f; f = f->traverseNext(false)) {
137     blink::WebDocument doc = f->document();
138     if (!doc.isHTMLDocument())
139       continue;
140
141     GURL full_origin(doc.url());
142     if (data.origin != full_origin.ReplaceComponents(rep))
143       continue;
144
145     blink::WebVector<blink::WebFormElement> forms;
146     doc.forms(forms);
147
148     for (size_t i = 0; i < forms.size(); ++i) {
149       blink::WebFormElement fe = forms[i];
150
151       GURL full_action(f->document().completeURL(fe.action()));
152       if (full_action.is_empty()) {
153         // The default action URL is the form's origin.
154         full_action = full_origin;
155       }
156
157       // Action URL must match.
158       if (data.action != full_action.ReplaceComponents(rep))
159         continue;
160
161       scoped_ptr<FormElements> curr_elements(new FormElements);
162       if (!FindFormInputElements(&fe, data, curr_elements.get()))
163         continue;
164
165       // We found the right element.
166       // Note: this assignment adds a reference to |fe|.
167       curr_elements->form_element = fe;
168       results->push_back(curr_elements.release());
169     }
170   }
171 }
172
173 bool IsElementEditable(const blink::WebInputElement& element) {
174   return element.isEnabled() && !element.isReadOnly();
175 }
176
177 bool DoUsernamesMatch(const base::string16& username1,
178                       const base::string16& username2,
179                       bool exact_match) {
180   if (exact_match)
181     return username1 == username2;
182   return StartsWith(username1, username2, true);
183 }
184
185 // Returns |true| if the given element is both editable and has permission to be
186 // autocompleted. The latter can be either because there is no
187 // autocomplete='off' set for the element, or because the flag is set to ignore
188 // autocomplete='off'. Otherwise, returns |false|.
189 bool IsElementAutocompletable(const blink::WebInputElement& element) {
190   return IsElementEditable(element) &&
191          (ShouldIgnoreAutocompleteOffForPasswordFields() ||
192           element.autoComplete());
193 }
194
195 // Returns true if the password specified in |form| is a default value.
196 bool PasswordValueIsDefault(const PasswordForm& form,
197                             blink::WebFormElement form_element) {
198   blink::WebVector<blink::WebNode> temp_elements;
199   form_element.getNamedElements(form.password_element, temp_elements);
200
201   // We are loose in our definition here and will return true if any of the
202   // appropriately named elements match the element to be saved. Currently
203   // we ignore filling passwords where naming is ambigious anyway.
204   for (size_t i = 0; i < temp_elements.size(); ++i) {
205     if (temp_elements[i].to<blink::WebElement>().getAttribute("value") ==
206         form.password_value)
207       return true;
208   }
209   return false;
210 }
211
212 // Log a message including the name, method and action of |form|.
213 void LogHTMLForm(SavePasswordProgressLogger* logger,
214                  SavePasswordProgressLogger::StringID message_id,
215                  const blink::WebFormElement& form) {
216   logger->LogHTMLForm(message_id,
217                       form.name().utf8(),
218                       form.method().utf8(),
219                       GURL(form.action().utf8()));
220 }
221
222 }  // namespace
223
224 ////////////////////////////////////////////////////////////////////////////////
225 // PasswordAutofillAgent, public:
226
227 PasswordAutofillAgent::PasswordAutofillAgent(content::RenderView* render_view)
228     : content::RenderViewObserver(render_view),
229       usernames_usage_(NOTHING_TO_AUTOFILL),
230       web_view_(render_view->GetWebView()),
231       logging_state_active_(false),
232       weak_ptr_factory_(this) {
233 }
234
235 PasswordAutofillAgent::~PasswordAutofillAgent() {
236 }
237
238 PasswordAutofillAgent::PasswordValueGatekeeper::PasswordValueGatekeeper()
239     : was_user_gesture_seen_(false) {
240 }
241
242 PasswordAutofillAgent::PasswordValueGatekeeper::~PasswordValueGatekeeper() {
243 }
244
245 void PasswordAutofillAgent::PasswordValueGatekeeper::RegisterElement(
246     blink::WebInputElement* element) {
247   if (was_user_gesture_seen_)
248     ShowValue(element);
249   else
250     elements_.push_back(*element);
251 }
252
253 void PasswordAutofillAgent::PasswordValueGatekeeper::OnUserGesture() {
254   was_user_gesture_seen_ = true;
255
256   for (std::vector<blink::WebInputElement>::iterator it = elements_.begin();
257        it != elements_.end();
258        ++it) {
259     ShowValue(&(*it));
260   }
261
262   elements_.clear();
263 }
264
265 void PasswordAutofillAgent::PasswordValueGatekeeper::Reset() {
266   was_user_gesture_seen_ = false;
267   elements_.clear();
268 }
269
270 void PasswordAutofillAgent::PasswordValueGatekeeper::ShowValue(
271     blink::WebInputElement* element) {
272   if (!element->isNull() && !element->suggestedValue().isNull())
273     element->setValue(element->suggestedValue(), true);
274 }
275
276 bool PasswordAutofillAgent::TextFieldDidEndEditing(
277     const blink::WebInputElement& element) {
278   LoginToPasswordInfoMap::const_iterator iter =
279       login_to_password_info_.find(element);
280   if (iter == login_to_password_info_.end())
281     return false;
282
283   const PasswordFormFillData& fill_data = iter->second.fill_data;
284
285   // If wait_for_username is false, we should have filled when the text changed.
286   if (!fill_data.wait_for_username)
287     return false;
288
289   blink::WebInputElement password = iter->second.password_field;
290   if (!IsElementEditable(password))
291     return false;
292
293   blink::WebInputElement username = element;  // We need a non-const.
294
295   // Do not set selection when ending an editing session, otherwise it can
296   // mess with focus.
297   FillUserNameAndPassword(&username,
298                           &password,
299                           fill_data,
300                           true /* exact_username_match */,
301                           false /* set_selection */);
302   return true;
303 }
304
305 bool PasswordAutofillAgent::TextDidChangeInTextField(
306     const blink::WebInputElement& element) {
307   LoginToPasswordInfoMap::const_iterator iter =
308       login_to_password_info_.find(element);
309   if (iter == login_to_password_info_.end())
310     return false;
311
312   // The input text is being changed, so any autofilled password is now
313   // outdated.
314   blink::WebInputElement username = element;  // We need a non-const.
315   username.setAutofilled(false);
316
317   blink::WebInputElement password = iter->second.password_field;
318   if (password.isAutofilled()) {
319     password.setValue(base::string16(), true);
320     password.setAutofilled(false);
321   }
322
323   // If wait_for_username is true we will fill when the username loses focus.
324   if (iter->second.fill_data.wait_for_username)
325     return false;
326
327   if (!element.isText() || !IsElementAutocompletable(element) ||
328       !IsElementAutocompletable(password)) {
329     return false;
330   }
331
332   // Don't inline autocomplete if the user is deleting, that would be confusing.
333   // But refresh the popup.  Note, since this is ours, return true to signal
334   // no further processing is required.
335   if (iter->second.backspace_pressed_last) {
336     ShowSuggestionPopup(iter->second.fill_data, username);
337     return true;
338   }
339
340   blink::WebString name = element.nameForAutofill();
341   if (name.isEmpty())
342     return false;  // If the field has no name, then we won't have values.
343
344   // Don't attempt to autofill with values that are too large.
345   if (element.value().length() > kMaximumTextSizeForAutocomplete)
346     return false;
347
348   // The caret position should have already been updated.
349   PerformInlineAutocomplete(element, password, iter->second.fill_data);
350   return true;
351 }
352
353 bool PasswordAutofillAgent::TextFieldHandlingKeyDown(
354     const blink::WebInputElement& element,
355     const blink::WebKeyboardEvent& event) {
356   // If using the new Autofill UI that lives in the browser, it will handle
357   // keypresses before this function. This is not currently an issue but if
358   // the keys handled there or here change, this issue may appear.
359
360   LoginToPasswordInfoMap::iterator iter = login_to_password_info_.find(element);
361   if (iter == login_to_password_info_.end())
362     return false;
363
364   int win_key_code = event.windowsKeyCode;
365   iter->second.backspace_pressed_last =
366       (win_key_code == ui::VKEY_BACK || win_key_code == ui::VKEY_DELETE);
367   return true;
368 }
369
370 bool PasswordAutofillAgent::AcceptSuggestion(
371     const blink::WebNode& node,
372     const blink::WebString& username,
373     const blink::WebString& password) {
374   blink::WebInputElement username_element;
375   PasswordInfo password_info;
376
377   if (!FindLoginInfo(node, &username_element, &password_info) ||
378       !IsElementAutocompletable(username_element) ||
379       !IsElementAutocompletable(password_info.password_field)) {
380     return false;
381   }
382
383   base::string16 current_username = username_element.value();
384   username_element.setValue(username, true);
385   username_element.setAutofilled(true);
386   username_element.setSelectionRange(username.length(), username.length());
387
388   password_info.password_field.setValue(password, true);
389   password_info.password_field.setAutofilled(true);
390
391   return true;
392 }
393
394 bool PasswordAutofillAgent::DidClearAutofillSelection(
395     const blink::WebNode& node) {
396   blink::WebInputElement input;
397   PasswordInfo password;
398   return FindLoginInfo(node, &input, &password);
399 }
400
401 bool PasswordAutofillAgent::ShowSuggestions(
402     const blink::WebInputElement& element) {
403   LoginToPasswordInfoMap::const_iterator iter =
404       login_to_password_info_.find(element);
405   if (iter == login_to_password_info_.end())
406     return false;
407
408   // If autocomplete='off' is set on the form elements, no suggestion dialog
409   // should be shown. However, return |true| to indicate that this is a known
410   // password form and that the request to show suggestions has been handled (as
411   // a no-op).
412   if (!IsElementAutocompletable(element) ||
413       !IsElementAutocompletable(iter->second.password_field))
414     return true;
415
416   return ShowSuggestionPopup(iter->second.fill_data, element);
417 }
418
419 bool PasswordAutofillAgent::OriginCanAccessPasswordManager(
420     const blink::WebSecurityOrigin& origin) {
421   return origin.canAccessPasswordManager();
422 }
423
424 void PasswordAutofillAgent::OnDynamicFormsSeen(blink::WebFrame* frame) {
425   SendPasswordForms(frame, false /* only_visible */);
426 }
427
428 void PasswordAutofillAgent::FirstUserGestureObserved() {
429   gatekeeper_.OnUserGesture();
430 }
431
432 void PasswordAutofillAgent::SendPasswordForms(blink::WebFrame* frame,
433                                               bool only_visible) {
434   scoped_ptr<RendererSavePasswordProgressLogger> logger;
435   // From the perspective of saving passwords, only calls with |only_visible|
436   // being true are important -- the decision whether to save the password is
437   // only made after visible forms are known, for failed login detection. Calls
438   // with |only_visible| false are important for password form autofill, which
439   // is currently not part of the logging.
440   if (only_visible && logging_state_active_) {
441     logger.reset(new RendererSavePasswordProgressLogger(this, routing_id()));
442     logger->LogMessage(Logger::STRING_SEND_PASSWORD_FORMS_METHOD);
443   }
444
445   // Make sure that this security origin is allowed to use password manager.
446   blink::WebSecurityOrigin origin = frame->document().securityOrigin();
447   if (logger) {
448     logger->LogURL(Logger::STRING_SECURITY_ORIGIN,
449                    GURL(origin.toString().utf8()));
450   }
451   if (!OriginCanAccessPasswordManager(origin)) {
452     if (logger) {
453       logger->LogMessage(Logger::STRING_SECURITY_ORIGIN_FAILURE);
454       logger->LogMessage(Logger::STRING_DECISION_DROP);
455     }
456     return;
457   }
458
459   // Checks whether the webpage is a redirect page or an empty page.
460   if (IsWebpageEmpty(frame)) {
461     if (logger) {
462       logger->LogMessage(Logger::STRING_WEBPAGE_EMPTY);
463       logger->LogMessage(Logger::STRING_DECISION_DROP);
464     }
465     return;
466   }
467
468   blink::WebVector<blink::WebFormElement> forms;
469   frame->document().forms(forms);
470   if (logger)
471     logger->LogNumber(Logger::STRING_NUMBER_OF_ALL_FORMS, forms.size());
472
473   std::vector<PasswordForm> password_forms;
474   for (size_t i = 0; i < forms.size(); ++i) {
475     const blink::WebFormElement& form = forms[i];
476     bool is_form_visible = IsWebNodeVisible(form);
477     if (logger) {
478       LogHTMLForm(logger.get(), Logger::STRING_FORM_FOUND_ON_PAGE, form);
479       logger->LogBoolean(Logger::STRING_FORM_IS_VISIBLE, is_form_visible);
480     }
481
482     // If requested, ignore non-rendered forms, e.g. those styled with
483     // display:none.
484     if (only_visible && !is_form_visible)
485       continue;
486
487     scoped_ptr<PasswordForm> password_form(CreatePasswordForm(form));
488     if (password_form.get()) {
489       if (logger) {
490         logger->LogPasswordForm(Logger::STRING_FORM_IS_PASSWORD,
491                                 *password_form);
492       }
493       password_forms.push_back(*password_form);
494     }
495   }
496
497   if (password_forms.empty() && !only_visible) {
498     // We need to send the PasswordFormsRendered message regardless of whether
499     // there are any forms visible, as this is also the code path that triggers
500     // showing the infobar.
501     return;
502   }
503
504   if (only_visible) {
505     Send(new AutofillHostMsg_PasswordFormsRendered(routing_id(),
506                                                    password_forms));
507   } else {
508     Send(new AutofillHostMsg_PasswordFormsParsed(routing_id(), password_forms));
509   }
510 }
511
512 bool PasswordAutofillAgent::OnMessageReceived(const IPC::Message& message) {
513   bool handled = true;
514   IPC_BEGIN_MESSAGE_MAP(PasswordAutofillAgent, message)
515     IPC_MESSAGE_HANDLER(AutofillMsg_FillPasswordForm, OnFillPasswordForm)
516     IPC_MESSAGE_HANDLER(AutofillMsg_ChangeLoggingState, OnChangeLoggingState)
517     IPC_MESSAGE_UNHANDLED(handled = false)
518   IPC_END_MESSAGE_MAP()
519   return handled;
520 }
521
522 void PasswordAutofillAgent::DidStartLoading() {
523   if (usernames_usage_ != NOTHING_TO_AUTOFILL) {
524     UMA_HISTOGRAM_ENUMERATION("PasswordManager.OtherPossibleUsernamesUsage",
525                               usernames_usage_,
526                               OTHER_POSSIBLE_USERNAMES_MAX);
527     usernames_usage_ = NOTHING_TO_AUTOFILL;
528   }
529 }
530
531 void PasswordAutofillAgent::DidFinishDocumentLoad(blink::WebLocalFrame* frame) {
532   // The |frame| contents have been parsed, but not yet rendered.  Let the
533   // PasswordManager know that forms are loaded, even though we can't yet tell
534   // whether they're visible.
535   SendPasswordForms(frame, false);
536 }
537
538 void PasswordAutofillAgent::DidFinishLoad(blink::WebLocalFrame* frame) {
539   // The |frame| contents have been rendered.  Let the PasswordManager know
540   // which of the loaded frames are actually visible to the user.  This also
541   // triggers the "Save password?" infobar if the user just submitted a password
542   // form.
543   SendPasswordForms(frame, true);
544 }
545
546 void PasswordAutofillAgent::FrameDetached(blink::WebFrame* frame) {
547   FrameClosing(frame);
548 }
549
550 void PasswordAutofillAgent::FrameWillClose(blink::WebFrame* frame) {
551   FrameClosing(frame);
552 }
553
554 void PasswordAutofillAgent::WillSendSubmitEvent(
555     blink::WebLocalFrame* frame,
556     const blink::WebFormElement& form) {
557   // Some login forms have onSubmit handlers that put a hash of the password
558   // into a hidden field and then clear the password (http://crbug.com/28910).
559   // This method gets called before any of those handlers run, so save away
560   // a copy of the password in case it gets lost.
561   scoped_ptr<PasswordForm> password_form(CreatePasswordForm(form));
562   if (password_form)
563     provisionally_saved_forms_[frame].reset(password_form.release());
564 }
565
566 void PasswordAutofillAgent::WillSubmitForm(blink::WebLocalFrame* frame,
567                                            const blink::WebFormElement& form) {
568   scoped_ptr<RendererSavePasswordProgressLogger> logger;
569   if (logging_state_active_) {
570     logger.reset(new RendererSavePasswordProgressLogger(this, routing_id()));
571     logger->LogMessage(Logger::STRING_WILL_SUBMIT_FORM_METHOD);
572     LogHTMLForm(logger.get(), Logger::STRING_HTML_FORM_FOR_SUBMIT, form);
573   }
574
575   scoped_ptr<PasswordForm> submitted_form = CreatePasswordForm(form);
576
577   // If there is a provisionally saved password, copy over the previous
578   // password value so we get the user's typed password, not the value that
579   // may have been transformed for submit.
580   // TODO(gcasto): Do we need to have this action equality check? Is it trying
581   // to prevent accidentally copying over passwords from a different form?
582   if (submitted_form) {
583     if (logger) {
584       logger->LogPasswordForm(Logger::STRING_CREATED_PASSWORD_FORM,
585                               *submitted_form);
586     }
587     if (provisionally_saved_forms_[frame].get() &&
588         submitted_form->action == provisionally_saved_forms_[frame]->action) {
589       if (logger)
590         logger->LogMessage(Logger::STRING_SUBMITTED_PASSWORD_REPLACED);
591       submitted_form->password_value =
592           provisionally_saved_forms_[frame]->password_value;
593     }
594
595     // Some observers depend on sending this information now instead of when
596     // the frame starts loading. If there are redirects that cause a new
597     // RenderView to be instantiated (such as redirects to the WebStore)
598     // we will never get to finish the load.
599     Send(new AutofillHostMsg_PasswordFormSubmitted(routing_id(),
600                                                    *submitted_form));
601     // Remove reference since we have already submitted this form.
602     provisionally_saved_forms_.erase(frame);
603   } else if (logger) {
604     logger->LogMessage(Logger::STRING_DECISION_DROP);
605   }
606 }
607
608 blink::WebFrame* PasswordAutofillAgent::CurrentOrChildFrameWithSavedForms(
609     const blink::WebFrame* current_frame) {
610   for (FrameToPasswordFormMap::const_iterator it =
611            provisionally_saved_forms_.begin();
612        it != provisionally_saved_forms_.end();
613        ++it) {
614     blink::WebFrame* form_frame = it->first;
615     // The check that the returned frame is related to |current_frame| is mainly
616     // for double-checking. There should not be any unrelated frames in
617     // |provisionally_saved_forms_|, because the map is cleared after
618     // navigation. If there are reasons to remove this check in the future and
619     // keep just the first frame found, it might be a good idea to add a UMA
620     // statistic or a similar check on how many frames are here to choose from.
621     if (current_frame == form_frame ||
622         current_frame->findChildByName(form_frame->assignedName())) {
623       return form_frame;
624     }
625   }
626   return NULL;
627 }
628
629 void PasswordAutofillAgent::DidStartProvisionalLoad(
630     blink::WebLocalFrame* frame) {
631   scoped_ptr<RendererSavePasswordProgressLogger> logger;
632   if (logging_state_active_) {
633     logger.reset(new RendererSavePasswordProgressLogger(this, routing_id()));
634     logger->LogMessage(Logger::STRING_DID_START_PROVISIONAL_LOAD_METHOD);
635   }
636
637   if (!frame->parent()) {
638     // If the navigation is not triggered by a user gesture, e.g. by some ajax
639     // callback, then inherit the submitted password form from the previous
640     // state. This fixes the no password save issue for ajax login, tracked in
641     // [http://crbug/43219]. Note that this still fails for sites that use
642     // synchonous XHR as isProcessingUserGesture() will return true.
643     blink::WebFrame* form_frame = CurrentOrChildFrameWithSavedForms(frame);
644     if (logger) {
645       logger->LogBoolean(Logger::STRING_FORM_FRAME_EQ_FRAME,
646                          form_frame == frame);
647     }
648     // Bug fix for crbug.com/368690. isProcessingUserGesture() is false when
649     // the user is performing actions outside the page (e.g. typed url,
650     // history navigation). We don't want to trigger saving in these cases.
651     content::DocumentState* document_state =
652         content::DocumentState::FromDataSource(
653             frame->provisionalDataSource());
654     content::NavigationState* navigation_state =
655         document_state->navigation_state();
656     if (content::PageTransitionIsWebTriggerable(
657             navigation_state->transition_type()) &&
658         !blink::WebUserGestureIndicator::isProcessingUserGesture()) {
659       // If onsubmit has been called, try and save that form.
660       if (provisionally_saved_forms_[form_frame].get()) {
661         if (logger) {
662           logger->LogPasswordForm(
663               Logger::STRING_PROVISIONALLY_SAVED_FORM_FOR_FRAME,
664               *provisionally_saved_forms_[form_frame]);
665         }
666         Send(new AutofillHostMsg_PasswordFormSubmitted(
667             routing_id(), *provisionally_saved_forms_[form_frame]));
668         provisionally_saved_forms_.erase(form_frame);
669       } else {
670         // Loop through the forms on the page looking for one that has been
671         // filled out. If one exists, try and save the credentials.
672         blink::WebVector<blink::WebFormElement> forms;
673         frame->document().forms(forms);
674
675         bool password_forms_found = false;
676         for (size_t i = 0; i < forms.size(); ++i) {
677           blink::WebFormElement form_element = forms[i];
678           if (logger) {
679             LogHTMLForm(
680                 logger.get(), Logger::STRING_FORM_FOUND_ON_PAGE, form_element);
681           }
682           scoped_ptr<PasswordForm> password_form(
683               CreatePasswordForm(form_element));
684           if (password_form.get() && !password_form->username_value.empty() &&
685               !password_form->password_value.empty() &&
686               !PasswordValueIsDefault(*password_form, form_element)) {
687             password_forms_found = true;
688             if (logger) {
689               logger->LogPasswordForm(
690                   Logger::STRING_PASSWORD_FORM_FOUND_ON_PAGE, *password_form);
691             }
692             Send(new AutofillHostMsg_PasswordFormSubmitted(routing_id(),
693                                                            *password_form));
694           }
695         }
696         if (!password_forms_found && logger) {
697           logger->LogMessage(Logger::STRING_DECISION_DROP);
698         }
699       }
700     }
701     // Clear the whole map during main frame navigation.
702     provisionally_saved_forms_.clear();
703
704     // This is a new navigation, so require a new user gesture before filling in
705     // passwords.
706     gatekeeper_.Reset();
707   } else {
708     if (logger)
709       logger->LogMessage(Logger::STRING_DECISION_DROP);
710   }
711 }
712
713 void PasswordAutofillAgent::OnFillPasswordForm(
714     const PasswordFormFillData& form_data) {
715   if (usernames_usage_ == NOTHING_TO_AUTOFILL) {
716     if (form_data.other_possible_usernames.size())
717       usernames_usage_ = OTHER_POSSIBLE_USERNAMES_PRESENT;
718     else if (usernames_usage_ == NOTHING_TO_AUTOFILL)
719       usernames_usage_ = OTHER_POSSIBLE_USERNAMES_ABSENT;
720   }
721
722   FormElementsList forms;
723   // We own the FormElements* in forms.
724   FindFormElements(render_view()->GetWebView(), form_data.basic_data, &forms);
725   FormElementsList::iterator iter;
726   for (iter = forms.begin(); iter != forms.end(); ++iter) {
727     scoped_ptr<FormElements> form_elements(*iter);
728
729     // Attach autocomplete listener to enable selecting alternate logins.
730     // First, get pointers to username element.
731     blink::WebInputElement username_element =
732         form_elements->input_elements[form_data.basic_data.fields[0].name];
733
734     // Get pointer to password element. (We currently only support single
735     // password forms).
736     blink::WebInputElement password_element =
737         form_elements->input_elements[form_data.basic_data.fields[1].name];
738
739     // If wait_for_username is true, we don't want to initially fill the form
740     // until the user types in a valid username.
741     if (!form_data.wait_for_username)
742       FillFormOnPasswordRecieved(form_data, username_element, password_element);
743
744     // We might have already filled this form if there are two <form> elements
745     // with identical markup.
746     if (login_to_password_info_.find(username_element) !=
747         login_to_password_info_.end())
748       continue;
749
750     PasswordInfo password_info;
751     password_info.fill_data = form_data;
752     password_info.password_field = password_element;
753     login_to_password_info_[username_element] = password_info;
754
755     FormData form;
756     FormFieldData field;
757     FindFormAndFieldForFormControlElement(
758         username_element, &form, &field, REQUIRE_NONE);
759     Send(new AutofillHostMsg_AddPasswordFormMapping(
760         routing_id(), field, form_data));
761   }
762 }
763
764 void PasswordAutofillAgent::OnChangeLoggingState(bool active) {
765   logging_state_active_ = active;
766 }
767
768 ////////////////////////////////////////////////////////////////////////////////
769 // PasswordAutofillAgent, private:
770
771 void PasswordAutofillAgent::GetSuggestions(
772     const PasswordFormFillData& fill_data,
773     const base::string16& input,
774     std::vector<base::string16>* suggestions,
775     std::vector<base::string16>* realms) {
776   if (StartsWith(fill_data.basic_data.fields[0].value, input, false)) {
777     suggestions->push_back(fill_data.basic_data.fields[0].value);
778     realms->push_back(base::UTF8ToUTF16(fill_data.preferred_realm));
779   }
780
781   for (PasswordFormFillData::LoginCollection::const_iterator iter =
782            fill_data.additional_logins.begin();
783        iter != fill_data.additional_logins.end();
784        ++iter) {
785     if (StartsWith(iter->first, input, false)) {
786       suggestions->push_back(iter->first);
787       realms->push_back(base::UTF8ToUTF16(iter->second.realm));
788     }
789   }
790
791   for (PasswordFormFillData::UsernamesCollection::const_iterator iter =
792            fill_data.other_possible_usernames.begin();
793        iter != fill_data.other_possible_usernames.end();
794        ++iter) {
795     for (size_t i = 0; i < iter->second.size(); ++i) {
796       if (StartsWith(iter->second[i], input, false)) {
797         usernames_usage_ = OTHER_POSSIBLE_USERNAME_SHOWN;
798         suggestions->push_back(iter->second[i]);
799         realms->push_back(base::UTF8ToUTF16(iter->first.realm));
800       }
801     }
802   }
803 }
804
805 bool PasswordAutofillAgent::ShowSuggestionPopup(
806     const PasswordFormFillData& fill_data,
807     const blink::WebInputElement& user_input) {
808   blink::WebFrame* frame = user_input.document().frame();
809   if (!frame)
810     return false;
811
812   blink::WebView* webview = frame->view();
813   if (!webview)
814     return false;
815
816   std::vector<base::string16> suggestions;
817   std::vector<base::string16> realms;
818   GetSuggestions(fill_data, user_input.value(), &suggestions, &realms);
819   DCHECK_EQ(suggestions.size(), realms.size());
820
821   FormData form;
822   FormFieldData field;
823   FindFormAndFieldForFormControlElement(
824       user_input, &form, &field, REQUIRE_NONE);
825
826   blink::WebInputElement selected_element = user_input;
827   gfx::Rect bounding_box(selected_element.boundsInViewportSpace());
828
829   float scale = web_view_->pageScaleFactor();
830   gfx::RectF bounding_box_scaled(bounding_box.x() * scale,
831                                  bounding_box.y() * scale,
832                                  bounding_box.width() * scale,
833                                  bounding_box.height() * scale);
834   Send(new AutofillHostMsg_ShowPasswordSuggestions(
835       routing_id(), field, bounding_box_scaled, suggestions, realms));
836   return !suggestions.empty();
837 }
838
839 void PasswordAutofillAgent::FillFormOnPasswordRecieved(
840     const PasswordFormFillData& fill_data,
841     blink::WebInputElement username_element,
842     blink::WebInputElement password_element) {
843   // Do not fill if the password field is in an iframe.
844   DCHECK(password_element.document().frame());
845   if (password_element.document().frame()->parent())
846     return;
847
848   if (!ShouldIgnoreAutocompleteOffForPasswordFields() &&
849       !username_element.form().autoComplete())
850     return;
851
852   // If we can't modify the password, don't try to set the username
853   if (!IsElementAutocompletable(password_element))
854     return;
855
856   // Try to set the username to the preferred name, but only if the field
857   // can be set and isn't prefilled.
858   if (IsElementAutocompletable(username_element) &&
859       username_element.value().isEmpty()) {
860     // TODO(tkent): Check maxlength and pattern.
861     username_element.setValue(fill_data.basic_data.fields[0].value, true);
862   }
863
864   // Fill if we have an exact match for the username. Note that this sets
865   // username to autofilled.
866   FillUserNameAndPassword(&username_element,
867                           &password_element,
868                           fill_data,
869                           true /* exact_username_match */,
870                           false /* set_selection */);
871 }
872
873 bool PasswordAutofillAgent::FillUserNameAndPassword(
874     blink::WebInputElement* username_element,
875     blink::WebInputElement* password_element,
876     const PasswordFormFillData& fill_data,
877     bool exact_username_match,
878     bool set_selection) {
879   base::string16 current_username = username_element->value();
880   // username and password will contain the match found if any.
881   base::string16 username;
882   base::string16 password;
883
884   // Look for any suitable matches to current field text.
885   if (DoUsernamesMatch(fill_data.basic_data.fields[0].value,
886                        current_username,
887                        exact_username_match)) {
888     username = fill_data.basic_data.fields[0].value;
889     password = fill_data.basic_data.fields[1].value;
890   } else {
891     // Scan additional logins for a match.
892     PasswordFormFillData::LoginCollection::const_iterator iter;
893     for (iter = fill_data.additional_logins.begin();
894          iter != fill_data.additional_logins.end();
895          ++iter) {
896       if (DoUsernamesMatch(
897               iter->first, current_username, exact_username_match)) {
898         username = iter->first;
899         password = iter->second.password;
900         break;
901       }
902     }
903
904     // Check possible usernames.
905     if (username.empty() && password.empty()) {
906       for (PasswordFormFillData::UsernamesCollection::const_iterator iter =
907                fill_data.other_possible_usernames.begin();
908            iter != fill_data.other_possible_usernames.end();
909            ++iter) {
910         for (size_t i = 0; i < iter->second.size(); ++i) {
911           if (DoUsernamesMatch(
912                   iter->second[i], current_username, exact_username_match)) {
913             usernames_usage_ = OTHER_POSSIBLE_USERNAME_SELECTED;
914             username = iter->second[i];
915             password = iter->first.password;
916             break;
917           }
918         }
919         if (!username.empty() && !password.empty())
920           break;
921       }
922     }
923   }
924   if (password.empty())
925     return false;  // No match was found.
926
927   // TODO(tkent): Check maxlength and pattern for both username and password
928   // fields.
929
930   // Don't fill username if password can't be set.
931   if (!IsElementAutocompletable(*password_element)) {
932     return false;
933   }
934
935   // Input matches the username, fill in required values.
936   if (IsElementAutocompletable(*username_element)) {
937     username_element->setValue(username, true);
938     username_element->setAutofilled(true);
939
940     if (set_selection) {
941       username_element->setSelectionRange(current_username.length(),
942                                           username.length());
943     }
944   } else if (current_username != username) {
945     // If the username can't be filled and it doesn't match a saved password
946     // as is, don't autofill a password.
947     return false;
948   }
949
950   // Wait to fill in the password until a user gesture occurs. This is to make
951   // sure that we do not fill in the DOM with a password until we believe the
952   // user is intentionally interacting with the page.
953   password_element->setSuggestedValue(password);
954   gatekeeper_.RegisterElement(password_element);
955
956   password_element->setAutofilled(true);
957   return true;
958 }
959
960 void PasswordAutofillAgent::PerformInlineAutocomplete(
961     const blink::WebInputElement& username_input,
962     const blink::WebInputElement& password_input,
963     const PasswordFormFillData& fill_data) {
964   DCHECK(!fill_data.wait_for_username);
965
966   // We need non-const versions of the username and password inputs.
967   blink::WebInputElement username = username_input;
968   blink::WebInputElement password = password_input;
969
970   // Don't inline autocomplete if the caret is not at the end.
971   // TODO(jcivelli): is there a better way to test the caret location?
972   if (username.selectionStart() != username.selectionEnd() ||
973       username.selectionEnd() != static_cast<int>(username.value().length())) {
974     return;
975   }
976
977   // Show the popup with the list of available usernames.
978   ShowSuggestionPopup(fill_data, username);
979
980 #if !defined(OS_ANDROID)
981   // Fill the user and password field with the most relevant match. Android
982   // only fills in the fields after the user clicks on the suggestion popup.
983   FillUserNameAndPassword(&username,
984                           &password,
985                           fill_data,
986                           false /* exact_username_match */,
987                           true /* set_selection */);
988 #endif
989 }
990
991 void PasswordAutofillAgent::FrameClosing(const blink::WebFrame* frame) {
992   for (LoginToPasswordInfoMap::iterator iter = login_to_password_info_.begin();
993        iter != login_to_password_info_.end();) {
994     if (iter->first.document().frame() == frame)
995       login_to_password_info_.erase(iter++);
996     else
997       ++iter;
998   }
999   for (FrameToPasswordFormMap::iterator iter =
1000            provisionally_saved_forms_.begin();
1001        iter != provisionally_saved_forms_.end();) {
1002     if (iter->first == frame)
1003       provisionally_saved_forms_.erase(iter++);
1004     else
1005       ++iter;
1006   }
1007 }
1008
1009 bool PasswordAutofillAgent::FindLoginInfo(const blink::WebNode& node,
1010                                           blink::WebInputElement* found_input,
1011                                           PasswordInfo* found_password) {
1012   if (!node.isElementNode())
1013     return false;
1014
1015   blink::WebElement element = node.toConst<blink::WebElement>();
1016   if (!element.hasTagName("input"))
1017     return false;
1018
1019   blink::WebInputElement input = element.to<blink::WebInputElement>();
1020   LoginToPasswordInfoMap::iterator iter = login_to_password_info_.find(input);
1021   if (iter == login_to_password_info_.end())
1022     return false;
1023
1024   *found_input = input;
1025   *found_password = iter->second;
1026   return true;
1027 }
1028
1029 }  // namespace autofill