1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
|
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "build/build_config.h"
#include "chrome/browser/search_engines/template_url_fetcher.h"
#include "chrome/browser/net/url_fetcher.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/search_engines/template_url_parser.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/notification_source.h"
#include "chrome/common/notification_type.h"
// RequestDelegate ------------------------------------------------------------
class TemplateURLFetcher::RequestDelegate : public URLFetcher::Delegate,
public NotificationObserver {
public:
RequestDelegate(TemplateURLFetcher* fetcher,
const std::wstring& keyword,
const GURL& osdd_url,
const GURL& favicon_url,
TabContents* source,
bool autodetected)
: ALLOW_THIS_IN_INITIALIZER_LIST(url_fetcher_(osdd_url,
URLFetcher::GET, this)),
fetcher_(fetcher),
keyword_(keyword),
osdd_url_(osdd_url),
favicon_url_(favicon_url),
autodetected_(autodetected),
source_(source) {
url_fetcher_.set_request_context(fetcher->profile()->GetRequestContext());
url_fetcher_.Start();
registrar_.Add(this,
NotificationType::TAB_CONTENTS_DESTROYED,
Source<TabContents>(source_));
}
// URLFetcher::Delegate:
// If data contains a valid OSDD, a TemplateURL is created and added to
// the TemplateURLModel.
virtual void OnURLFetchComplete(const URLFetcher* source,
const GURL& url,
const URLRequestStatus& status,
int response_code,
const ResponseCookies& cookies,
const std::string& data);
// NotificationObserver:
virtual void Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
DCHECK(type == NotificationType::TAB_CONTENTS_DESTROYED);
DCHECK(source == Source<TabContents>(source_));
source_ = NULL;
}
// URL of the OSDD.
const GURL& url() const { return osdd_url_; }
// Keyword to use.
const std::wstring keyword() const { return keyword_; }
private:
URLFetcher url_fetcher_;
TemplateURLFetcher* fetcher_;
const std::wstring keyword_;
const GURL osdd_url_;
const GURL favicon_url_;
bool autodetected_;
// The TabContents where this request originated. Can be NULL if the
// originating tab is closed. If NULL, the engine is not added.
TabContents* source_;
// Handles registering for our notifications.
NotificationRegistrar registrar_;
DISALLOW_COPY_AND_ASSIGN(RequestDelegate);
};
void TemplateURLFetcher::RequestDelegate::OnURLFetchComplete(
const URLFetcher* source,
const GURL& url,
const URLRequestStatus& status,
int response_code,
const ResponseCookies& cookies,
const std::string& data) {
// Make sure we can still replace the keyword.
if (response_code != 200) {
fetcher_->RequestCompleted(this);
// WARNING: RequestCompleted deletes us.
return;
}
scoped_ptr<TemplateURL> template_url(new TemplateURL());
if (TemplateURLParser::Parse(
reinterpret_cast<const unsigned char*>(data.c_str()),
data.length(),
NULL,
template_url.get()) &&
template_url->url() && template_url->url()->SupportsReplacement()) {
TemplateURLModel* model = fetcher_->profile()->GetTemplateURLModel();
const TemplateURL* existing_url;
if (!model || !model->loaded() ||
!model->CanReplaceKeyword(keyword_, template_url->url()->url(),
&existing_url)) {
// TODO(pamg): If we're coming from JS (not autodetected) and this URL
// already exists in the model, consider bringing up the
// EditKeywordController to edit it. This would be helpful feedback in
// the case of clicking a button twice, and annoying in the case of a
// page that calls AddSearchProvider() in JS without a user action.
fetcher_->RequestCompleted(this);
// WARNING: RequestCompleted deletes us.
return;
}
if (existing_url)
model->Remove(existing_url);
// The short name is what is shown to the user. We reset it to make sure
// we don't display random text from the web.
template_url->set_short_name(keyword_);
template_url->set_keyword(keyword_);
template_url->set_originating_url(osdd_url_);
// The page may have specified a URL to use for favicons, if not, set it.
if (!template_url->GetFavIconURL().is_valid())
template_url->SetFavIconURL(favicon_url_);
if (autodetected_) {
// Mark the keyword as replaceable so it can be removed if necessary.
template_url->set_safe_for_autoreplace(true);
model->Add(template_url.release());
} else if (source_ && source_->delegate()) {
// Confirm addition and allow user to edit default choices. It's ironic
// that only *non*-autodetected additions get confirmed, but the user
// expects feedback that his action did something.
// The source TabContents' delegate takes care of adding the URL to the
// model, which takes ownership, or of deleting it if the add is
// cancelled.
source_->delegate()->ConfirmAddSearchProvider(template_url.release(),
fetcher_->profile());
}
}
fetcher_->RequestCompleted(this);
// WARNING: RequestCompleted deletes us.
}
// TemplateURLFetcher ---------------------------------------------------------
TemplateURLFetcher::TemplateURLFetcher(Profile* profile) : profile_(profile) {
DCHECK(profile_);
}
TemplateURLFetcher::~TemplateURLFetcher() {
}
void TemplateURLFetcher::ScheduleDownload(const std::wstring& keyword,
const GURL& osdd_url,
const GURL& favicon_url,
TabContents* source,
bool autodetected) {
DCHECK(!keyword.empty() && osdd_url.is_valid());
// Make sure we aren't already downloading this request.
for (std::vector<RequestDelegate*>::iterator i = requests_->begin();
i != requests_->end(); ++i) {
if ((*i)->url() == osdd_url || (*i)->keyword() == keyword)
return;
}
requests_->push_back(
new RequestDelegate(this, keyword, osdd_url, favicon_url, source,
autodetected));
}
void TemplateURLFetcher::RequestCompleted(RequestDelegate* request) {
DCHECK(find(requests_->begin(), requests_->end(), request) !=
requests_->end());
requests_->erase(find(requests_->begin(), requests_->end(), request));
delete request;
}
|