| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2011 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 "chrome/browser/download/downloads_extension_api.h" |
| 6 |
| 7 #include <algorithm> |
| 8 #include <cctype> |
| 9 #include <iterator> |
| 10 #include <set> |
| 11 #include <string> |
| 12 |
| 13 #include "base/bind.h" |
| 14 #include "base/callback.h" |
| 15 #include "base/json/json_writer.h" |
| 16 #include "base/logging.h" |
| 17 #include "base/metrics/histogram.h" |
| 18 #include "base/stl_util.h" |
| 19 #include "base/string16.h" |
| 20 #include "base/string_split.h" |
| 21 #include "base/string_util.h" |
| 22 #include "base/stringprintf.h" |
| 23 #include "base/values.h" |
| 24 #include "chrome/browser/browser_process.h" |
| 25 #include "chrome/browser/download/download_service.h" |
| 26 #include "chrome/browser/download/download_service_factory.h" |
| 27 #include "chrome/browser/download/download_util.h" |
| 28 #include "chrome/browser/extensions/extension_event_names.h" |
| 29 #include "chrome/browser/extensions/extension_event_router.h" |
| 30 #include "chrome/browser/icon_loader.h" |
| 31 #include "chrome/browser/icon_manager.h" |
| 32 #include "chrome/browser/renderer_host/chrome_render_message_filter.h" |
| 33 #include "chrome/browser/ui/browser_list.h" |
| 34 #include "content/browser/download/download_file_manager.h" |
| 35 #include "content/browser/download/download_item.h" |
| 36 #include "content/browser/download/download_query.h" |
| 37 #include "content/browser/download/download_types.h" |
| 38 #include "content/browser/download/interrupt_reasons.h" |
| 39 #include "content/browser/renderer_host/render_process_host.h" |
| 40 #include "content/browser/renderer_host/render_view_host.h" |
| 41 #include "content/browser/renderer_host/resource_dispatcher_host.h" |
| 42 #include "net/http/http_util.h" |
| 43 #include "net/url_request/url_request.h" |
| 44 |
| 45 using content::BrowserThread; |
| 46 using download_util::DownloadQuery; |
| 47 |
| 48 namespace { |
| 49 |
| 50 namespace constants { |
| 51 |
| 52 // Error messages |
| 53 const char kNotImplemented[] = "NotImplemented"; |
| 54 const char kGenericError[] = "I'm afraid I can't do that."; |
| 55 const char kInvalidURL[] = "Invalid URL"; |
| 56 |
| 57 // Parameter keys |
| 58 const char kBodyKey[] = "body"; |
| 59 const char kBytesReceivedKey[] = "bytesReceived"; |
| 60 const char kDangerAcceptedKey[] = "dangerAccepted"; |
| 61 const char kDangerFile[] = "file"; |
| 62 const char kDangerKey[] = "danger"; |
| 63 const char kDangerSafe[] = "safe"; |
| 64 const char kDangerUrl[] = "url"; |
| 65 const char kEndTimeKey[] = "endTime"; |
| 66 const char kEndedAfterKey[] = "endedAfter"; |
| 67 const char kEndedBeforeKey[] = "endedBefore"; |
| 68 const char kErrorKey[] = "error"; |
| 69 const char kFileSizeGreaterKey[] = "fileSizeGreater"; |
| 70 const char kFileSizeKey[] = "fileSize"; |
| 71 const char kFileSizeLessKey[] = "fileSizeLess"; |
| 72 const char kFilenameKey[] = "filename"; |
| 73 const char kFilenameRegexKey[] = "filenameRegex"; |
| 74 const char kHeaderNameKey[] = "name"; |
| 75 const char kHeaderValueKey[] = "value"; |
| 76 const char kHeadersKey[] = "headers"; |
| 77 const char kIdKey[] = "id"; |
| 78 const char kLimitKey[] = "limit"; |
| 79 const char kMethodKey[] = "method"; |
| 80 const char kMimeKey[] = "mime"; |
| 81 const char kOrderByKey[] = "orderBy"; |
| 82 const char kPausedKey[] = "paused"; |
| 83 const char kQueryKey[] = "query"; |
| 84 const char kSaveAsKey[] = "saveAs"; |
| 85 const char kStartTimeKey[] = "startTime"; |
| 86 const char kStartedAfterKey[] = "startedAfter"; |
| 87 const char kStartedBeforeKey[] = "startedBefore"; |
| 88 const char kStateComplete[] = "complete"; |
| 89 const char kStateInProgress[] = "in_progress"; |
| 90 const char kStateInterrupted[] = "interrupted"; |
| 91 const char kStateKey[] = "state"; |
| 92 const char kTotalBytesGreaterKey[] = "totalBytesGreater"; |
| 93 const char kTotalBytesKey[] = "totalBytes"; |
| 94 const char kTotalBytesLessKey[] = "totalBytesLess"; |
| 95 const char kUrlKey[] = "url"; |
| 96 const char kUrlRegexKey[] = "urlRegex"; |
| 97 |
| 98 const char* DangerString(DownloadItem::DangerType danger) { |
| 99 switch (danger) { |
| 100 case DownloadItem::NOT_DANGEROUS: return kDangerSafe; |
| 101 case DownloadItem::DANGEROUS_FILE: return kDangerFile; |
| 102 case DownloadItem::DANGEROUS_URL: return kDangerUrl; |
| 103 default: |
| 104 NOTREACHED(); |
| 105 return ""; |
| 106 } |
| 107 } |
| 108 |
| 109 const char* StateString(DownloadItem::DownloadState state) { |
| 110 switch (state) { |
| 111 case DownloadItem::IN_PROGRESS: return kStateInProgress; |
| 112 case DownloadItem::COMPLETE: return kStateComplete; |
| 113 case DownloadItem::INTERRUPTED: // fall through |
| 114 case DownloadItem::CANCELLED: return kStateInterrupted; |
| 115 case DownloadItem::REMOVING: // fall through |
| 116 default: |
| 117 NOTREACHED(); |
| 118 return ""; |
| 119 } |
| 120 } |
| 121 |
| 122 DownloadItem::DangerType DangerEnumFromString(const std::string& danger) { |
| 123 if (danger == kDangerSafe) return DownloadItem::NOT_DANGEROUS; |
| 124 if (danger == kDangerFile) return DownloadItem::DANGEROUS_FILE; |
| 125 if (danger == kDangerUrl) return DownloadItem::DANGEROUS_URL; |
| 126 return DownloadItem::DANGEROUS_TYPE_MAX; |
| 127 } |
| 128 |
| 129 DownloadItem::DownloadState StateEnumFromString(const std::string& state) { |
| 130 if (state == kStateInProgress) return DownloadItem::IN_PROGRESS; |
| 131 if (state == kStateComplete) return DownloadItem::COMPLETE; |
| 132 if (state == kStateInterrupted) return DownloadItem::INTERRUPTED; |
| 133 return DownloadItem::MAX_DOWNLOAD_STATE; |
| 134 } |
| 135 |
| 136 } // namespace constants |
| 137 |
| 138 base::DictionaryValue* DownloadItemToJSON(DownloadItem* item) { |
| 139 base::DictionaryValue* json = new base::DictionaryValue(); |
| 140 json->SetInteger(constants::kIdKey, item->id()); |
| 141 json->SetString(constants::kUrlKey, item->original_url().spec()); |
| 142 json->SetString(constants::kFilenameKey, |
| 143 item->full_path().LossyDisplayName()); |
| 144 json->SetString(constants::kDangerKey, |
| 145 constants::DangerString(item->GetDangerType())); |
| 146 if (item->safety_state() != DownloadItem::SAFE) |
| 147 json->SetBoolean(constants::kDangerAcceptedKey, |
| 148 item->safety_state() == DownloadItem::DANGEROUS_BUT_VALIDATED); |
| 149 json->SetString(constants::kStateKey, |
| 150 constants::StateString(item->state())); |
| 151 json->SetBoolean(constants::kPausedKey, item->is_paused()); |
| 152 json->SetString(constants::kMimeKey, item->mime_type()); |
| 153 // TODO(benjhayden): Change startTime to a double! |
| 154 json->SetInteger(constants::kStartTimeKey, |
| 155 (item->start_time() - base::Time::UnixEpoch()).InMilliseconds()); |
| 156 json->SetInteger(constants::kBytesReceivedKey, item->received_bytes()); |
| 157 json->SetInteger(constants::kTotalBytesKey, item->total_bytes()); |
| 158 if (item->state() == DownloadItem::INTERRUPTED) |
| 159 json->SetInteger(constants::kErrorKey, |
| 160 static_cast<int>(item->last_reason())); |
| 161 // TODO(benjhayden): Implement endTime and fileSize. |
| 162 // json->SetInteger(constants::kEndTimeKey, -1); |
| 163 json->SetInteger(constants::kFileSizeKey, item->total_bytes()); |
| 164 return json; |
| 165 } |
| 166 |
| 167 template <typename T> |
| 168 bool GetJsonValue(base::DictionaryValue* json, const char* name, T* value); |
| 169 |
| 170 template<> |
| 171 bool GetJsonValue(base::DictionaryValue* json, const char* name, int* value) { |
| 172 return json->GetInteger(name, value); |
| 173 } |
| 174 |
| 175 template<> |
| 176 bool GetJsonValue(base::DictionaryValue* json, const char* name, |
| 177 string16* value) { |
| 178 return json->GetString(name, value); |
| 179 } |
| 180 |
| 181 template<> |
| 182 bool GetJsonValue(base::DictionaryValue* json, const char* name, |
| 183 std::string* value) { |
| 184 return json->GetString(name, value); |
| 185 } |
| 186 |
| 187 template<> |
| 188 bool GetJsonValue(base::DictionaryValue* json, const char* name, bool* value) { |
| 189 return json->GetBoolean(name, value); |
| 190 } |
| 191 |
| 192 struct SortFieldParsePair { |
| 193 const char* json_name; |
| 194 const DownloadQuery::SortFieldName field_name; |
| 195 }; |
| 196 |
| 197 const SortFieldParsePair sort_field_parse_pairs[] = { |
| 198 {constants::kBytesReceivedKey, DownloadQuery::SORT_FIELD_BYTES_RECEIVED}, |
| 199 {constants::kDangerKey, DownloadQuery::SORT_FIELD_DANGER}, |
| 200 {constants::kDangerAcceptedKey, DownloadQuery::SORT_FIELD_DANGER_ACCEPTED}, |
| 201 {constants::kEndTimeKey, DownloadQuery::SORT_FIELD_END_TIME}, |
| 202 {constants::kErrorKey, DownloadQuery::SORT_FIELD_ERROR}, |
| 203 {constants::kFilenameKey, DownloadQuery::SORT_FIELD_FILENAME}, |
| 204 {constants::kFileSizeKey, DownloadQuery::SORT_FIELD_FILE_SIZE}, |
| 205 {constants::kMimeKey, DownloadQuery::SORT_FIELD_MIME}, |
| 206 {constants::kPausedKey, DownloadQuery::SORT_FIELD_PAUSED}, |
| 207 {constants::kStartTimeKey, DownloadQuery::SORT_FIELD_START_TIME}, |
| 208 {constants::kStateKey, DownloadQuery::SORT_FIELD_STATE}, |
| 209 {constants::kTotalBytesKey, DownloadQuery::SORT_FIELD_TOTAL_BYTES}, |
| 210 {constants::kUrlKey, DownloadQuery::SORT_FIELD_URL}, |
| 211 }; |
| 212 |
| 213 bool DownloadSearchOrderByStringToEnum( |
| 214 const std::string& json_name, DownloadQuery::SortFieldName* field_name) { |
| 215 for (uint32 i = 0; i < arraysize(sort_field_parse_pairs); ++i) { |
| 216 if (json_name == sort_field_parse_pairs[i].json_name) { |
| 217 *field_name = sort_field_parse_pairs[i].field_name; |
| 218 return true; |
| 219 } |
| 220 } |
| 221 return false; |
| 222 } |
| 223 |
| 224 } // anonymous namespace |
| 225 |
| 226 bool DownloadsFunctionInterface::RunImplImpl( |
| 227 DownloadsFunctionInterface* pimpl) { |
| 228 CHECK(pimpl); |
| 229 if (!pimpl->ParseArgs()) return false; |
| 230 UMA_HISTOGRAM_ENUMERATION( |
| 231 "Download.ApiFunctions", pimpl->function(), DOWNLOADS_FUNCTION_LAST); |
| 232 pimpl->RunInternal(); |
| 233 return true; |
| 234 } |
| 235 |
| 236 SyncDownloadsFunction::SyncDownloadsFunction( |
| 237 DownloadsFunctionInterface::DownloadsFunctionName function) |
| 238 : function_(function) { |
| 239 } |
| 240 |
| 241 SyncDownloadsFunction::~SyncDownloadsFunction() {} |
| 242 |
| 243 bool SyncDownloadsFunction::RunImpl() { |
| 244 return DownloadsFunctionInterface::RunImplImpl(this); |
| 245 } |
| 246 |
| 247 DownloadsFunctionInterface::DownloadsFunctionName |
| 248 SyncDownloadsFunction::function() const { |
| 249 return function_; |
| 250 } |
| 251 |
| 252 AsyncDownloadsFunction::AsyncDownloadsFunction( |
| 253 DownloadsFunctionInterface::DownloadsFunctionName function) |
| 254 : function_(function) { |
| 255 } |
| 256 |
| 257 AsyncDownloadsFunction::~AsyncDownloadsFunction() {} |
| 258 |
| 259 bool AsyncDownloadsFunction::RunImpl() { |
| 260 return DownloadsFunctionInterface::RunImplImpl(this); |
| 261 } |
| 262 |
| 263 DownloadsFunctionInterface::DownloadsFunctionName |
| 264 AsyncDownloadsFunction::function() const { |
| 265 return function_; |
| 266 } |
| 267 |
| 268 DownloadsDownloadFunction::DownloadsDownloadFunction() |
| 269 : AsyncDownloadsFunction(DOWNLOADS_FUNCTION_DOWNLOAD) { |
| 270 } |
| 271 |
| 272 DownloadsDownloadFunction::~DownloadsDownloadFunction() {} |
| 273 |
| 274 DownloadsDownloadFunction::IOData::IOData() |
| 275 : save_as(false), |
| 276 extra_headers(NULL), |
| 277 method("GET"), |
| 278 rdh(NULL), |
| 279 resource_context(NULL), |
| 280 render_process_host_id(0), |
| 281 render_view_host_routing_id(0) { |
| 282 } |
| 283 |
| 284 DownloadsDownloadFunction::IOData::~IOData() {} |
| 285 |
| 286 bool DownloadsDownloadFunction::ParseArgs() { |
| 287 base::DictionaryValue* options = NULL; |
| 288 std::string url; |
| 289 iodata_.reset(new IOData()); |
| 290 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &options)); |
| 291 EXTENSION_FUNCTION_VALIDATE(options->GetString(constants::kUrlKey, &url)); |
| 292 iodata_->url = GURL(url); |
| 293 if (!iodata_->url.is_valid()) { |
| 294 error_ = constants::kInvalidURL; |
| 295 return false; |
| 296 } |
| 297 if (options->HasKey(constants::kFilenameKey)) |
| 298 EXTENSION_FUNCTION_VALIDATE(options->GetString( |
| 299 constants::kFilenameKey, &iodata_->filename)); |
| 300 // TODO(benjhayden): More robust validation of filename. |
| 301 if (((iodata_->filename[0] == L'.') && (iodata_->filename[1] == L'.')) || |
| 302 (iodata_->filename[0] == L'/')) { |
| 303 error_ = constants::kGenericError; |
| 304 return false; |
| 305 } |
| 306 if (options->HasKey(constants::kSaveAsKey)) |
| 307 EXTENSION_FUNCTION_VALIDATE(options->GetBoolean( |
| 308 constants::kSaveAsKey, &iodata_->save_as)); |
| 309 if (options->HasKey(constants::kMethodKey)) |
| 310 EXTENSION_FUNCTION_VALIDATE(options->GetString( |
| 311 constants::kMethodKey, &iodata_->method)); |
| 312 // It's ok to use a pointer to extra_headers without DeepCopy()ing because |
| 313 // |args_| (which owns *extra_headers) is guaranteed to live as long as |
| 314 // |this|. |
| 315 if (options->HasKey(constants::kHeadersKey)) |
| 316 EXTENSION_FUNCTION_VALIDATE(options->GetList( |
| 317 constants::kHeadersKey, &iodata_->extra_headers)); |
| 318 if (options->HasKey(constants::kBodyKey)) |
| 319 EXTENSION_FUNCTION_VALIDATE(options->GetString( |
| 320 constants::kBodyKey, &iodata_->post_body)); |
| 321 if (iodata_->extra_headers != NULL) { |
| 322 for (size_t index = 0; index < iodata_->extra_headers->GetSize(); ++index) { |
| 323 base::DictionaryValue* header = NULL; |
| 324 std::string name, value; |
| 325 EXTENSION_FUNCTION_VALIDATE(iodata_->extra_headers->GetDictionary( |
| 326 index, &header)); |
| 327 EXTENSION_FUNCTION_VALIDATE(header->GetString( |
| 328 constants::kHeaderNameKey, &name)); |
| 329 EXTENSION_FUNCTION_VALIDATE(header->GetString( |
| 330 constants::kHeaderValueKey, &value)); |
| 331 if (!net::HttpUtil::IsSafeHeader(name)) { |
| 332 error_ = constants::kGenericError; |
| 333 return false; |
| 334 } |
| 335 } |
| 336 } |
| 337 iodata_->rdh = g_browser_process->resource_dispatcher_host(); |
| 338 iodata_->resource_context = &profile()->GetResourceContext(); |
| 339 iodata_->render_process_host_id = render_view_host()->process()->id(); |
| 340 iodata_->render_view_host_routing_id = render_view_host()->routing_id(); |
| 341 return true; |
| 342 } |
| 343 |
| 344 void DownloadsDownloadFunction::RunInternal() { |
| 345 VLOG(1) << __FUNCTION__ << " " << iodata_->url.spec(); |
| 346 if (!BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind( |
| 347 &DownloadsDownloadFunction::BeginDownloadOnIOThread, this))) { |
| 348 error_ = constants::kGenericError; |
| 349 SendResponse(error_.empty()); |
| 350 } |
| 351 } |
| 352 |
| 353 void DownloadsDownloadFunction::BeginDownloadOnIOThread() { |
| 354 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 355 DVLOG(1) << __FUNCTION__ << " " << iodata_->url.spec(); |
| 356 DownloadSaveInfo save_info; |
| 357 // TODO(benjhayden) Ensure that this filename is interpreted as a path |
| 358 // relative to the default downloads directory without allowing '..'. |
| 359 save_info.suggested_name = iodata_->filename; |
| 360 net::URLRequest* request = new net::URLRequest(iodata_->url, iodata_->rdh); |
| 361 request->set_method(iodata_->method); |
| 362 if (iodata_->extra_headers != NULL) { |
| 363 for (size_t index = 0; index < iodata_->extra_headers->GetSize(); ++index) { |
| 364 base::DictionaryValue* header = NULL; |
| 365 std::string name, value; |
| 366 CHECK(iodata_->extra_headers->GetDictionary(index, &header)); |
| 367 CHECK(header->GetString("name", &name)); |
| 368 CHECK(header->GetString("value", &value)); |
| 369 request->SetExtraRequestHeaderByName(name, value, false/*overwrite*/); |
| 370 } |
| 371 } |
| 372 if (!iodata_->post_body.empty()) { |
| 373 request->AppendBytesToUpload(iodata_->post_body.data(), |
| 374 iodata_->post_body.size()); |
| 375 } |
| 376 iodata_->rdh->BeginDownload( |
| 377 request, |
| 378 save_info, |
| 379 iodata_->save_as, |
| 380 base::Bind(&DownloadsDownloadFunction::OnStarted, this), |
| 381 iodata_->render_process_host_id, |
| 382 iodata_->render_view_host_routing_id, |
| 383 *(iodata_->resource_context)); |
| 384 iodata_.reset(); |
| 385 } |
| 386 |
| 387 void DownloadsDownloadFunction::OnStarted(DownloadId dl_id, net::Error error) { |
| 388 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 389 VLOG(1) << __FUNCTION__ << " " << dl_id << " " << error; |
| 390 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( |
| 391 &DownloadsDownloadFunction::RespondOnUIThread, this, |
| 392 dl_id.local(), error)); |
| 393 } |
| 394 |
| 395 void DownloadsDownloadFunction::RespondOnUIThread(int dl_id, net::Error error) { |
| 396 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 397 VLOG(1) << __FUNCTION__; |
| 398 if (dl_id >= 0) { |
| 399 result_.reset(base::Value::CreateIntegerValue(dl_id)); |
| 400 } else { |
| 401 error_ = net::ErrorToString(error); |
| 402 } |
| 403 SendResponse(error_.empty()); |
| 404 } |
| 405 |
| 406 DownloadsSearchFunction::DownloadsSearchFunction() |
| 407 : SyncDownloadsFunction(DOWNLOADS_FUNCTION_SEARCH), |
| 408 get_id_(0), |
| 409 has_get_id_(false) { |
| 410 } |
| 411 |
| 412 DownloadsSearchFunction::~DownloadsSearchFunction() {} |
| 413 |
| 414 template <typename ValueType> |
| 415 bool DownloadsSearchFunction::Parse( |
| 416 base::DictionaryValue* json, |
| 417 const char* json_name, |
| 418 DownloadQuery::FilterFieldName filter_name) { |
| 419 if (json->HasKey(json_name)) { |
| 420 ValueType value; |
| 421 EXTENSION_FUNCTION_VALIDATE(GetJsonValue(json, json_name, &value)); |
| 422 if (!query_.Filter(filter_name, value)) { |
| 423 error_ = constants::kGenericError; // TODO(benjhayden) |
| 424 return false; |
| 425 } |
| 426 } |
| 427 return true; |
| 428 } |
| 429 |
| 430 bool DownloadsSearchFunction::ParseArgs() { |
| 431 base::DictionaryValue* query_json = NULL; |
| 432 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &query_json)); |
| 433 if (query_json->HasKey(constants::kDangerKey)) { |
| 434 std::string danger; |
| 435 EXTENSION_FUNCTION_VALIDATE(query_json->GetString( |
| 436 constants::kDangerKey, &danger)); |
| 437 if (!query_.Filter(DownloadQuery::FILTER_FIELD_DANGER, |
| 438 constants::DangerEnumFromString(danger))) { |
| 439 error_ = constants::kGenericError; // TODO |
| 440 return false; |
| 441 } |
| 442 } |
| 443 if (query_json->HasKey(constants::kStateKey)) { |
| 444 std::string state; |
| 445 EXTENSION_FUNCTION_VALIDATE(query_json->GetString( |
| 446 constants::kStateKey, &state)); |
| 447 if (!query_.Filter(DownloadQuery::FILTER_FIELD_STATE, |
| 448 constants::StateEnumFromString(state))) { |
| 449 error_ = constants::kGenericError; // TODO |
| 450 return false; |
| 451 } |
| 452 } |
| 453 if (query_json->HasKey(constants::kIdKey)) { |
| 454 EXTENSION_FUNCTION_VALIDATE(query_json->GetInteger( |
| 455 constants::kIdKey, &get_id_)); |
| 456 has_get_id_ = true; |
| 457 } |
| 458 if (query_json->HasKey(constants::kOrderByKey)) { |
| 459 std::string order_by_str; |
| 460 EXTENSION_FUNCTION_VALIDATE(query_json->GetString( |
| 461 constants::kOrderByKey, &order_by_str)); |
| 462 std::vector<std::string> order_by_strs; |
| 463 base::SplitString(order_by_str, ' ', &order_by_strs); |
| 464 for (std::vector<std::string>::const_iterator iter = order_by_strs.begin(); |
| 465 iter != order_by_strs.end(); ++iter) { |
| 466 std::string term_str = *iter; |
| 467 DownloadQuery::SortFieldDirection direction = DownloadQuery::ASCENDING; |
| 468 if (term_str[0] == '-') { |
| 469 direction = DownloadQuery::DESCENDING; |
| 470 term_str = term_str.substr(1); |
| 471 } |
| 472 DownloadQuery::SortFieldName field_enum; |
| 473 if (!DownloadSearchOrderByStringToEnum(term_str, &field_enum)) { |
| 474 error_ = constants::kGenericError; // TODO |
| 475 return false; |
| 476 } |
| 477 query_.Sort(field_enum, direction); |
| 478 } |
| 479 } |
| 480 if (query_json->HasKey(constants::kLimitKey)) { |
| 481 int limit = 0; |
| 482 EXTENSION_FUNCTION_VALIDATE(query_json->GetInteger( |
| 483 constants::kLimitKey, &limit)); |
| 484 query_.Limit(limit); |
| 485 } |
| 486 return Parse<int>(query_json, constants::kStartTimeKey, |
| 487 DownloadQuery::FILTER_FIELD_START_TIME) && |
| 488 Parse<int>(query_json, constants::kEndTimeKey, |
| 489 DownloadQuery::FILTER_FIELD_END_TIME) && |
| 490 Parse<int>(query_json, constants::kStartedBeforeKey, |
| 491 DownloadQuery::FILTER_FIELD_STARTED_BEFORE) && |
| 492 Parse<int>(query_json, constants::kStartedAfterKey, |
| 493 DownloadQuery::FILTER_FIELD_STARTED_AFTER) && |
| 494 Parse<int>(query_json, constants::kEndedBeforeKey, |
| 495 DownloadQuery::FILTER_FIELD_ENDED_BEFORE) && |
| 496 Parse<int>(query_json, constants::kEndedAfterKey, |
| 497 DownloadQuery::FILTER_FIELD_ENDED_AFTER) && |
| 498 Parse<int>(query_json, constants::kBytesReceivedKey, |
| 499 DownloadQuery::FILTER_FIELD_BYTES_RECEIVED) && |
| 500 Parse<int>(query_json, constants::kTotalBytesKey, |
| 501 DownloadQuery::FILTER_FIELD_TOTAL_BYTES) && |
| 502 Parse<int>(query_json, constants::kTotalBytesGreaterKey, |
| 503 DownloadQuery::FILTER_FIELD_TOTAL_BYTES_GREATER) && |
| 504 Parse<int>(query_json, constants::kTotalBytesLessKey, |
| 505 DownloadQuery::FILTER_FIELD_TOTAL_BYTES_LESS) && |
| 506 Parse<int>(query_json, constants::kFileSizeKey, |
| 507 DownloadQuery::FILTER_FIELD_FILE_SIZE) && |
| 508 Parse<int>(query_json, constants::kFileSizeGreaterKey, |
| 509 DownloadQuery::FILTER_FIELD_FILE_SIZE_GREATER) && |
| 510 Parse<int>(query_json, constants::kFileSizeLessKey, |
| 511 DownloadQuery::FILTER_FIELD_FILE_SIZE_LESS) && |
| 512 Parse<int>(query_json, constants::kErrorKey, |
| 513 DownloadQuery::FILTER_FIELD_ERROR) && |
| 514 Parse<bool>(query_json, constants::kDangerAcceptedKey, |
| 515 DownloadQuery::FILTER_FIELD_DANGER_ACCEPTED) && |
| 516 Parse<bool>(query_json, constants::kPausedKey, |
| 517 DownloadQuery::FILTER_FIELD_PAUSED) && |
| 518 Parse<string16>(query_json, constants::kFilenameKey, |
| 519 DownloadQuery::FILTER_FIELD_FILENAME) && |
| 520 Parse<std::string>(query_json, constants::kMimeKey, |
| 521 DownloadQuery::FILTER_FIELD_MIME) && |
| 522 Parse<std::string>(query_json, constants::kQueryKey, |
| 523 DownloadQuery::FILTER_FIELD_QUERY) && |
| 524 Parse<std::string>(query_json, constants::kFilenameRegexKey, |
| 525 DownloadQuery::FILTER_FIELD_FILENAME_REGEX) && |
| 526 Parse<std::string>(query_json, constants::kUrlRegexKey, |
| 527 DownloadQuery::FILTER_FIELD_URL_REGEX) && |
| 528 Parse<std::string>(query_json, constants::kUrlKey, |
| 529 DownloadQuery::FILTER_FIELD_URL); |
| 530 } |
| 531 |
| 532 void DownloadsSearchFunction::RunInternal() { |
| 533 DownloadManager::DownloadVector cpp_results; |
| 534 if (has_get_id_) { |
| 535 DownloadItem* item = profile()->GetDownloadManager()->GetDownloadItem( |
| 536 get_id_); |
| 537 if (item && query_.Matches(*item)) |
| 538 cpp_results.push_back(item); |
| 539 } else { |
| 540 profile()->GetDownloadManager()->Search(query_, &cpp_results); |
| 541 } |
| 542 base::ListValue* json_results = new base::ListValue(); |
| 543 for (DownloadManager::DownloadVector::const_iterator it = cpp_results.begin(); |
| 544 it != cpp_results.end(); ++it) { |
| 545 json_results->Append(DownloadItemToJSON(*it)); |
| 546 } |
| 547 result_.reset(json_results); |
| 548 } |
| 549 |
| 550 DownloadsPauseFunction::DownloadsPauseFunction() |
| 551 : SyncDownloadsFunction(DOWNLOADS_FUNCTION_PAUSE) { |
| 552 } |
| 553 |
| 554 DownloadsPauseFunction::~DownloadsPauseFunction() {} |
| 555 |
| 556 bool DownloadsPauseFunction::ParseArgs() { |
| 557 int dl_id = 0; |
| 558 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &dl_id)); |
| 559 VLOG(1) << __FUNCTION__ << " " << dl_id; |
| 560 error_ = constants::kNotImplemented; |
| 561 return false; |
| 562 } |
| 563 |
| 564 void DownloadsPauseFunction::RunInternal() { |
| 565 NOTIMPLEMENTED(); |
| 566 } |
| 567 |
| 568 DownloadsResumeFunction::DownloadsResumeFunction() |
| 569 : AsyncDownloadsFunction(DOWNLOADS_FUNCTION_RESUME) { |
| 570 } |
| 571 |
| 572 DownloadsResumeFunction::~DownloadsResumeFunction() {} |
| 573 |
| 574 bool DownloadsResumeFunction::ParseArgs() { |
| 575 int dl_id = 0; |
| 576 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &dl_id)); |
| 577 VLOG(1) << __FUNCTION__ << " " << dl_id; |
| 578 error_ = constants::kNotImplemented; |
| 579 return false; |
| 580 } |
| 581 |
| 582 void DownloadsResumeFunction::RunInternal() { |
| 583 NOTIMPLEMENTED(); |
| 584 } |
| 585 |
| 586 DownloadsCancelFunction::DownloadsCancelFunction() |
| 587 : AsyncDownloadsFunction(DOWNLOADS_FUNCTION_CANCEL) { |
| 588 } |
| 589 |
| 590 DownloadsCancelFunction::~DownloadsCancelFunction() {} |
| 591 |
| 592 bool DownloadsCancelFunction::ParseArgs() { |
| 593 int dl_id = 0; |
| 594 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &dl_id)); |
| 595 VLOG(1) << __FUNCTION__ << " " << dl_id; |
| 596 error_ = constants::kNotImplemented; |
| 597 return false; |
| 598 } |
| 599 |
| 600 void DownloadsCancelFunction::RunInternal() { |
| 601 NOTIMPLEMENTED(); |
| 602 } |
| 603 |
| 604 DownloadsEraseFunction::DownloadsEraseFunction() |
| 605 : AsyncDownloadsFunction(DOWNLOADS_FUNCTION_ERASE) { |
| 606 } |
| 607 |
| 608 DownloadsEraseFunction::~DownloadsEraseFunction() {} |
| 609 |
| 610 bool DownloadsEraseFunction::ParseArgs() { |
| 611 base::DictionaryValue* query_json = NULL; |
| 612 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &query_json)); |
| 613 error_ = constants::kNotImplemented; |
| 614 return false; |
| 615 } |
| 616 |
| 617 void DownloadsEraseFunction::RunInternal() { |
| 618 NOTIMPLEMENTED(); |
| 619 } |
| 620 |
| 621 DownloadsSetDestinationFunction::DownloadsSetDestinationFunction() |
| 622 : AsyncDownloadsFunction(DOWNLOADS_FUNCTION_SET_DESTINATION) { |
| 623 } |
| 624 |
| 625 DownloadsSetDestinationFunction::~DownloadsSetDestinationFunction() {} |
| 626 |
| 627 bool DownloadsSetDestinationFunction::ParseArgs() { |
| 628 int dl_id = 0; |
| 629 std::string path; |
| 630 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &dl_id)); |
| 631 EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &path)); |
| 632 VLOG(1) << __FUNCTION__ << " " << dl_id << " " << &path; |
| 633 error_ = constants::kNotImplemented; |
| 634 return false; |
| 635 } |
| 636 |
| 637 void DownloadsSetDestinationFunction::RunInternal() { |
| 638 NOTIMPLEMENTED(); |
| 639 } |
| 640 |
| 641 DownloadsAcceptDangerFunction::DownloadsAcceptDangerFunction() |
| 642 : AsyncDownloadsFunction(DOWNLOADS_FUNCTION_ACCEPT_DANGER) { |
| 643 } |
| 644 |
| 645 DownloadsAcceptDangerFunction::~DownloadsAcceptDangerFunction() {} |
| 646 |
| 647 bool DownloadsAcceptDangerFunction::ParseArgs() { |
| 648 int dl_id = 0; |
| 649 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &dl_id)); |
| 650 VLOG(1) << __FUNCTION__ << " " << dl_id; |
| 651 error_ = constants::kNotImplemented; |
| 652 return false; |
| 653 } |
| 654 |
| 655 void DownloadsAcceptDangerFunction::RunInternal() { |
| 656 NOTIMPLEMENTED(); |
| 657 } |
| 658 |
| 659 DownloadsShowFunction::DownloadsShowFunction() |
| 660 : AsyncDownloadsFunction(DOWNLOADS_FUNCTION_SHOW) { |
| 661 } |
| 662 |
| 663 DownloadsShowFunction::~DownloadsShowFunction() {} |
| 664 |
| 665 bool DownloadsShowFunction::ParseArgs() { |
| 666 int dl_id = 0; |
| 667 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &dl_id)); |
| 668 VLOG(1) << __FUNCTION__ << " " << dl_id; |
| 669 error_ = constants::kNotImplemented; |
| 670 return false; |
| 671 } |
| 672 |
| 673 void DownloadsShowFunction::RunInternal() { |
| 674 NOTIMPLEMENTED(); |
| 675 } |
| 676 |
| 677 DownloadsDragFunction::DownloadsDragFunction() |
| 678 : AsyncDownloadsFunction(DOWNLOADS_FUNCTION_DRAG) { |
| 679 } |
| 680 |
| 681 DownloadsDragFunction::~DownloadsDragFunction() {} |
| 682 |
| 683 bool DownloadsDragFunction::ParseArgs() { |
| 684 int dl_id = 0; |
| 685 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &dl_id)); |
| 686 VLOG(1) << __FUNCTION__ << " " << dl_id; |
| 687 error_ = constants::kNotImplemented; |
| 688 return false; |
| 689 } |
| 690 |
| 691 void DownloadsDragFunction::RunInternal() { |
| 692 NOTIMPLEMENTED(); |
| 693 } |
| 694 |
| 695 ExtensionDownloadsEventRouter::ExtensionDownloadsEventRouter( |
| 696 Profile* profile) |
| 697 : profile_(profile), |
| 698 manager_( |
| 699 profile ? |
| 700 DownloadServiceFactory::GetForProfile(profile)->GetDownloadManager() : |
| 701 NULL) { |
| 702 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 703 DCHECK(profile_); |
| 704 DCHECK(manager_); |
| 705 manager_->AddObserver(this); |
| 706 } |
| 707 |
| 708 ExtensionDownloadsEventRouter::~ExtensionDownloadsEventRouter() { |
| 709 if (manager_ != NULL) |
| 710 manager_->RemoveObserver(this); |
| 711 } |
| 712 |
| 713 void ExtensionDownloadsEventRouter::ModelChanged() { |
| 714 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 715 if (manager_ == NULL) |
| 716 return; |
| 717 DownloadManager::DownloadVector current_vec; |
| 718 manager_->SearchDownloads(string16(), ¤t_vec); |
| 719 DownloadIdSet current_set; |
| 720 ItemMap current_map; |
| 721 for (DownloadManager::DownloadVector::const_iterator iter = |
| 722 current_vec.begin(); |
| 723 iter != current_vec.end(); ++iter) { |
| 724 DownloadItem* item = *iter; |
| 725 int item_id = item->id(); |
| 726 // TODO(benjhayden): Remove the following line when every item's id >= 0, |
| 727 // which will allow firing onErased events for items from the history. |
| 728 if (item_id < 0) continue; |
| 729 DCHECK(current_map.find(item_id) == current_map.end()); |
| 730 current_set.insert(item_id); |
| 731 current_map[item_id] = item; |
| 732 } |
| 733 DownloadIdSet new_set; // current_set - downloads_; |
| 734 DownloadIdSet erased_set; // downloads_ - current_set; |
| 735 std::insert_iterator<DownloadIdSet> new_insertor(new_set, new_set.begin()); |
| 736 std::insert_iterator<DownloadIdSet> erased_insertor( |
| 737 erased_set, erased_set.begin()); |
| 738 std::set_difference(current_set.begin(), current_set.end(), |
| 739 downloads_.begin(), downloads_.end(), |
| 740 new_insertor); |
| 741 std::set_difference(downloads_.begin(), downloads_.end(), |
| 742 current_set.begin(), current_set.end(), |
| 743 erased_insertor); |
| 744 for (DownloadIdSet::const_iterator iter = new_set.begin(); |
| 745 iter != new_set.end(); ++iter) { |
| 746 DispatchEvent(extension_event_names::kOnDownloadCreated, |
| 747 DownloadItemToJSON(current_map[*iter])); |
| 748 } |
| 749 for (DownloadIdSet::const_iterator iter = erased_set.begin(); |
| 750 iter != erased_set.end(); ++iter) { |
| 751 DispatchEvent(extension_event_names::kOnDownloadErased, |
| 752 base::Value::CreateIntegerValue(*iter)); |
| 753 } |
| 754 downloads_.swap(current_set); |
| 755 } |
| 756 |
| 757 void ExtensionDownloadsEventRouter::ManagerGoingDown() { |
| 758 manager_->RemoveObserver(this); |
| 759 manager_ = NULL; |
| 760 } |
| 761 |
| 762 void ExtensionDownloadsEventRouter::DispatchEvent( |
| 763 const char* event_name, base::Value* arg) { |
| 764 ListValue args; |
| 765 args.Append(arg); |
| 766 std::string json_args; |
| 767 base::JSONWriter::Write(&args, false, &json_args); |
| 768 profile_->GetExtensionEventRouter()->DispatchEventToRenderers( |
| 769 event_name, |
| 770 json_args, |
| 771 profile_, |
| 772 GURL()); |
| 773 } |
| OLD | NEW |