172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "build/build_config.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/search_engines/template_url_fetcher.h"
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
9731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "base/string_number_conversions.h"
10731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "base/utf_string_conversions.h"
1121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile.h"
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/search_engines/template_url.h"
13731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "chrome/browser/search_engines/template_url_fetcher_callbacks.h"
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/search_engines/template_url_model.h"
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/search_engines/template_url_parser.h"
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/net/url_fetcher.h"
17ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_observer.h"
18ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_registrar.h"
19ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_source.h"
20ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_type.h"
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/url_request/url_request_status.h"
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// RequestDelegate ------------------------------------------------------------
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass TemplateURLFetcher::RequestDelegate : public URLFetcher::Delegate,
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                            public NotificationObserver {
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
27731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // Takes ownership of |callbacks|.
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  RequestDelegate(TemplateURLFetcher* fetcher,
2972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                  const string16& keyword,
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                  const GURL& osdd_url,
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                  const GURL& favicon_url,
32731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                  TemplateURLFetcherCallbacks* callbacks,
33731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                  ProviderType provider_type);
34731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
35731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // NotificationObserver:
36731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  virtual void Observe(NotificationType type,
37731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                       const NotificationSource& source,
38731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                       const NotificationDetails& details);
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // URLFetcher::Delegate:
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If data contains a valid OSDD, a TemplateURL is created and added to
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // the TemplateURLModel.
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void OnURLFetchComplete(const URLFetcher* source,
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  const GURL& url,
4572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                  const net::URLRequestStatus& status,
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  int response_code,
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  const ResponseCookies& cookies,
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  const std::string& data);
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // URL of the OSDD.
5172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  GURL url() const { return osdd_url_; }
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Keyword to use.
5472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  string16 keyword() const { return keyword_; }
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
56731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // The type of search provider being fetched.
57731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  ProviderType provider_type() const { return provider_type_; }
58731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
60731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  void AddSearchProvider();
61731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  URLFetcher url_fetcher_;
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TemplateURLFetcher* fetcher_;
64731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  scoped_ptr<TemplateURL> template_url_;
6572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  string16 keyword_;
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const GURL osdd_url_;
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const GURL favicon_url_;
68731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  const ProviderType provider_type_;
69731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  scoped_ptr<TemplateURLFetcherCallbacks> callbacks_;
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Handles registering for our notifications.
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  NotificationRegistrar registrar_;
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DISALLOW_COPY_AND_ASSIGN(RequestDelegate);
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
77731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickTemplateURLFetcher::RequestDelegate::RequestDelegate(
78731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    TemplateURLFetcher* fetcher,
7972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    const string16& keyword,
80731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    const GURL& osdd_url,
81731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    const GURL& favicon_url,
82731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    TemplateURLFetcherCallbacks* callbacks,
83731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    ProviderType provider_type)
84731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    : ALLOW_THIS_IN_INITIALIZER_LIST(url_fetcher_(osdd_url,
85731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                                  URLFetcher::GET, this)),
86731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      fetcher_(fetcher),
87731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      keyword_(keyword),
88731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      osdd_url_(osdd_url),
89731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      favicon_url_(favicon_url),
90731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      provider_type_(provider_type),
91731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      callbacks_(callbacks) {
92731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  TemplateURLModel* model = fetcher_->profile()->GetTemplateURLModel();
93731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(model);  // TemplateURLFetcher::ScheduleDownload verifies this.
94731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
95731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (!model->loaded()) {
96731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // Start the model load and set-up waiting for it.
97731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    registrar_.Add(this,
98731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                   NotificationType::TEMPLATE_URL_MODEL_LOADED,
99731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                   Source<TemplateURLModel>(model));
100731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    model->Load();
101731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
102731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
103731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  url_fetcher_.set_request_context(fetcher->profile()->GetRequestContext());
104731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  url_fetcher_.Start();
105731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
106731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
107731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid TemplateURLFetcher::RequestDelegate::Observe(
108731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    NotificationType type,
109731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    const NotificationSource& source,
110731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    const NotificationDetails& details) {
111731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(type == NotificationType::TEMPLATE_URL_MODEL_LOADED);
112731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
113731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (!template_url_.get())
114731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return;
115731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  AddSearchProvider();
116731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // WARNING: AddSearchProvider deletes us.
117731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TemplateURLFetcher::RequestDelegate::OnURLFetchComplete(
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const URLFetcher* source,
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const GURL& url,
12272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    const net::URLRequestStatus& status,
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int response_code,
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const ResponseCookies& cookies,
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::string& data) {
126731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  template_url_.reset(new TemplateURL());
127731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
128731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // Validation checks.
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Make sure we can still replace the keyword, i.e. the fetch was successful.
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If the OSDD file was loaded HTTP, we also have to check the response_code.
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // For other schemes, e.g. when the OSDD file is bundled with an extension,
132731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // the response_code is not applicable and should be -1. Also, ensure that
133731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // the returned information results in a valid search URL.
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!status.is_success() ||
135731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      ((response_code != -1) && (response_code != 200)) ||
136731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      !TemplateURLParser::Parse(
137731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          reinterpret_cast<const unsigned char*>(data.c_str()),
138731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          data.length(),
139731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          NULL,
140731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          template_url_.get()) ||
141731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      !template_url_->url() || !template_url_->url()->SupportsReplacement()) {
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    fetcher_->RequestCompleted(this);
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // WARNING: RequestCompleted deletes us.
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
147731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // Wait for the model to be loaded before adding the provider.
148731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  TemplateURLModel* model = fetcher_->profile()->GetTemplateURLModel();
149731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (!model->loaded())
150731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return;
151731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  AddSearchProvider();
152731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // WARNING: AddSearchProvider deletes us.
153731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
154731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
155731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid TemplateURLFetcher::RequestDelegate::AddSearchProvider() {
156731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(template_url_.get());
157731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (provider_type_ != AUTODETECTED_PROVIDER || keyword_.empty()) {
158731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // Generate new keyword from URL in OSDD for none autodetected case.
159731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // Previous keyword was generated from URL where OSDD was placed and
160731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // it gives wrong result when OSDD is located on third party site that
161731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // has nothing in common with search engine in OSDD.
162731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    GURL keyword_url(template_url_->url()->url());
16372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    string16 new_keyword = TemplateURLModel::GenerateKeyword(
164731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        keyword_url, false);
165731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (!new_keyword.empty())
166731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      keyword_ = new_keyword;
167731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
168731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  TemplateURLModel* model = fetcher_->profile()->GetTemplateURLModel();
169731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  const TemplateURL* existing_url;
170731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (keyword_.empty() ||
171731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      !model || !model->loaded() ||
172731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      !model->CanReplaceKeyword(keyword_, GURL(template_url_->url()->url()),
173731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                &existing_url)) {
174731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (provider_type_ == AUTODETECTED_PROVIDER || !model || !model->loaded()) {
175731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      fetcher_->RequestCompleted(this);
176731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      // WARNING: RequestCompleted deletes us.
177731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return;
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
179731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
180731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    existing_url = NULL;
181731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
182731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // Try to generate a keyword automatically when we are setting the default
183731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // provider. The keyword isn't as important in this case.
184731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (provider_type_ == EXPLICIT_DEFAULT_PROVIDER) {
185731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      // The loop numbers are arbitrary and are simply a strong effort.
18672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      string16 new_keyword;
187731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      for (int i = 0; i < 100; ++i) {
188731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        // Concatenate a number at end of the keyword and try that.
189731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        new_keyword = keyword_;
190731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        // Try the keyword alone the first time
191731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        if (i > 0)
19272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          new_keyword.append(base::IntToString16(i));
193731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        if (!model->GetTemplateURLForKeyword(new_keyword) ||
194731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick            model->CanReplaceKeyword(new_keyword,
195731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                     GURL(template_url_->url()->url()),
196731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                     &existing_url)) {
197731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          break;
198731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        }
199731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        new_keyword.clear();
200731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        existing_url = NULL;
201731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      }
202731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
203731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      if (new_keyword.empty()) {
204731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        // A keyword could not be found. This user must have a lot of numerical
205731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        // keywords built up.
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        fetcher_->RequestCompleted(this);
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // WARNING: RequestCompleted deletes us.
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return;
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
210731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      keyword_ = new_keyword;
211731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    } else {
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // If we're coming from JS (neither autodetected nor failure to load the
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // template URL model) and this URL already exists in the model, we bring
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // up the EditKeywordController to edit it.  This is helpful feedback in
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // the case of clicking a button twice, and annoying in the case of a
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // page that calls AddSearchProvider() in JS without a user action.
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      keyword_.clear();
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
219731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
221731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (existing_url)
222731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    model->Remove(existing_url);
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
224731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // The short name is what is shown to the user. We preserve original names
225731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // since it is better when generated keyword in many cases.
226731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  template_url_->set_keyword(keyword_);
227731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  template_url_->set_originating_url(osdd_url_);
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
229731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // The page may have specified a URL to use for favicons, if not, set it.
230ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!template_url_->GetFaviconURL().is_valid())
231ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    template_url_->SetFaviconURL(favicon_url_);
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
233731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  switch (provider_type_) {
234731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    case AUTODETECTED_PROVIDER:
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Mark the keyword as replaceable so it can be removed if necessary.
236731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      template_url_->set_safe_for_autoreplace(true);
237731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      model->Add(template_url_.release());
238731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      break;
239731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
240731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    case EXPLICIT_PROVIDER:
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Confirm addition and allow user to edit default choices. It's ironic
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // that only *non*-autodetected additions get confirmed, but the user
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // expects feedback that his action did something.
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // The source TabContents' delegate takes care of adding the URL to the
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // model, which takes ownership, or of deleting it if the add is
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // cancelled.
247731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      callbacks_->ConfirmAddSearchProvider(template_url_.release(),
248731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                           fetcher_->profile());
249731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      break;
250731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
251731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    case EXPLICIT_DEFAULT_PROVIDER:
252731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      callbacks_->ConfirmSetDefaultSearchProvider(template_url_.release(),
253731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                                  model);
254731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      break;
255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
256731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  fetcher_->RequestCompleted(this);
258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // WARNING: RequestCompleted deletes us.
259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// TemplateURLFetcher ---------------------------------------------------------
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
263c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTemplateURLFetcher::TemplateURLFetcher(Profile* profile) : profile_(profile) {
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(profile_);
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTemplateURLFetcher::~TemplateURLFetcher() {
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
270731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid TemplateURLFetcher::ScheduleDownload(
27172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    const string16& keyword,
272731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    const GURL& osdd_url,
273731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    const GURL& favicon_url,
274731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    TemplateURLFetcherCallbacks* callbacks,
275731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    ProviderType provider_type) {
276731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(osdd_url.is_valid());
277731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  scoped_ptr<TemplateURLFetcherCallbacks> owned_callbacks(callbacks);
278731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
279731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // For JS added OSDD empty keyword is OK because we will generate keyword
280731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // later from OSDD content.
281731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (provider_type == TemplateURLFetcher::AUTODETECTED_PROVIDER &&
282731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      keyword.empty())
283731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return;
284731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  TemplateURLModel* url_model = profile()->GetTemplateURLModel();
285731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (!url_model)
286731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return;
287731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
288731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // Avoid certain checks for the default provider because we'll do the load
289731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // and try to brute force a unique keyword for it.
290731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (provider_type != TemplateURLFetcher::EXPLICIT_DEFAULT_PROVIDER) {
291731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (!url_model->loaded()) {
292731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      url_model->Load();
293731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return;
294731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    }
295731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    const TemplateURL* template_url =
296731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        url_model->GetTemplateURLForKeyword(keyword);
297731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (template_url && (!template_url->safe_for_autoreplace() ||
298731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                         template_url->originating_url() == osdd_url)) {
299731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      // Either there is a user created TemplateURL for this keyword, or the
300731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      // keyword has the same OSDD url and we've parsed it.
301731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return;
302731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    }
303731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
304731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Make sure we aren't already downloading this request.
306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (std::vector<RequestDelegate*>::iterator i = requests_->begin();
307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       i != requests_->end(); ++i) {
308731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    bool keyword_or_osdd_match = (*i)->url() == osdd_url ||
309731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        (*i)->keyword() == keyword;
310731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    bool same_type_or_neither_is_default =
311731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        (*i)->provider_type() == provider_type ||
312731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        ((*i)->provider_type() != EXPLICIT_DEFAULT_PROVIDER &&
313731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick         provider_type != EXPLICIT_DEFAULT_PROVIDER);
314731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (keyword_or_osdd_match && same_type_or_neither_is_default)
315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  requests_->push_back(
319731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      new RequestDelegate(this, keyword, osdd_url, favicon_url,
320731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                          owned_callbacks.release(), provider_type));
321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TemplateURLFetcher::RequestCompleted(RequestDelegate* request) {
324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(find(requests_->begin(), requests_->end(), request) !=
325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         requests_->end());
326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  requests_->erase(find(requests_->begin(), requests_->end(), request));
327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  delete request;
328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
329