OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/intents/web_intents_registry.h" | 5 #include "chrome/browser/intents/web_intents_registry.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/bind_helpers.h" | 10 #include "base/bind_helpers.h" |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
77 const string16& action, | 77 const string16& action, |
78 IntentServiceList* matching_services) { | 78 IntentServiceList* matching_services) { |
79 const IntentServiceList& services = extension.intents_services(); | 79 const IntentServiceList& services = extension.intents_services(); |
80 for (IntentServiceList::const_iterator i = services.begin(); | 80 for (IntentServiceList::const_iterator i = services.begin(); |
81 i != services.end(); ++i) { | 81 i != services.end(); ++i) { |
82 if (action.empty() || action == i->action) | 82 if (action.empty() || action == i->action) |
83 matching_services->push_back(*i); | 83 matching_services->push_back(*i); |
84 } | 84 } |
85 } | 85 } |
86 | 86 |
87 // Removes all services from |matching_services| that do not match |mimetype|. | 87 // Removes all services from |matching_services| that do not match |type|. |
88 // Wildcards are supported, of the form '<type>/*' or '*'. | 88 // Wildcards are supported, of the form '<type>/*' or '*'. |
89 void FilterServicesByMimetype(const string16& mimetype, | 89 void FilterServicesByType(const string16& type, |
90 IntentServiceList* matching_services) { | 90 IntentServiceList* matching_services) { |
91 // Filter out all services not matching the query type. | 91 // Filter out all services not matching the query type. |
92 IntentServiceList::iterator iter(matching_services->begin()); | 92 IntentServiceList::iterator iter(matching_services->begin()); |
93 while (iter != matching_services->end()) { | 93 while (iter != matching_services->end()) { |
94 if (WebIntentsTypesMatch(iter->type, mimetype)) | 94 if (WebIntentsTypesMatch(iter->type, type)) |
95 ++iter; | 95 ++iter; |
96 else | 96 else |
97 iter = matching_services->erase(iter); | 97 iter = matching_services->erase(iter); |
98 } | 98 } |
99 } | 99 } |
100 | 100 |
101 // Callback for existence checks. Converts a callback for a list of services | 101 // Callback for existence checks. Converts a callback for a list of services |
102 // into a callback that returns true if the list contains a specific service. | 102 // into a callback that returns true if the list contains a specific service. |
103 void ExistenceCallback(const webkit_glue::WebIntentServiceData& service, | 103 void ExistenceCallback(const webkit_glue::WebIntentServiceData& service, |
104 const base::Callback<void(bool)>& callback, | 104 const base::Callback<void(bool)>& callback, |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
144 (lhs.action != rhs.action) || | 144 (lhs.action != rhs.action) || |
145 (lhs.title != rhs.title) || | 145 (lhs.title != rhs.title) || |
146 (lhs.disposition != rhs.disposition)); | 146 (lhs.disposition != rhs.disposition)); |
147 } | 147 } |
148 | 148 |
149 } // namespace | 149 } // namespace |
150 | 150 |
151 using webkit_glue::WebIntentServiceData; | 151 using webkit_glue::WebIntentServiceData; |
152 | 152 |
153 // Internal object representing all data associated with a single query. | 153 // Internal object representing all data associated with a single query. |
154 struct WebIntentsRegistry::IntentsQuery { | 154 struct WebIntentsRegistry::IntentsQuery : public WebDataServiceConsumer { |
| 155 |
| 156 // Handle so we can call back into the WebIntentsRegistry when |
| 157 // processing query results. The registry is guaranteed to be |
| 158 // valid for the life of this object. We do not own this object. |
| 159 WebIntentsRegistry* registry_; |
| 160 |
155 // Underlying data query. | 161 // Underlying data query. |
156 WebDataService::Handle pending_query_; | 162 WebDataService::Handle query_handle_; |
157 | 163 |
158 // The callback for this particular query. | 164 // The callback for this particular query. |
159 QueryCallback callback_; | 165 QueryCallback callback_; |
160 | 166 |
161 // Callback for a query for defaults. | 167 // Callback for a query for defaults. |
162 DefaultQueryCallback default_callback_; | 168 DefaultQueryCallback default_callback_; |
163 | 169 |
164 // The particular action to filter for while searching through extensions. | 170 // The particular action to filter for while searching through extensions. |
165 // If |action_| is empty, return all extension-provided services. | 171 // If |action_| is empty, return all extension-provided services. |
166 string16 action_; | 172 string16 action_; |
167 | 173 |
168 // The MIME type that was requested for this service query. | 174 // The MIME type that was requested for this service query. |
169 // Suppports wild cards. | 175 // Suppports wild cards. |
170 string16 type_; | 176 string16 type_; |
171 | 177 |
172 // The url of the invoking page. | 178 // The url of the invoking page. |
173 GURL url_; | 179 GURL url_; |
174 | 180 |
175 // Create a new IntentsQuery for services with the specified action/type. | 181 // Create a new IntentsQuery for services with the specified action/type. |
176 IntentsQuery(const QueryCallback& callback, | 182 IntentsQuery(WebIntentsRegistry* registry, |
| 183 const QueryCallback& callback, |
177 const string16& action, const string16& type) | 184 const string16& action, const string16& type) |
178 : callback_(callback), action_(action), type_(type) {} | 185 : registry_(registry), callback_(callback), action_(action), |
| 186 type_(type) {} |
179 | 187 |
180 // Create a new IntentsQuery for all intent services or for existence checks. | 188 // Create a new IntentsQuery for all intent services or for existence checks. |
181 explicit IntentsQuery(const QueryCallback callback) | 189 IntentsQuery(WebIntentsRegistry* registry, |
182 : callback_(callback), type_(ASCIIToUTF16("*")) {} | 190 const QueryCallback callback) |
| 191 : registry_(registry), callback_(callback), type_(ASCIIToUTF16("*")) {} |
183 | 192 |
184 // Create a new IntentsQuery for default services. | 193 // Create a new IntentsQuery for default services. |
185 IntentsQuery(const DefaultQueryCallback& callback, | 194 IntentsQuery(WebIntentsRegistry* registry, |
| 195 const DefaultQueryCallback& callback, |
186 const string16& action, const string16& type, const GURL& url) | 196 const string16& action, const string16& type, const GURL& url) |
187 : default_callback_(callback), action_(action), type_(type), url_(url) {} | 197 : registry_(registry), default_callback_(callback), action_(action), |
| 198 type_(type), url_(url) {} |
| 199 |
| 200 void OnWebDataServiceRequestDone( |
| 201 WebDataService::Handle h, |
| 202 const WDTypedResult* result) OVERRIDE { |
| 203 |
| 204 // dispatch the request |
| 205 if (result->GetType() == WEB_INTENTS_RESULT) { |
| 206 registry_->OnWebIntentsResultReceived(this, result); |
| 207 } else if (result->GetType() == WEB_INTENTS_DEFAULTS_RESULT) { |
| 208 registry_->OnWebIntentsDefaultsResultReceived(this, result); |
| 209 } else { |
| 210 NOTREACHED(); |
| 211 } |
| 212 } |
188 }; | 213 }; |
189 | 214 |
190 WebIntentsRegistry::WebIntentsRegistry() {} | 215 WebIntentsRegistry::WebIntentsRegistry() {} |
191 | 216 |
192 WebIntentsRegistry::~WebIntentsRegistry() { | 217 WebIntentsRegistry::~WebIntentsRegistry() { |
| 218 |
193 // Cancel all pending queries, since we can't handle them any more. | 219 // Cancel all pending queries, since we can't handle them any more. |
194 for (QueryMap::iterator it(queries_.begin()); it != queries_.end(); ++it) { | 220 for (QueryVector::iterator it = pending_queries_.begin(); |
195 wds_->CancelRequest(it->first); | 221 it != pending_queries_.end(); ++it) { |
196 delete it->second; | 222 IntentsQuery* query = *it; |
| 223 wds_->CancelRequest(query->query_handle_); |
| 224 delete query; |
197 } | 225 } |
198 } | 226 } |
199 | 227 |
200 void WebIntentsRegistry::Initialize( | 228 void WebIntentsRegistry::Initialize( |
201 scoped_refptr<WebDataService> wds, | 229 scoped_refptr<WebDataService> wds, |
202 ExtensionServiceInterface* extension_service) { | 230 ExtensionServiceInterface* extension_service) { |
203 wds_ = wds; | 231 wds_ = wds; |
204 extension_service_ = extension_service; | 232 extension_service_ = extension_service; |
205 } | 233 } |
206 | 234 |
207 void WebIntentsRegistry::OnWebDataServiceRequestDone( | 235 void WebIntentsRegistry::OnWebIntentsResultReceived( |
208 WebDataService::Handle h, | 236 IntentsQuery* query, |
209 const WDTypedResult* result) { | 237 const WDTypedResult* result) { |
| 238 DCHECK(query); |
210 DCHECK(result); | 239 DCHECK(result); |
211 if (result->GetType() == WEB_INTENTS_DEFAULTS_RESULT) { | |
212 OnWebDataServiceDefaultsRequestDone(h, result); | |
213 return; | |
214 } | |
215 DCHECK(result->GetType() == WEB_INTENTS_RESULT); | 240 DCHECK(result->GetType() == WEB_INTENTS_RESULT); |
216 | 241 |
217 QueryMap::iterator it = queries_.find(h); | 242 ReleaseQuery(query); |
218 DCHECK(it != queries_.end()); | |
219 | |
220 IntentsQuery* query(it->second); | |
221 DCHECK(query); | |
222 queries_.erase(it); | |
223 | 243 |
224 IntentServiceList matching_services = static_cast< | 244 IntentServiceList matching_services = static_cast< |
225 const WDResult<IntentServiceList>*>(result)->GetValue(); | 245 const WDResult<IntentServiceList>*>(result)->GetValue(); |
226 | 246 |
227 // Loop over all services in all extensions, collect ones | 247 // Loop over all services in all extensions, collect ones |
228 // matching the query. | 248 // matching the query. |
229 if (extension_service_) { | 249 if (extension_service_) { |
230 const ExtensionSet* extensions = extension_service_->extensions(); | 250 const ExtensionSet* extensions = extension_service_->extensions(); |
231 if (extensions) { | 251 if (extensions) { |
232 for (ExtensionSet::const_iterator i(extensions->begin()); | 252 for (ExtensionSet::const_iterator i(extensions->begin()); |
233 i != extensions->end(); ++i) { | 253 i != extensions->end(); ++i) { |
234 AddMatchingServicesForExtension(**i, query->action_, | 254 AddMatchingServicesForExtension(**i, query->action_, |
235 &matching_services); | 255 &matching_services); |
236 } | 256 } |
237 } | 257 } |
238 } | 258 } |
239 | 259 |
240 // Filter out all services not matching the query type. | 260 // Filter out all services not matching the query type. |
241 FilterServicesByMimetype(query->type_, &matching_services); | 261 FilterServicesByType(query->type_, &matching_services); |
242 | 262 |
243 // Collapse intents that are equivalent for all but |type|. | 263 // Collapse intents that are equivalent for all but |type|. |
244 CollapseIntents(&matching_services); | 264 CollapseIntents(&matching_services); |
245 | 265 |
246 query->callback_.Run(matching_services); | 266 query->callback_.Run(matching_services); |
247 delete query; | 267 delete query; |
248 } | 268 } |
249 | 269 |
250 const Extension* WebIntentsRegistry::ExtensionForURL(const std::string& url) { | 270 void WebIntentsRegistry::OnWebIntentsDefaultsResultReceived( |
251 const ExtensionSet* extensions = extension_service_->extensions(); | 271 IntentsQuery* query, |
252 if (!extensions) | 272 const WDTypedResult* result) { |
253 return NULL; | 273 DCHECK(query); |
| 274 DCHECK(result); |
| 275 DCHECK(result->GetType() == WEB_INTENTS_DEFAULTS_RESULT); |
254 | 276 |
255 // Use the unsafe ExtensionURLInfo constructor: we don't care if the extension | 277 ReleaseQuery(query); |
256 // is running or not. | |
257 GURL gurl(url); | |
258 ExtensionURLInfo info(gurl); | |
259 return extensions->GetExtensionOrAppByURL(info); | |
260 } | |
261 | |
262 void WebIntentsRegistry::OnWebDataServiceDefaultsRequestDone( | |
263 WebDataService::Handle h, | |
264 const WDTypedResult* result) { | |
265 QueryMap::iterator it = queries_.find(h); | |
266 DCHECK(it != queries_.end()); | |
267 | |
268 IntentsQuery* query(it->second); | |
269 DCHECK(query); | |
270 queries_.erase(it); | |
271 | 278 |
272 std::vector<DefaultWebIntentService> services = static_cast< | 279 std::vector<DefaultWebIntentService> services = static_cast< |
273 const WDResult<std::vector<DefaultWebIntentService> >*>(result)-> | 280 const WDResult<std::vector<DefaultWebIntentService> >*>(result)-> |
274 GetValue(); | 281 GetValue(); |
275 | 282 |
276 DefaultWebIntentService default_service; | 283 DefaultWebIntentService default_service; |
277 std::vector<DefaultWebIntentService>::iterator iter(services.begin()); | 284 std::vector<DefaultWebIntentService>::iterator iter(services.begin()); |
278 for (; iter != services.end(); ++iter) { | 285 for (; iter != services.end(); ++iter) { |
279 if (!WebIntentsTypesMatch(iter->type, query->type_)) { | 286 if (!WebIntentsTypesMatch(iter->type, query->type_)) { |
280 continue; | 287 continue; |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
318 break; | 325 break; |
319 } | 326 } |
320 } | 327 } |
321 } | 328 } |
322 | 329 |
323 query->default_callback_.Run(default_service); | 330 query->default_callback_.Run(default_service); |
324 delete query; | 331 delete query; |
325 } | 332 } |
326 | 333 |
327 void WebIntentsRegistry::GetIntentServices( | 334 void WebIntentsRegistry::GetIntentServices( |
328 const string16& action, const string16& mimetype, | 335 const string16& action, const string16& type, |
329 const QueryCallback& callback) { | 336 const QueryCallback& callback) { |
330 DCHECK(wds_.get()); | 337 DCHECK(wds_.get()); |
331 DCHECK(!callback.is_null()); | 338 DCHECK(!callback.is_null()); |
332 | 339 |
333 IntentsQuery* query = new IntentsQuery(callback, action, mimetype); | 340 IntentsQuery* query = new IntentsQuery(this, callback, action, type); |
334 query->pending_query_ = wds_->GetWebIntentServices(action, this); | 341 query->query_handle_ = wds_->GetWebIntentServices(action, query); |
335 queries_[query->pending_query_] = query; | 342 TrackQuery(query); |
336 } | 343 } |
337 | 344 |
338 void WebIntentsRegistry::GetAllIntentServices( | 345 void WebIntentsRegistry::GetAllIntentServices( |
339 const QueryCallback& callback) { | 346 const QueryCallback& callback) { |
340 DCHECK(wds_.get()); | 347 DCHECK(wds_.get()); |
341 DCHECK(!callback.is_null()); | 348 DCHECK(!callback.is_null()); |
342 | 349 |
343 IntentsQuery* query = new IntentsQuery(callback); | 350 IntentsQuery* query = new IntentsQuery(this, callback); |
344 query->pending_query_ = wds_->GetAllWebIntentServices(this); | 351 query->query_handle_ = wds_->GetAllWebIntentServices(query); |
345 queries_[query->pending_query_] = query; | 352 TrackQuery(query); |
346 } | 353 } |
347 | 354 |
348 void WebIntentsRegistry::IntentServiceExists( | 355 void WebIntentsRegistry::IntentServiceExists( |
349 const WebIntentServiceData& service, | 356 const WebIntentServiceData& service, |
350 const base::Callback<void(bool)>& callback) { | 357 const base::Callback<void(bool)>& callback) { |
351 DCHECK(!callback.is_null()); | 358 DCHECK(!callback.is_null()); |
352 | 359 |
353 IntentsQuery* query = new IntentsQuery( | 360 IntentsQuery* query = new IntentsQuery( |
354 base::Bind(&ExistenceCallback, service, callback)); | 361 this, base::Bind(&ExistenceCallback, service, callback)); |
355 query->pending_query_ = wds_->GetWebIntentServicesForURL( | 362 query->query_handle_ = wds_->GetWebIntentServicesForURL( |
356 UTF8ToUTF16(service.service_url.spec()), this); | 363 UTF8ToUTF16(service.service_url.spec()), query); |
357 queries_[query->pending_query_] = query; | 364 TrackQuery(query); |
358 } | 365 } |
359 | 366 |
360 void WebIntentsRegistry::GetIntentServicesForExtensionFilter( | 367 void WebIntentsRegistry::GetIntentServicesForExtensionFilter( |
361 const string16& action, | 368 const string16& action, |
362 const string16& mimetype, | 369 const string16& type, |
363 const std::string& extension_id, | 370 const std::string& extension_id, |
364 const QueryCallback& callback) { | 371 const QueryCallback& callback) { |
365 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 372 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
366 DCHECK(!callback.is_null()); | 373 DCHECK(!callback.is_null()); |
367 | 374 |
| 375 // This isn't a WDS query, so we don't track it, |
| 376 // or claim the query later. |
368 scoped_ptr<IntentsQuery> query( | 377 scoped_ptr<IntentsQuery> query( |
369 new IntentsQuery(callback, action, mimetype)); | 378 new IntentsQuery(this, callback, action, type)); |
370 content::BrowserThread::PostTask( | 379 content::BrowserThread::PostTask( |
371 content::BrowserThread::UI, | 380 content::BrowserThread::UI, |
372 FROM_HERE, | 381 FROM_HERE, |
373 base::Bind(&WebIntentsRegistry::DoGetIntentServicesForExtensionFilter, | 382 base::Bind(&WebIntentsRegistry::DoGetIntentServicesForExtensionFilter, |
374 base::Unretained(this), | 383 base::Unretained(this), |
375 base::Passed(&query), extension_id)); | 384 base::Passed(&query), extension_id)); |
376 } | 385 } |
377 | 386 |
378 void WebIntentsRegistry::DoGetIntentServicesForExtensionFilter( | 387 void WebIntentsRegistry::DoGetIntentServicesForExtensionFilter( |
379 scoped_ptr<IntentsQuery> query, | 388 scoped_ptr<IntentsQuery> query, |
380 const std::string& extension_id) { | 389 const std::string& extension_id) { |
381 IntentServiceList matching_services; | 390 IntentServiceList matching_services; |
382 | 391 |
383 if (extension_service_) { | 392 if (extension_service_) { |
384 const Extension* extension = | 393 const Extension* extension = |
385 extension_service_->GetExtensionById(extension_id, false); | 394 extension_service_->GetExtensionById(extension_id, false); |
386 AddMatchingServicesForExtension(*extension, | 395 AddMatchingServicesForExtension(*extension, |
387 query->action_, | 396 query->action_, |
388 &matching_services); | 397 &matching_services); |
389 FilterServicesByMimetype(query->type_, &matching_services); | 398 FilterServicesByType(query->type_, &matching_services); |
390 } | 399 } |
391 | 400 |
392 query->callback_.Run(matching_services); | 401 query->callback_.Run(matching_services); |
393 } | 402 } |
394 | 403 |
395 void WebIntentsRegistry::RegisterDefaultIntentService( | 404 void WebIntentsRegistry::RegisterDefaultIntentService( |
396 const DefaultWebIntentService& default_service) { | 405 const DefaultWebIntentService& default_service) { |
397 DCHECK(wds_.get()); | 406 DCHECK(wds_.get()); |
398 wds_->AddDefaultWebIntentService(default_service); | 407 wds_->AddDefaultWebIntentService(default_service); |
399 } | 408 } |
400 | 409 |
401 void WebIntentsRegistry::UnregisterDefaultIntentService( | 410 void WebIntentsRegistry::UnregisterDefaultIntentService( |
402 const DefaultWebIntentService& default_service) { | 411 const DefaultWebIntentService& default_service) { |
403 DCHECK(wds_.get()); | 412 DCHECK(wds_.get()); |
404 wds_->RemoveDefaultWebIntentService(default_service); | 413 wds_->RemoveDefaultWebIntentService(default_service); |
405 } | 414 } |
406 | 415 |
407 void WebIntentsRegistry::GetDefaultIntentService( | 416 void WebIntentsRegistry::GetDefaultIntentService( |
408 const string16& action, | 417 const string16& action, |
409 const string16& type, | 418 const string16& type, |
410 const GURL& invoking_url, | 419 const GURL& invoking_url, |
411 const DefaultQueryCallback& callback) { | 420 const DefaultQueryCallback& callback) { |
412 DCHECK(!callback.is_null()); | 421 DCHECK(!callback.is_null()); |
413 | 422 |
414 IntentsQuery* query = | 423 IntentsQuery* query = |
415 new IntentsQuery(callback, action, type, invoking_url); | 424 new IntentsQuery(this, callback, action, type, invoking_url); |
416 query->pending_query_ = | 425 query->query_handle_ = |
417 wds_->GetDefaultWebIntentServicesForAction(action, this); | 426 wds_->GetDefaultWebIntentServicesForAction(action, query); |
418 queries_[query->pending_query_] = query; | 427 TrackQuery(query); |
419 } | 428 } |
420 | 429 |
421 void WebIntentsRegistry::RegisterIntentService( | 430 void WebIntentsRegistry::RegisterIntentService( |
422 const WebIntentServiceData& service) { | 431 const WebIntentServiceData& service) { |
423 DCHECK(wds_.get()); | 432 DCHECK(wds_.get()); |
424 wds_->AddWebIntentService(service); | 433 wds_->AddWebIntentService(service); |
425 } | 434 } |
426 | 435 |
427 void WebIntentsRegistry::UnregisterIntentService( | 436 void WebIntentsRegistry::UnregisterIntentService( |
428 const WebIntentServiceData& service) { | 437 const WebIntentServiceData& service) { |
(...skipping 24 matching lines...) Expand all Loading... |
453 if (write_iter != read_iter) | 462 if (write_iter != read_iter) |
454 *write_iter = *read_iter; | 463 *write_iter = *read_iter; |
455 } | 464 } |
456 ++read_iter; | 465 ++read_iter; |
457 } | 466 } |
458 | 467 |
459 // Cut off everything after the last intent copied to the list. | 468 // Cut off everything after the last intent copied to the list. |
460 if (++write_iter != services->end()) | 469 if (++write_iter != services->end()) |
461 services->erase(write_iter, services->end()); | 470 services->erase(write_iter, services->end()); |
462 } | 471 } |
| 472 |
| 473 const Extension* WebIntentsRegistry::ExtensionForURL(const std::string& url) { |
| 474 const ExtensionSet* extensions = extension_service_->extensions(); |
| 475 if (!extensions) |
| 476 return NULL; |
| 477 |
| 478 // Use the unsafe ExtensionURLInfo constructor: we don't care if the extension |
| 479 // is running or not. |
| 480 GURL gurl(url); |
| 481 ExtensionURLInfo info(gurl); |
| 482 return extensions->GetExtensionOrAppByURL(info); |
| 483 } |
| 484 |
| 485 void WebIntentsRegistry::TrackQuery(IntentsQuery* query) { |
| 486 DCHECK(query); |
| 487 pending_queries_.push_back(query); |
| 488 } |
| 489 |
| 490 void WebIntentsRegistry::ReleaseQuery(IntentsQuery* query) { |
| 491 QueryVector::iterator it = std::find( |
| 492 pending_queries_.begin(), pending_queries_.end(), query); |
| 493 if (it != pending_queries_.end()) |
| 494 pending_queries_.erase(it); |
| 495 else |
| 496 NOTREACHED(); |
| 497 } |
OLD | NEW |