Roll src/third_party/skia a5783ae:7628967
[chromium-blink-merge.git] / components / search_engines / template_url_fetcher.cc
blob4ff12d0ded197bfb5053735a5e66576ca58ad5aa
1 // Copyright 2014 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.
5 #include "build/build_config.h"
7 #include "components/search_engines/template_url_fetcher.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "components/search_engines/template_url.h"
12 #include "components/search_engines/template_url_parser.h"
13 #include "components/search_engines/template_url_service.h"
14 #include "net/base/load_flags.h"
15 #include "net/url_request/url_fetcher.h"
16 #include "net/url_request/url_fetcher_delegate.h"
17 #include "net/url_request/url_request_context_getter.h"
18 #include "net/url_request/url_request_status.h"
20 // RequestDelegate ------------------------------------------------------------
21 class TemplateURLFetcher::RequestDelegate : public net::URLFetcherDelegate {
22 public:
23 RequestDelegate(
24 TemplateURLFetcher* fetcher,
25 const base::string16& keyword,
26 const GURL& osdd_url,
27 const GURL& favicon_url,
28 const URLFetcherCustomizeCallback& url_fetcher_customize_callback,
29 const ConfirmAddSearchProviderCallback& confirm_add_callback,
30 ProviderType provider_type);
32 // net::URLFetcherDelegate:
33 // If data contains a valid OSDD, a TemplateURL is created and added to
34 // the TemplateURLService.
35 void OnURLFetchComplete(const net::URLFetcher* source) override;
37 // URL of the OSDD.
38 GURL url() const { return osdd_url_; }
40 // Keyword to use.
41 base::string16 keyword() const { return keyword_; }
43 // The type of search provider being fetched.
44 ProviderType provider_type() const { return provider_type_; }
46 private:
47 void OnLoaded();
48 void AddSearchProvider();
50 scoped_ptr<net::URLFetcher> url_fetcher_;
51 TemplateURLFetcher* fetcher_;
52 scoped_ptr<TemplateURL> template_url_;
53 base::string16 keyword_;
54 const GURL osdd_url_;
55 const GURL favicon_url_;
56 const ProviderType provider_type_;
57 ConfirmAddSearchProviderCallback confirm_add_callback_;
59 scoped_ptr<TemplateURLService::Subscription> template_url_subscription_;
61 DISALLOW_COPY_AND_ASSIGN(RequestDelegate);
64 TemplateURLFetcher::RequestDelegate::RequestDelegate(
65 TemplateURLFetcher* fetcher,
66 const base::string16& keyword,
67 const GURL& osdd_url,
68 const GURL& favicon_url,
69 const URLFetcherCustomizeCallback& url_fetcher_customize_callback,
70 const ConfirmAddSearchProviderCallback& confirm_add_callback,
71 ProviderType provider_type)
72 : url_fetcher_(
73 net::URLFetcher::Create(osdd_url, net::URLFetcher::GET, this).Pass()),
74 fetcher_(fetcher),
75 keyword_(keyword),
76 osdd_url_(osdd_url),
77 favicon_url_(favicon_url),
78 provider_type_(provider_type),
79 confirm_add_callback_(confirm_add_callback) {
80 TemplateURLService* model = fetcher_->template_url_service_;
81 DCHECK(model); // TemplateURLFetcher::ScheduleDownload verifies this.
83 if (!model->loaded()) {
84 // Start the model load and set-up waiting for it.
85 template_url_subscription_ = model->RegisterOnLoadedCallback(
86 base::Bind(&TemplateURLFetcher::RequestDelegate::OnLoaded,
87 base::Unretained(this)));
88 model->Load();
91 if (!url_fetcher_customize_callback.is_null())
92 url_fetcher_customize_callback.Run(url_fetcher_.get());
94 url_fetcher_->SetRequestContext(fetcher->request_context_.get());
95 url_fetcher_->Start();
98 void TemplateURLFetcher::RequestDelegate::OnLoaded() {
99 template_url_subscription_.reset();
100 if (!template_url_.get())
101 return;
102 AddSearchProvider();
103 // WARNING: AddSearchProvider deletes us.
106 void TemplateURLFetcher::RequestDelegate::OnURLFetchComplete(
107 const net::URLFetcher* source) {
108 // Validation checks.
109 // Make sure we can still replace the keyword, i.e. the fetch was successful.
110 // If the OSDD file was loaded HTTP, we also have to check the response_code.
111 // For other schemes, e.g. when the OSDD file is bundled with an extension,
112 // the response_code is not applicable and should be -1. Also, ensure that
113 // the returned information results in a valid search URL.
114 std::string data;
115 if (!source->GetStatus().is_success() ||
116 ((source->GetResponseCode() != -1) &&
117 (source->GetResponseCode() != 200)) ||
118 !source->GetResponseAsString(&data)) {
119 fetcher_->RequestCompleted(this);
120 // WARNING: RequestCompleted deletes us.
121 return;
124 template_url_.reset(TemplateURLParser::Parse(
125 fetcher_->template_url_service_->search_terms_data(), false,
126 data.data(), data.length(), NULL));
127 if (!template_url_.get() ||
128 !template_url_->url_ref().SupportsReplacement(
129 fetcher_->template_url_service_->search_terms_data())) {
130 fetcher_->RequestCompleted(this);
131 // WARNING: RequestCompleted deletes us.
132 return;
135 if (provider_type_ != AUTODETECTED_PROVIDER || keyword_.empty()) {
136 // Use the parser-generated new keyword from the URL in the OSDD for the
137 // non-autodetected case. The existing |keyword_| was generated from the
138 // URL that hosted the OSDD, which results in the wrong keyword when the
139 // OSDD was located on a third-party site that has nothing in common with
140 // search engine described by OSDD.
141 keyword_ = template_url_->keyword();
142 DCHECK(!keyword_.empty());
145 // Wait for the model to be loaded before adding the provider.
146 if (!fetcher_->template_url_service_->loaded())
147 return;
148 AddSearchProvider();
149 // WARNING: AddSearchProvider deletes us.
152 void TemplateURLFetcher::RequestDelegate::AddSearchProvider() {
153 DCHECK(template_url_.get());
154 DCHECK(!keyword_.empty());
155 TemplateURLService* model = fetcher_->template_url_service_;
156 DCHECK(model);
157 DCHECK(model->loaded());
159 TemplateURL* existing_url = NULL;
160 if (model->CanAddAutogeneratedKeyword(keyword_, GURL(template_url_->url()),
161 &existing_url)) {
162 if (existing_url)
163 model->Remove(existing_url);
164 } else if (provider_type_ == AUTODETECTED_PROVIDER) {
165 fetcher_->RequestCompleted(this); // WARNING: Deletes us!
166 return;
169 // The short name is what is shown to the user. We preserve original names
170 // since it is better when generated keyword in many cases.
171 TemplateURLData data(template_url_->data());
172 data.SetKeyword(keyword_);
173 data.originating_url = osdd_url_;
175 // The page may have specified a URL to use for favicons, if not, set it.
176 if (!data.favicon_url.is_valid())
177 data.favicon_url = favicon_url_;
179 switch (provider_type_) {
180 case AUTODETECTED_PROVIDER:
181 // Mark the keyword as replaceable so it can be removed if necessary.
182 data.safe_for_autoreplace = true;
183 model->Add(new TemplateURL(data));
184 break;
186 case EXPLICIT_PROVIDER:
187 // Confirm addition and allow user to edit default choices. It's ironic
188 // that only *non*-autodetected additions get confirmed, but the user
189 // expects feedback that his action did something.
190 // The source WebContents' delegate takes care of adding the URL to the
191 // model, which takes ownership, or of deleting it if the add is
192 // cancelled.
193 confirm_add_callback_.Run(make_scoped_ptr(new TemplateURL(data)));
194 break;
196 default:
197 NOTREACHED();
198 break;
201 fetcher_->RequestCompleted(this);
202 // WARNING: RequestCompleted deletes us.
205 // TemplateURLFetcher ---------------------------------------------------------
207 TemplateURLFetcher::TemplateURLFetcher(
208 TemplateURLService* template_url_service,
209 net::URLRequestContextGetter* request_context)
210 : template_url_service_(template_url_service),
211 request_context_(request_context) {
214 TemplateURLFetcher::~TemplateURLFetcher() {
217 void TemplateURLFetcher::ScheduleDownload(
218 const base::string16& keyword,
219 const GURL& osdd_url,
220 const GURL& favicon_url,
221 const URLFetcherCustomizeCallback& url_fetcher_customize_callback,
222 const ConfirmAddSearchProviderCallback& confirm_add_callback,
223 ProviderType provider_type) {
224 DCHECK(osdd_url.is_valid());
226 // For a JS-added OSDD, the provided keyword is irrelevant because we will
227 // generate a keyword later from the OSDD content. For the autodetected case,
228 // we need a valid keyword up front.
229 if (provider_type == TemplateURLFetcher::AUTODETECTED_PROVIDER) {
230 DCHECK(!keyword.empty());
232 if (!template_url_service_->loaded()) {
233 // We could try to set up a callback to this function again once the model
234 // is loaded but since this is an auto-add case anyway, meh.
235 template_url_service_->Load();
236 return;
239 const TemplateURL* template_url =
240 template_url_service_->GetTemplateURLForKeyword(keyword);
241 if (template_url && (!template_url->safe_for_autoreplace() ||
242 template_url->originating_url() == osdd_url))
243 return;
246 // Make sure we aren't already downloading this request.
247 for (Requests::iterator i = requests_.begin(); i != requests_.end(); ++i) {
248 if (((*i)->url() == osdd_url) ||
249 ((provider_type == TemplateURLFetcher::AUTODETECTED_PROVIDER) &&
250 ((*i)->keyword() == keyword)))
251 return;
254 requests_.push_back(new RequestDelegate(
255 this, keyword, osdd_url, favicon_url, url_fetcher_customize_callback,
256 confirm_add_callback, provider_type));
259 void TemplateURLFetcher::RequestCompleted(RequestDelegate* request) {
260 Requests::iterator i =
261 std::find(requests_.begin(), requests_.end(), request);
262 DCHECK(i != requests_.end());
263 requests_.weak_erase(i);
264 delete request;