OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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 "build/build_config.h" | |
6 | |
7 #include "chrome/browser/search_engines/template_url_fetcher.h" | |
8 | |
9 #include "base/strings/string_number_conversions.h" | |
10 #include "base/strings/utf_string_conversions.h" | |
11 #include "chrome/browser/search_engines/template_url_parser.h" | |
12 #include "components/search_engines/template_url.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" | |
19 | |
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); | |
31 | |
32 // net::URLFetcherDelegate: | |
33 // If data contains a valid OSDD, a TemplateURL is created and added to | |
34 // the TemplateURLService. | |
35 virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE; | |
36 | |
37 // URL of the OSDD. | |
38 GURL url() const { return osdd_url_; } | |
39 | |
40 // Keyword to use. | |
41 base::string16 keyword() const { return keyword_; } | |
42 | |
43 // The type of search provider being fetched. | |
44 ProviderType provider_type() const { return provider_type_; } | |
45 | |
46 private: | |
47 void OnLoaded(); | |
48 void AddSearchProvider(); | |
49 | |
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_; | |
58 | |
59 scoped_ptr<TemplateURLService::Subscription> template_url_subscription_; | |
60 | |
61 DISALLOW_COPY_AND_ASSIGN(RequestDelegate); | |
62 }; | |
63 | |
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_(net::URLFetcher::Create( | |
73 osdd_url, net::URLFetcher::GET, this)), | |
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. | |
82 | |
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(); | |
89 } | |
90 | |
91 if (!url_fetcher_customize_callback.is_null()) | |
92 url_fetcher_customize_callback.Run(url_fetcher_.get()); | |
93 | |
94 url_fetcher_->SetRequestContext(fetcher->request_context_.get()); | |
95 url_fetcher_->Start(); | |
96 } | |
97 | |
98 void TemplateURLFetcher::RequestDelegate::OnLoaded() { | |
99 template_url_subscription_.reset(); | |
100 if (!template_url_.get()) | |
101 return; | |
102 AddSearchProvider(); | |
103 // WARNING: AddSearchProvider deletes us. | |
104 } | |
105 | |
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; | |
122 } | |
123 | |
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; | |
133 } | |
134 | |
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()); | |
143 } | |
144 | |
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. | |
150 } | |
151 | |
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()); | |
158 | |
159 TemplateURL* existing_url = NULL; | |
160 if (model->CanReplaceKeyword(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; | |
167 } | |
168 | |
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_; | |
174 | |
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_; | |
178 | |
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; | |
185 | |
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; | |
195 | |
196 default: | |
197 NOTREACHED(); | |
198 break; | |
199 } | |
200 | |
201 fetcher_->RequestCompleted(this); | |
202 // WARNING: RequestCompleted deletes us. | |
203 } | |
204 | |
205 // TemplateURLFetcher --------------------------------------------------------- | |
206 | |
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) { | |
212 } | |
213 | |
214 TemplateURLFetcher::~TemplateURLFetcher() { | |
215 } | |
216 | |
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()); | |
225 | |
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()); | |
231 | |
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; | |
237 } | |
238 | |
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; | |
244 } | |
245 | |
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; | |
252 } | |
253 | |
254 requests_.push_back(new RequestDelegate( | |
255 this, keyword, osdd_url, favicon_url, url_fetcher_customize_callback, | |
256 confirm_add_callback, provider_type)); | |
257 } | |
258 | |
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; | |
265 } | |
OLD | NEW |