Home | History | Annotate | Download | only in autofill
      1 // Copyright (c) 2011 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 "chrome/browser/autofill/autofill_download.h"
      6 
      7 #include <algorithm>
      8 #include <ostream>
      9 #include <vector>
     10 
     11 #ifdef ANDROID
     12 #include "android/jni/autofill_request_url.h"
     13 #endif
     14 #include "base/logging.h"
     15 #include "base/rand_util.h"
     16 #include "base/stl_util-inl.h"
     17 #include "base/string_util.h"
     18 #include "chrome/browser/autofill/autofill_metrics.h"
     19 #include "chrome/browser/autofill/autofill_xml_parser.h"
     20 #include "chrome/browser/autofill/form_structure.h"
     21 #include "chrome/browser/prefs/pref_service.h"
     22 #include "chrome/browser/profiles/profile.h"
     23 #include "chrome/common/pref_names.h"
     24 #include "googleurl/src/gurl.h"
     25 #include "net/http/http_response_headers.h"
     26 #include "third_party/libjingle/source/talk/xmllite/xmlparser.h"
     27 
     28 #define AUTO_FILL_QUERY_SERVER_REQUEST_URL \
     29     "http://toolbarqueries.clients.google.com:80/tbproxy/af/query"
     30 #define AUTO_FILL_UPLOAD_SERVER_REQUEST_URL \
     31     "http://toolbarqueries.clients.google.com:80/tbproxy/af/upload"
     32 #define AUTO_FILL_QUERY_SERVER_NAME_START_IN_HEADER "GFE/"
     33 
     34 namespace {
     35 const size_t kMaxFormCacheSize = 16;
     36 };
     37 
     38 struct AutofillDownloadManager::FormRequestData {
     39   std::vector<std::string> form_signatures;
     40   AutofillRequestType request_type;
     41 };
     42 
     43 #ifdef ANDROID
     44 // Taken from autofill_manager.cc
     45 const double kAutoFillPositiveUploadRateDefaultValue = 0.01;
     46 const double kAutoFillNegativeUploadRateDefaultValue = 0.01;
     47 #endif
     48 
     49 AutofillDownloadManager::AutofillDownloadManager(Profile* profile)
     50     : profile_(profile),
     51       observer_(NULL),
     52       max_form_cache_size_(kMaxFormCacheSize),
     53       next_query_request_(base::Time::Now()),
     54       next_upload_request_(base::Time::Now()),
     55       positive_upload_rate_(0),
     56       negative_upload_rate_(0),
     57       fetcher_id_for_unittest_(0) {
     58   // |profile_| could be NULL in some unit-tests.
     59 #ifdef ANDROID
     60   positive_upload_rate_ = kAutoFillPositiveUploadRateDefaultValue;
     61   negative_upload_rate_ = kAutoFillNegativeUploadRateDefaultValue;
     62 #else
     63   if (profile_) {
     64     PrefService* preferences = profile_->GetPrefs();
     65     positive_upload_rate_ =
     66         preferences->GetDouble(prefs::kAutofillPositiveUploadRate);
     67     negative_upload_rate_ =
     68         preferences->GetDouble(prefs::kAutofillNegativeUploadRate);
     69   }
     70 #endif
     71 }
     72 
     73 AutofillDownloadManager::~AutofillDownloadManager() {
     74   STLDeleteContainerPairFirstPointers(url_fetchers_.begin(),
     75                                       url_fetchers_.end());
     76 }
     77 
     78 void AutofillDownloadManager::SetObserver(
     79     AutofillDownloadManager::Observer *observer) {
     80   if (observer) {
     81     DCHECK(!observer_);
     82     observer_ = observer;
     83   } else {
     84     observer_ = NULL;
     85   }
     86 }
     87 
     88 bool AutofillDownloadManager::StartQueryRequest(
     89     const ScopedVector<FormStructure>& forms,
     90     const AutofillMetrics& metric_logger) {
     91   if (next_query_request_ > base::Time::Now()) {
     92     // We are in back-off mode: do not do the request.
     93     return false;
     94   }
     95   std::string form_xml;
     96   FormRequestData request_data;
     97   if (!FormStructure::EncodeQueryRequest(forms, &request_data.form_signatures,
     98                                          &form_xml)) {
     99     return false;
    100   }
    101 
    102   request_data.request_type = AutofillDownloadManager::REQUEST_QUERY;
    103   metric_logger.Log(AutofillMetrics::QUERY_SENT);
    104 
    105   std::string query_data;
    106   if (CheckCacheForQueryRequest(request_data.form_signatures, &query_data)) {
    107     VLOG(1) << "AutofillDownloadManager: query request has been retrieved from"
    108             << "the cache";
    109     if (observer_)
    110       observer_->OnLoadedAutofillHeuristics(query_data);
    111     return true;
    112   }
    113 
    114   return StartRequest(form_xml, request_data);
    115 }
    116 
    117 bool AutofillDownloadManager::StartUploadRequest(
    118     const FormStructure& form, bool form_was_matched) {
    119   if (next_upload_request_ > base::Time::Now()) {
    120     // We are in back-off mode: do not do the request.
    121     return false;
    122   }
    123 
    124   // Check if we need to upload form.
    125   double upload_rate = form_was_matched ? GetPositiveUploadRate() :
    126                                           GetNegativeUploadRate();
    127   if (base::RandDouble() > upload_rate) {
    128     VLOG(1) << "AutofillDownloadManager: Upload request is ignored";
    129     // If we ever need notification that upload was skipped, add it here.
    130     return false;
    131   }
    132   std::string form_xml;
    133   if (!form.EncodeUploadRequest(form_was_matched, &form_xml))
    134     return false;
    135 
    136   FormRequestData request_data;
    137   request_data.form_signatures.push_back(form.FormSignature());
    138   request_data.request_type = AutofillDownloadManager::REQUEST_UPLOAD;
    139 
    140   return StartRequest(form_xml, request_data);
    141 }
    142 
    143 bool AutofillDownloadManager::CancelRequest(
    144     const std::string& form_signature,
    145     AutofillDownloadManager::AutofillRequestType request_type) {
    146   for (std::map<URLFetcher *, FormRequestData>::iterator it =
    147        url_fetchers_.begin();
    148        it != url_fetchers_.end();
    149        ++it) {
    150     if (std::find(it->second.form_signatures.begin(),
    151         it->second.form_signatures.end(), form_signature) !=
    152         it->second.form_signatures.end() &&
    153         it->second.request_type == request_type) {
    154       delete it->first;
    155       url_fetchers_.erase(it);
    156       return true;
    157     }
    158   }
    159   return false;
    160 }
    161 
    162 double AutofillDownloadManager::GetPositiveUploadRate() const {
    163   return positive_upload_rate_;
    164 }
    165 
    166 double AutofillDownloadManager::GetNegativeUploadRate() const {
    167   return negative_upload_rate_;
    168 }
    169 
    170 void AutofillDownloadManager::SetPositiveUploadRate(double rate) {
    171   if (rate == positive_upload_rate_)
    172     return;
    173   positive_upload_rate_ = rate;
    174   DCHECK_GE(rate, 0.0);
    175   DCHECK_LE(rate, 1.0);
    176   DCHECK(profile_);
    177 #ifndef ANDROID
    178   PrefService* preferences = profile_->GetPrefs();
    179   preferences->SetDouble(prefs::kAutofillPositiveUploadRate, rate);
    180 #endif
    181 }
    182 
    183 void AutofillDownloadManager::SetNegativeUploadRate(double rate) {
    184   if (rate == negative_upload_rate_)
    185     return;
    186   negative_upload_rate_ = rate;
    187   DCHECK_GE(rate, 0.0);
    188   DCHECK_LE(rate, 1.0);
    189   DCHECK(profile_);
    190 #ifndef ANDROID
    191   PrefService* preferences = profile_->GetPrefs();
    192   preferences->SetDouble(prefs::kAutofillNegativeUploadRate, rate);
    193 #endif
    194 }
    195 
    196 bool AutofillDownloadManager::StartRequest(
    197     const std::string& form_xml,
    198     const FormRequestData& request_data) {
    199   net::URLRequestContextGetter* request_context =
    200 #ifdef ANDROID
    201       // On Android, use the webview request context getter which was passed
    202       // through in the WebAutoFill::init() method in WebKit.
    203       profile_->GetRequestContext();
    204 #else
    205       Profile::GetDefaultRequestContext();
    206 #endif
    207   // Check if default request context is NULL: this very rarely happens,
    208   // I think, this could happen only if user opens chrome with some pages
    209   // loading the forms immediately; I cannot reproduce this even in that
    210   // scenario, but bug 74492 shows it happened at least once. In that case bail
    211   // out and fall back on our own heuristics.
    212   if (!request_context)
    213     return false;
    214   std::string request_url;
    215   if (request_data.request_type == AutofillDownloadManager::REQUEST_QUERY)
    216     request_url = AUTO_FILL_QUERY_SERVER_REQUEST_URL;
    217   else
    218     request_url = AUTO_FILL_UPLOAD_SERVER_REQUEST_URL;
    219 
    220 #ifdef ANDROID
    221   if (request_data.request_type == AutofillDownloadManager::REQUEST_QUERY) {
    222     // Ask the platform what URL to use for Autofill. If the
    223     // platform doesn't know, bail and rely on the heuristics
    224     // we've gathered.
    225     request_url = android::AutofillRequestUrl::GetQueryUrl();
    226     if (request_url.empty())
    227       return false;
    228   }
    229 #endif
    230 
    231   // Id is ignored for regular chrome, in unit test id's for fake fetcher
    232   // factory will be 0, 1, 2, ...
    233   URLFetcher *fetcher = URLFetcher::Create(fetcher_id_for_unittest_++,
    234                                            GURL(request_url),
    235                                            URLFetcher::POST,
    236                                            this);
    237   url_fetchers_[fetcher] = request_data;
    238   fetcher->set_automatically_retry_on_5xx(false);
    239   fetcher->set_request_context(request_context);
    240   fetcher->set_upload_data("text/plain", form_xml);
    241   fetcher->Start();
    242   return true;
    243 }
    244 
    245 void AutofillDownloadManager::CacheQueryRequest(
    246     const std::vector<std::string>& forms_in_query,
    247     const std::string& query_data) {
    248   std::string signature = GetCombinedSignature(forms_in_query);
    249   for (QueryRequestCache::iterator it = cached_forms_.begin();
    250        it != cached_forms_.end(); ++it) {
    251     if (it->first == signature) {
    252       // We hit the cache, move to the first position and return.
    253       std::pair<std::string, std::string> data = *it;
    254       cached_forms_.erase(it);
    255       cached_forms_.push_front(data);
    256       return;
    257     }
    258   }
    259   std::pair<std::string, std::string> data;
    260   data.first = signature;
    261   data.second = query_data;
    262   cached_forms_.push_front(data);
    263   while (cached_forms_.size() > max_form_cache_size_)
    264     cached_forms_.pop_back();
    265 }
    266 
    267 bool AutofillDownloadManager::CheckCacheForQueryRequest(
    268     const std::vector<std::string>& forms_in_query,
    269     std::string* query_data) const {
    270   std::string signature = GetCombinedSignature(forms_in_query);
    271   for (QueryRequestCache::const_iterator it = cached_forms_.begin();
    272        it != cached_forms_.end(); ++it) {
    273     if (it->first == signature) {
    274       // We hit the cache, fill the data and return.
    275       *query_data = it->second;
    276       return true;
    277     }
    278   }
    279   return false;
    280 }
    281 
    282 std::string AutofillDownloadManager::GetCombinedSignature(
    283     const std::vector<std::string>& forms_in_query) const {
    284   size_t total_size = forms_in_query.size();
    285   for (size_t i = 0; i < forms_in_query.size(); ++i)
    286     total_size += forms_in_query[i].length();
    287   std::string signature;
    288 
    289   signature.reserve(total_size);
    290 
    291   for (size_t i = 0; i < forms_in_query.size(); ++i) {
    292     if (i)
    293       signature.append(",");
    294     signature.append(forms_in_query[i]);
    295   }
    296   return signature;
    297 }
    298 
    299 void AutofillDownloadManager::OnURLFetchComplete(
    300     const URLFetcher* source,
    301     const GURL& url,
    302     const net::URLRequestStatus& status,
    303     int response_code,
    304     const ResponseCookies& cookies,
    305     const std::string& data) {
    306   std::map<URLFetcher *, FormRequestData>::iterator it =
    307       url_fetchers_.find(const_cast<URLFetcher*>(source));
    308   if (it == url_fetchers_.end()) {
    309     // Looks like crash on Mac is possibly caused with callback entering here
    310     // with unknown fetcher when network is refreshed.
    311     return;
    312   }
    313   std::string type_of_request(
    314       it->second.request_type == AutofillDownloadManager::REQUEST_QUERY ?
    315           "query" : "upload");
    316   const int kHttpResponseOk = 200;
    317   const int kHttpInternalServerError = 500;
    318   const int kHttpBadGateway = 502;
    319   const int kHttpServiceUnavailable = 503;
    320 
    321   CHECK(it->second.form_signatures.size());
    322   if (response_code != kHttpResponseOk) {
    323     bool back_off = false;
    324     std::string server_header;
    325     switch (response_code) {
    326       case kHttpBadGateway:
    327         if (!source->response_headers()->EnumerateHeader(NULL, "server",
    328                                                          &server_header) ||
    329             StartsWithASCII(server_header.c_str(),
    330                             AUTO_FILL_QUERY_SERVER_NAME_START_IN_HEADER,
    331                             false) != 0)
    332           break;
    333         // Bad gateway was received from Autofill servers. Fall through to back
    334         // off.
    335       case kHttpInternalServerError:
    336       case kHttpServiceUnavailable:
    337         back_off = true;
    338         break;
    339     }
    340 
    341     if (back_off) {
    342       base::Time back_off_time(base::Time::Now() + source->backoff_delay());
    343       if (it->second.request_type == AutofillDownloadManager::REQUEST_QUERY) {
    344         next_query_request_ = back_off_time;
    345       } else {
    346         next_upload_request_ = back_off_time;
    347       }
    348     }
    349 
    350     LOG(WARNING) << "AutofillDownloadManager: " << type_of_request
    351                  << " request has failed with response " << response_code;
    352     if (observer_) {
    353       observer_->OnHeuristicsRequestError(it->second.form_signatures[0],
    354                                           it->second.request_type,
    355                                           response_code);
    356     }
    357   } else {
    358     VLOG(1) << "AutofillDownloadManager: " << type_of_request
    359             << " request has succeeded";
    360     if (it->second.request_type == AutofillDownloadManager::REQUEST_QUERY) {
    361       CacheQueryRequest(it->second.form_signatures, data);
    362       if (observer_)
    363         observer_->OnLoadedAutofillHeuristics(data);
    364     } else {
    365       double new_positive_upload_rate = 0;
    366       double new_negative_upload_rate = 0;
    367       AutofillUploadXmlParser parse_handler(&new_positive_upload_rate,
    368                                             &new_negative_upload_rate);
    369       buzz::XmlParser parser(&parse_handler);
    370       parser.Parse(data.data(), data.length(), true);
    371       if (parse_handler.succeeded()) {
    372         SetPositiveUploadRate(new_positive_upload_rate);
    373         SetNegativeUploadRate(new_negative_upload_rate);
    374       }
    375 
    376       if (observer_)
    377         observer_->OnUploadedAutofillHeuristics(it->second.form_signatures[0]);
    378     }
    379   }
    380   delete it->first;
    381   url_fetchers_.erase(it);
    382 }
    383