| 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 "content/browser/download/save_package.h" | 5 #include "content/browser/download/save_package.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/file_path.h" | 10 #include "base/file_path.h" |
| (...skipping 367 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 378 // The parameter |dir_path| specifies directory part of the specified | 378 // The parameter |dir_path| specifies directory part of the specified |
| 379 // file path. The parameter |file_name_ext| specifies file extension | 379 // file path. The parameter |file_name_ext| specifies file extension |
| 380 // name part of the specified file path (including start dot). The parameter | 380 // name part of the specified file path (including start dot). The parameter |
| 381 // |max_file_path_len| specifies maximum length of the specified file path. | 381 // |max_file_path_len| specifies maximum length of the specified file path. |
| 382 // The parameter |pure_file_name| input pure file name part of the specified | 382 // The parameter |pure_file_name| input pure file name part of the specified |
| 383 // file path. If the length of specified file path is great than | 383 // file path. If the length of specified file path is great than |
| 384 // |max_file_path_len|, the |pure_file_name| will output new pure file name | 384 // |max_file_path_len|, the |pure_file_name| will output new pure file name |
| 385 // part for making sure the length of specified file path is less than | 385 // part for making sure the length of specified file path is less than |
| 386 // specified maximum length of file path. Return false if the function can | 386 // specified maximum length of file path. Return false if the function can |
| 387 // not get a safe pure file name, otherwise it returns true. | 387 // not get a safe pure file name, otherwise it returns true. |
| 388 bool SavePackage::GetSafePureFileName(const FilePath& dir_path, | 388 bool SavePackage::GetSafePureFileName( |
| 389 const FilePath::StringType& file_name_ext, | 389 const base::FilePath& dir_path, |
| 390 uint32 max_file_path_len, | 390 const base::FilePath::StringType& file_name_ext, |
| 391 FilePath::StringType* pure_file_name) { | 391 uint32 max_file_path_len, |
| 392 base::FilePath::StringType* pure_file_name) { |
| 392 DCHECK(!pure_file_name->empty()); | 393 DCHECK(!pure_file_name->empty()); |
| 393 int available_length = static_cast<int>(max_file_path_len - | 394 int available_length = static_cast<int>(max_file_path_len - |
| 394 dir_path.value().length() - | 395 dir_path.value().length() - |
| 395 file_name_ext.length()); | 396 file_name_ext.length()); |
| 396 // Need an extra space for the separator. | 397 // Need an extra space for the separator. |
| 397 if (!file_util::EndsWithSeparator(dir_path)) | 398 if (!file_util::EndsWithSeparator(dir_path)) |
| 398 --available_length; | 399 --available_length; |
| 399 | 400 |
| 400 // Plenty of room. | 401 // Plenty of room. |
| 401 if (static_cast<int>(pure_file_name->length()) <= available_length) | 402 if (static_cast<int>(pure_file_name->length()) <= available_length) |
| 402 return true; | 403 return true; |
| 403 | 404 |
| 404 // Limited room. Truncate |pure_file_name| to fit. | 405 // Limited room. Truncate |pure_file_name| to fit. |
| 405 if (available_length > 0) { | 406 if (available_length > 0) { |
| 406 *pure_file_name = pure_file_name->substr(0, available_length); | 407 *pure_file_name = pure_file_name->substr(0, available_length); |
| 407 return true; | 408 return true; |
| 408 } | 409 } |
| 409 | 410 |
| 410 // Not enough room to even use a shortened |pure_file_name|. | 411 // Not enough room to even use a shortened |pure_file_name|. |
| 411 pure_file_name->clear(); | 412 pure_file_name->clear(); |
| 412 return false; | 413 return false; |
| 413 } | 414 } |
| 414 | 415 |
| 415 // Generate name for saving resource. | 416 // Generate name for saving resource. |
| 416 bool SavePackage::GenerateFileName(const std::string& disposition, | 417 bool SavePackage::GenerateFileName(const std::string& disposition, |
| 417 const GURL& url, | 418 const GURL& url, |
| 418 bool need_html_ext, | 419 bool need_html_ext, |
| 419 FilePath::StringType* generated_name) { | 420 base::FilePath::StringType* generated_name) { |
| 420 // TODO(jungshik): Figure out the referrer charset when having one | 421 // TODO(jungshik): Figure out the referrer charset when having one |
| 421 // makes sense and pass it to GenerateFileName. | 422 // makes sense and pass it to GenerateFileName. |
| 422 FilePath file_path = net::GenerateFileName(url, disposition, "", "", "", | 423 base::FilePath file_path = net::GenerateFileName(url, disposition, "", "", "", |
| 423 kDefaultSaveName); | 424 kDefaultSaveName); |
| 424 | 425 |
| 425 DCHECK(!file_path.empty()); | 426 DCHECK(!file_path.empty()); |
| 426 FilePath::StringType pure_file_name = | 427 base::FilePath::StringType pure_file_name = |
| 427 file_path.RemoveExtension().BaseName().value(); | 428 file_path.RemoveExtension().BaseName().value(); |
| 428 FilePath::StringType file_name_ext = file_path.Extension(); | 429 base::FilePath::StringType file_name_ext = file_path.Extension(); |
| 429 | 430 |
| 430 // If it is HTML resource, use ".htm{l,}" as its extension. | 431 // If it is HTML resource, use ".htm{l,}" as its extension. |
| 431 if (need_html_ext) { | 432 if (need_html_ext) { |
| 432 file_name_ext = FILE_PATH_LITERAL("."); | 433 file_name_ext = FILE_PATH_LITERAL("."); |
| 433 file_name_ext.append(kDefaultHtmlExtension); | 434 file_name_ext.append(kDefaultHtmlExtension); |
| 434 } | 435 } |
| 435 | 436 |
| 436 // Need to make sure the suggested file name is not too long. | 437 // Need to make sure the suggested file name is not too long. |
| 437 uint32 max_path = GetMaxPathLengthForDirectory(saved_main_directory_path_); | 438 uint32 max_path = GetMaxPathLengthForDirectory(saved_main_directory_path_); |
| 438 | 439 |
| 439 // Get safe pure file name. | 440 // Get safe pure file name. |
| 440 if (!GetSafePureFileName(saved_main_directory_path_, file_name_ext, | 441 if (!GetSafePureFileName(saved_main_directory_path_, file_name_ext, |
| 441 max_path, &pure_file_name)) | 442 max_path, &pure_file_name)) |
| 442 return false; | 443 return false; |
| 443 | 444 |
| 444 FilePath::StringType file_name = pure_file_name + file_name_ext; | 445 base::FilePath::StringType file_name = pure_file_name + file_name_ext; |
| 445 | 446 |
| 446 // Check whether we already have same name in a case insensitive manner. | 447 // Check whether we already have same name in a case insensitive manner. |
| 447 FileNameSet::const_iterator iter = file_name_set_.find(file_name); | 448 FileNameSet::const_iterator iter = file_name_set_.find(file_name); |
| 448 if (iter == file_name_set_.end()) { | 449 if (iter == file_name_set_.end()) { |
| 449 file_name_set_.insert(file_name); | 450 file_name_set_.insert(file_name); |
| 450 } else { | 451 } else { |
| 451 // Found same name, increase the ordinal number for the file name. | 452 // Found same name, increase the ordinal number for the file name. |
| 452 pure_file_name = | 453 pure_file_name = |
| 453 FilePath(*iter).RemoveExtension().BaseName().value(); | 454 base::FilePath(*iter).RemoveExtension().BaseName().value(); |
| 454 FilePath::StringType base_file_name = StripOrdinalNumber(pure_file_name); | 455 base::FilePath::StringType base_file_name = |
| 456 StripOrdinalNumber(pure_file_name); |
| 455 | 457 |
| 456 // We need to make sure the length of base file name plus maximum ordinal | 458 // We need to make sure the length of base file name plus maximum ordinal |
| 457 // number path will be less than or equal to kMaxFilePathLength. | 459 // number path will be less than or equal to kMaxFilePathLength. |
| 458 if (!GetSafePureFileName(saved_main_directory_path_, file_name_ext, | 460 if (!GetSafePureFileName(saved_main_directory_path_, file_name_ext, |
| 459 max_path - kMaxFileOrdinalNumberPartLength, &base_file_name)) | 461 max_path - kMaxFileOrdinalNumberPartLength, &base_file_name)) |
| 460 return false; | 462 return false; |
| 461 | 463 |
| 462 // Prepare the new ordinal number. | 464 // Prepare the new ordinal number. |
| 463 uint32 ordinal_number; | 465 uint32 ordinal_number; |
| 464 FileNameCountMap::iterator it = file_name_count_map_.find(base_file_name); | 466 FileNameCountMap::iterator it = file_name_count_map_.find(base_file_name); |
| 465 if (it == file_name_count_map_.end()) { | 467 if (it == file_name_count_map_.end()) { |
| 466 // First base-name-conflict resolving, use 1 as initial ordinal number. | 468 // First base-name-conflict resolving, use 1 as initial ordinal number. |
| 467 file_name_count_map_[base_file_name] = 1; | 469 file_name_count_map_[base_file_name] = 1; |
| 468 ordinal_number = 1; | 470 ordinal_number = 1; |
| 469 } else { | 471 } else { |
| 470 // We have met same base-name conflict, use latest ordinal number. | 472 // We have met same base-name conflict, use latest ordinal number. |
| 471 ordinal_number = it->second; | 473 ordinal_number = it->second; |
| 472 } | 474 } |
| 473 | 475 |
| 474 if (ordinal_number > (kMaxFileOrdinalNumber - 1)) { | 476 if (ordinal_number > (kMaxFileOrdinalNumber - 1)) { |
| 475 // Use a random file from temporary file. | 477 // Use a random file from temporary file. |
| 476 FilePath temp_file; | 478 base::FilePath temp_file; |
| 477 file_util::CreateTemporaryFile(&temp_file); | 479 file_util::CreateTemporaryFile(&temp_file); |
| 478 file_name = temp_file.RemoveExtension().BaseName().value(); | 480 file_name = temp_file.RemoveExtension().BaseName().value(); |
| 479 // Get safe pure file name. | 481 // Get safe pure file name. |
| 480 if (!GetSafePureFileName(saved_main_directory_path_, | 482 if (!GetSafePureFileName(saved_main_directory_path_, |
| 481 FilePath::StringType(), | 483 base::FilePath::StringType(), |
| 482 max_path, &file_name)) | 484 max_path, &file_name)) |
| 483 return false; | 485 return false; |
| 484 } else { | 486 } else { |
| 485 for (int i = ordinal_number; i < kMaxFileOrdinalNumber; ++i) { | 487 for (int i = ordinal_number; i < kMaxFileOrdinalNumber; ++i) { |
| 486 FilePath::StringType new_name = base_file_name + | 488 base::FilePath::StringType new_name = base_file_name + |
| 487 StringPrintf(FILE_PATH_LITERAL("(%d)"), i) + file_name_ext; | 489 StringPrintf(FILE_PATH_LITERAL("(%d)"), i) + file_name_ext; |
| 488 if (file_name_set_.find(new_name) == file_name_set_.end()) { | 490 if (file_name_set_.find(new_name) == file_name_set_.end()) { |
| 489 // Resolved name conflict. | 491 // Resolved name conflict. |
| 490 file_name = new_name; | 492 file_name = new_name; |
| 491 file_name_count_map_[base_file_name] = ++i; | 493 file_name_count_map_[base_file_name] = ++i; |
| 492 break; | 494 break; |
| 493 } | 495 } |
| 494 } | 496 } |
| 495 } | 497 } |
| 496 | 498 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 518 | 520 |
| 519 DCHECK(!saved_main_file_path_.empty()); | 521 DCHECK(!saved_main_file_path_.empty()); |
| 520 | 522 |
| 521 save_item->SetSaveId(info->save_id); | 523 save_item->SetSaveId(info->save_id); |
| 522 save_item->SetTotalBytes(info->total_bytes); | 524 save_item->SetTotalBytes(info->total_bytes); |
| 523 | 525 |
| 524 // Determine the proper path for a saving job, by choosing either the default | 526 // Determine the proper path for a saving job, by choosing either the default |
| 525 // save directory, or prompting the user. | 527 // save directory, or prompting the user. |
| 526 DCHECK(!save_item->has_final_name()); | 528 DCHECK(!save_item->has_final_name()); |
| 527 if (info->url != page_url_) { | 529 if (info->url != page_url_) { |
| 528 FilePath::StringType generated_name; | 530 base::FilePath::StringType generated_name; |
| 529 // For HTML resource file, make sure it will have .htm as extension name, | 531 // For HTML resource file, make sure it will have .htm as extension name, |
| 530 // otherwise, when you open the saved page in Chrome again, download | 532 // otherwise, when you open the saved page in Chrome again, download |
| 531 // file manager will treat it as downloadable resource, and download it | 533 // file manager will treat it as downloadable resource, and download it |
| 532 // instead of opening it as HTML. | 534 // instead of opening it as HTML. |
| 533 bool need_html_ext = | 535 bool need_html_ext = |
| 534 info->save_source == SaveFileCreateInfo::SAVE_FILE_FROM_DOM; | 536 info->save_source == SaveFileCreateInfo::SAVE_FILE_FROM_DOM; |
| 535 if (!GenerateFileName(info->content_disposition, | 537 if (!GenerateFileName(info->content_disposition, |
| 536 GURL(info->url), | 538 GURL(info->url), |
| 537 need_html_ext, | 539 need_html_ext, |
| 538 &generated_name)) { | 540 &generated_name)) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 549 return; | 551 return; |
| 550 } | 552 } |
| 551 | 553 |
| 552 // When saving page as only-HTML, we only have a SaveItem whose url | 554 // When saving page as only-HTML, we only have a SaveItem whose url |
| 553 // must be page_url_. | 555 // must be page_url_. |
| 554 DCHECK(save_type_ == SAVE_PAGE_TYPE_AS_COMPLETE_HTML); | 556 DCHECK(save_type_ == SAVE_PAGE_TYPE_AS_COMPLETE_HTML); |
| 555 DCHECK(!saved_main_directory_path_.empty()); | 557 DCHECK(!saved_main_directory_path_.empty()); |
| 556 | 558 |
| 557 // Now we get final name retrieved from GenerateFileName, we will use it | 559 // Now we get final name retrieved from GenerateFileName, we will use it |
| 558 // rename the SaveItem. | 560 // rename the SaveItem. |
| 559 FilePath final_name = saved_main_directory_path_.Append(generated_name); | 561 base::FilePath final_name = |
| 562 saved_main_directory_path_.Append(generated_name); |
| 560 save_item->Rename(final_name); | 563 save_item->Rename(final_name); |
| 561 } else { | 564 } else { |
| 562 // It is the main HTML file, use the name chosen by the user. | 565 // It is the main HTML file, use the name chosen by the user. |
| 563 save_item->Rename(saved_main_file_path_); | 566 save_item->Rename(saved_main_file_path_); |
| 564 } | 567 } |
| 565 | 568 |
| 566 // If the save source is from file system, inform SaveFileManager to copy | 569 // If the save source is from file system, inform SaveFileManager to copy |
| 567 // corresponding file to the file path which this SaveItem specifies. | 570 // corresponding file to the file path which this SaveItem specifies. |
| 568 if (info->save_source == SaveFileCreateInfo::SAVE_FILE_FROM_FILE) { | 571 if (info->save_source == SaveFileCreateInfo::SAVE_FILE_FROM_FILE) { |
| 569 BrowserThread::PostTask( | 572 BrowserThread::PostTask( |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 685 if (download_) { | 688 if (download_) { |
| 686 download_->Cancel(false); | 689 download_->Cancel(false); |
| 687 FinalizeDownloadEntry(); | 690 FinalizeDownloadEntry(); |
| 688 } | 691 } |
| 689 } | 692 } |
| 690 | 693 |
| 691 void SavePackage::CheckFinish() { | 694 void SavePackage::CheckFinish() { |
| 692 if (in_process_count() || finished_) | 695 if (in_process_count() || finished_) |
| 693 return; | 696 return; |
| 694 | 697 |
| 695 FilePath dir = (save_type_ == SAVE_PAGE_TYPE_AS_COMPLETE_HTML && | 698 base::FilePath dir = (save_type_ == SAVE_PAGE_TYPE_AS_COMPLETE_HTML && |
| 696 saved_success_items_.size() > 1) ? | 699 saved_success_items_.size() > 1) ? |
| 697 saved_main_directory_path_ : FilePath(); | 700 saved_main_directory_path_ : base::FilePath(); |
| 698 | 701 |
| 699 // This vector contains the final names of all the successfully saved files | 702 // This vector contains the final names of all the successfully saved files |
| 700 // along with their save ids. It will be passed to SaveFileManager to do the | 703 // along with their save ids. It will be passed to SaveFileManager to do the |
| 701 // renaming job. | 704 // renaming job. |
| 702 FinalNameList final_names; | 705 FinalNameList final_names; |
| 703 for (SavedItemMap::iterator it = saved_success_items_.begin(); | 706 for (SavedItemMap::iterator it = saved_success_items_.begin(); |
| 704 it != saved_success_items_.end(); ++it) | 707 it != saved_success_items_.end(); ++it) |
| 705 final_names.push_back(std::make_pair(it->first, | 708 final_names.push_back(std::make_pair(it->first, |
| 706 it->second->full_path())); | 709 it->second->full_path())); |
| 707 | 710 |
| (...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 965 } | 968 } |
| 966 | 969 |
| 967 // After finishing all SaveItems which need to get data from net. | 970 // After finishing all SaveItems which need to get data from net. |
| 968 // We collect all URLs which have local storage and send the | 971 // We collect all URLs which have local storage and send the |
| 969 // map:(originalURL:currentLocalPath) to render process (backend). | 972 // map:(originalURL:currentLocalPath) to render process (backend). |
| 970 // Then render process will serialize DOM and send data to us. | 973 // Then render process will serialize DOM and send data to us. |
| 971 void SavePackage::GetSerializedHtmlDataForCurrentPageWithLocalLinks() { | 974 void SavePackage::GetSerializedHtmlDataForCurrentPageWithLocalLinks() { |
| 972 if (wait_state_ != HTML_DATA) | 975 if (wait_state_ != HTML_DATA) |
| 973 return; | 976 return; |
| 974 std::vector<GURL> saved_links; | 977 std::vector<GURL> saved_links; |
| 975 std::vector<FilePath> saved_file_paths; | 978 std::vector<base::FilePath> saved_file_paths; |
| 976 int successful_started_items_count = 0; | 979 int successful_started_items_count = 0; |
| 977 | 980 |
| 978 // Collect all saved items which have local storage. | 981 // Collect all saved items which have local storage. |
| 979 // First collect the status of all the resource files and check whether they | 982 // First collect the status of all the resource files and check whether they |
| 980 // have created local files although they have not been completely saved. | 983 // have created local files although they have not been completely saved. |
| 981 // If yes, the file can be saved. Otherwise, there is a disk error, so we | 984 // If yes, the file can be saved. Otherwise, there is a disk error, so we |
| 982 // need to cancel the page saving job. | 985 // need to cancel the page saving job. |
| 983 for (SaveUrlItemMap::iterator it = in_progress_items_.begin(); | 986 for (SaveUrlItemMap::iterator it = in_progress_items_.begin(); |
| 984 it != in_progress_items_.end(); ++it) { | 987 it != in_progress_items_.end(); ++it) { |
| 985 DCHECK(it->second->save_source() == | 988 DCHECK(it->second->save_source() == |
| (...skipping 10 matching lines...) Expand all Loading... |
| 996 | 999 |
| 997 // Collect all saved success items. | 1000 // Collect all saved success items. |
| 998 for (SavedItemMap::iterator it = saved_success_items_.begin(); | 1001 for (SavedItemMap::iterator it = saved_success_items_.begin(); |
| 999 it != saved_success_items_.end(); ++it) { | 1002 it != saved_success_items_.end(); ++it) { |
| 1000 DCHECK(it->second->has_final_name()); | 1003 DCHECK(it->second->has_final_name()); |
| 1001 saved_links.push_back(it->second->url()); | 1004 saved_links.push_back(it->second->url()); |
| 1002 saved_file_paths.push_back(it->second->file_name()); | 1005 saved_file_paths.push_back(it->second->file_name()); |
| 1003 } | 1006 } |
| 1004 | 1007 |
| 1005 // Get the relative directory name. | 1008 // Get the relative directory name. |
| 1006 FilePath relative_dir_name = saved_main_directory_path_.BaseName(); | 1009 base::FilePath relative_dir_name = saved_main_directory_path_.BaseName(); |
| 1007 | 1010 |
| 1008 Send(new ViewMsg_GetSerializedHtmlDataForCurrentPageWithLocalLinks( | 1011 Send(new ViewMsg_GetSerializedHtmlDataForCurrentPageWithLocalLinks( |
| 1009 routing_id(), saved_links, saved_file_paths, relative_dir_name)); | 1012 routing_id(), saved_links, saved_file_paths, relative_dir_name)); |
| 1010 } | 1013 } |
| 1011 | 1014 |
| 1012 // Process the serialized HTML content data of a specified web page | 1015 // Process the serialized HTML content data of a specified web page |
| 1013 // retrieved from render process. | 1016 // retrieved from render process. |
| 1014 void SavePackage::OnReceivedSerializedHtmlData(const GURL& frame_url, | 1017 void SavePackage::OnReceivedSerializedHtmlData(const GURL& frame_url, |
| 1015 const std::string& data, | 1018 const std::string& data, |
| 1016 int32 status) { | 1019 int32 status) { |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1147 waiting_item_queue_.push(save_item); | 1150 waiting_item_queue_.push(save_item); |
| 1148 } | 1151 } |
| 1149 wait_state_ = NET_FILES; | 1152 wait_state_ = NET_FILES; |
| 1150 DoSavingProcess(); | 1153 DoSavingProcess(); |
| 1151 } else { | 1154 } else { |
| 1152 // No resource files need to be saved, treat it as user cancel. | 1155 // No resource files need to be saved, treat it as user cancel. |
| 1153 Cancel(true); | 1156 Cancel(true); |
| 1154 } | 1157 } |
| 1155 } | 1158 } |
| 1156 | 1159 |
| 1157 FilePath SavePackage::GetSuggestedNameForSaveAs( | 1160 base::FilePath SavePackage::GetSuggestedNameForSaveAs( |
| 1158 bool can_save_as_complete, | 1161 bool can_save_as_complete, |
| 1159 const std::string& contents_mime_type, | 1162 const std::string& contents_mime_type, |
| 1160 const std::string& accept_langs) { | 1163 const std::string& accept_langs) { |
| 1161 FilePath name_with_proper_ext = | 1164 base::FilePath name_with_proper_ext = |
| 1162 FilePath::FromWStringHack(UTF16ToWideHack(title_)); | 1165 base::FilePath::FromWStringHack(UTF16ToWideHack(title_)); |
| 1163 | 1166 |
| 1164 // If the page's title matches its URL, use the URL. Try to use the last path | 1167 // If the page's title matches its URL, use the URL. Try to use the last path |
| 1165 // component or if there is none, the domain as the file name. | 1168 // component or if there is none, the domain as the file name. |
| 1166 // Normally we want to base the filename on the page title, or if it doesn't | 1169 // Normally we want to base the filename on the page title, or if it doesn't |
| 1167 // exist, on the URL. It's not easy to tell if the page has no title, because | 1170 // exist, on the URL. It's not easy to tell if the page has no title, because |
| 1168 // if the page has no title, WebContents::GetTitle() will return the page's | 1171 // if the page has no title, WebContents::GetTitle() will return the page's |
| 1169 // URL (adjusted for display purposes). Therefore, we convert the "title" | 1172 // URL (adjusted for display purposes). Therefore, we convert the "title" |
| 1170 // back to a URL, and if it matches the original page URL, we know the page | 1173 // back to a URL, and if it matches the original page URL, we know the page |
| 1171 // had no title (or had a title equal to its URL, which is fine to treat | 1174 // had no title (or had a title equal to its URL, which is fine to treat |
| 1172 // similarly). | 1175 // similarly). |
| 1173 if (title_ == net::FormatUrl(page_url_, accept_langs)) { | 1176 if (title_ == net::FormatUrl(page_url_, accept_langs)) { |
| 1174 std::string url_path; | 1177 std::string url_path; |
| 1175 if (!page_url_.SchemeIs(chrome::kDataScheme)) { | 1178 if (!page_url_.SchemeIs(chrome::kDataScheme)) { |
| 1176 std::vector<std::string> url_parts; | 1179 std::vector<std::string> url_parts; |
| 1177 base::SplitString(page_url_.path(), '/', &url_parts); | 1180 base::SplitString(page_url_.path(), '/', &url_parts); |
| 1178 if (!url_parts.empty()) { | 1181 if (!url_parts.empty()) { |
| 1179 for (int i = static_cast<int>(url_parts.size()) - 1; i >= 0; --i) { | 1182 for (int i = static_cast<int>(url_parts.size()) - 1; i >= 0; --i) { |
| 1180 url_path = url_parts[i]; | 1183 url_path = url_parts[i]; |
| 1181 if (!url_path.empty()) | 1184 if (!url_path.empty()) |
| 1182 break; | 1185 break; |
| 1183 } | 1186 } |
| 1184 } | 1187 } |
| 1185 if (url_path.empty()) | 1188 if (url_path.empty()) |
| 1186 url_path = page_url_.host(); | 1189 url_path = page_url_.host(); |
| 1187 } else { | 1190 } else { |
| 1188 url_path = "dataurl"; | 1191 url_path = "dataurl"; |
| 1189 } | 1192 } |
| 1190 name_with_proper_ext = FilePath::FromWStringHack(UTF8ToWide(url_path)); | 1193 name_with_proper_ext = |
| 1194 base::FilePath::FromWStringHack(UTF8ToWide(url_path)); |
| 1191 } | 1195 } |
| 1192 | 1196 |
| 1193 // Ask user for getting final saving name. | 1197 // Ask user for getting final saving name. |
| 1194 name_with_proper_ext = EnsureMimeExtension(name_with_proper_ext, | 1198 name_with_proper_ext = EnsureMimeExtension(name_with_proper_ext, |
| 1195 contents_mime_type); | 1199 contents_mime_type); |
| 1196 // Adjust extension for complete types. | 1200 // Adjust extension for complete types. |
| 1197 if (can_save_as_complete) | 1201 if (can_save_as_complete) |
| 1198 name_with_proper_ext = EnsureHtmlExtension(name_with_proper_ext); | 1202 name_with_proper_ext = EnsureHtmlExtension(name_with_proper_ext); |
| 1199 | 1203 |
| 1200 FilePath::StringType file_name = name_with_proper_ext.value(); | 1204 base::FilePath::StringType file_name = name_with_proper_ext.value(); |
| 1201 file_util::ReplaceIllegalCharactersInPath(&file_name, ' '); | 1205 file_util::ReplaceIllegalCharactersInPath(&file_name, ' '); |
| 1202 return FilePath(file_name); | 1206 return base::FilePath(file_name); |
| 1203 } | 1207 } |
| 1204 | 1208 |
| 1205 FilePath SavePackage::EnsureHtmlExtension(const FilePath& name) { | 1209 base::FilePath SavePackage::EnsureHtmlExtension(const base::FilePath& name) { |
| 1206 // If the file name doesn't have an extension suitable for HTML files, | 1210 // If the file name doesn't have an extension suitable for HTML files, |
| 1207 // append one. | 1211 // append one. |
| 1208 FilePath::StringType ext = name.Extension(); | 1212 base::FilePath::StringType ext = name.Extension(); |
| 1209 if (!ext.empty()) | 1213 if (!ext.empty()) |
| 1210 ext.erase(ext.begin()); // Erase preceding '.'. | 1214 ext.erase(ext.begin()); // Erase preceding '.'. |
| 1211 std::string mime_type; | 1215 std::string mime_type; |
| 1212 if (!net::GetMimeTypeFromExtension(ext, &mime_type) || | 1216 if (!net::GetMimeTypeFromExtension(ext, &mime_type) || |
| 1213 !CanSaveAsComplete(mime_type)) { | 1217 !CanSaveAsComplete(mime_type)) { |
| 1214 return FilePath(name.value() + FILE_PATH_LITERAL(".") + | 1218 return base::FilePath(name.value() + FILE_PATH_LITERAL(".") + |
| 1215 kDefaultHtmlExtension); | 1219 kDefaultHtmlExtension); |
| 1216 } | 1220 } |
| 1217 return name; | 1221 return name; |
| 1218 } | 1222 } |
| 1219 | 1223 |
| 1220 FilePath SavePackage::EnsureMimeExtension(const FilePath& name, | 1224 base::FilePath SavePackage::EnsureMimeExtension(const base::FilePath& name, |
| 1221 const std::string& contents_mime_type) { | 1225 const std::string& contents_mime_type) { |
| 1222 // Start extension at 1 to skip over period if non-empty. | 1226 // Start extension at 1 to skip over period if non-empty. |
| 1223 FilePath::StringType ext = name.Extension().length() ? | 1227 base::FilePath::StringType ext = name.Extension().length() ? |
| 1224 name.Extension().substr(1) : name.Extension(); | 1228 name.Extension().substr(1) : name.Extension(); |
| 1225 FilePath::StringType suggested_extension = | 1229 base::FilePath::StringType suggested_extension = |
| 1226 ExtensionForMimeType(contents_mime_type); | 1230 ExtensionForMimeType(contents_mime_type); |
| 1227 std::string mime_type; | 1231 std::string mime_type; |
| 1228 if (!suggested_extension.empty() && | 1232 if (!suggested_extension.empty() && |
| 1229 !net::GetMimeTypeFromExtension(ext, &mime_type)) { | 1233 !net::GetMimeTypeFromExtension(ext, &mime_type)) { |
| 1230 // Extension is absent or needs to be updated. | 1234 // Extension is absent or needs to be updated. |
| 1231 return FilePath(name.value() + FILE_PATH_LITERAL(".") + | 1235 return base::FilePath(name.value() + FILE_PATH_LITERAL(".") + |
| 1232 suggested_extension); | 1236 suggested_extension); |
| 1233 } | 1237 } |
| 1234 return name; | 1238 return name; |
| 1235 } | 1239 } |
| 1236 | 1240 |
| 1237 const FilePath::CharType* SavePackage::ExtensionForMimeType( | 1241 const base::FilePath::CharType* SavePackage::ExtensionForMimeType( |
| 1238 const std::string& contents_mime_type) { | 1242 const std::string& contents_mime_type) { |
| 1239 static const struct { | 1243 static const struct { |
| 1240 const FilePath::CharType *mime_type; | 1244 const base::FilePath::CharType *mime_type; |
| 1241 const FilePath::CharType *suggested_extension; | 1245 const base::FilePath::CharType *suggested_extension; |
| 1242 } extensions[] = { | 1246 } extensions[] = { |
| 1243 { FILE_PATH_LITERAL("text/html"), kDefaultHtmlExtension }, | 1247 { FILE_PATH_LITERAL("text/html"), kDefaultHtmlExtension }, |
| 1244 { FILE_PATH_LITERAL("text/xml"), FILE_PATH_LITERAL("xml") }, | 1248 { FILE_PATH_LITERAL("text/xml"), FILE_PATH_LITERAL("xml") }, |
| 1245 { FILE_PATH_LITERAL("application/xhtml+xml"), FILE_PATH_LITERAL("xhtml") }, | 1249 { FILE_PATH_LITERAL("application/xhtml+xml"), FILE_PATH_LITERAL("xhtml") }, |
| 1246 { FILE_PATH_LITERAL("text/plain"), FILE_PATH_LITERAL("txt") }, | 1250 { FILE_PATH_LITERAL("text/plain"), FILE_PATH_LITERAL("txt") }, |
| 1247 { FILE_PATH_LITERAL("text/css"), FILE_PATH_LITERAL("css") }, | 1251 { FILE_PATH_LITERAL("text/css"), FILE_PATH_LITERAL("css") }, |
| 1248 }; | 1252 }; |
| 1249 #if defined(OS_POSIX) | 1253 #if defined(OS_POSIX) |
| 1250 FilePath::StringType mime_type(contents_mime_type); | 1254 base::FilePath::StringType mime_type(contents_mime_type); |
| 1251 #elif defined(OS_WIN) | 1255 #elif defined(OS_WIN) |
| 1252 FilePath::StringType mime_type(UTF8ToWide(contents_mime_type)); | 1256 base::FilePath::StringType mime_type(UTF8ToWide(contents_mime_type)); |
| 1253 #endif // OS_WIN | 1257 #endif // OS_WIN |
| 1254 for (uint32 i = 0; i < ARRAYSIZE_UNSAFE(extensions); ++i) { | 1258 for (uint32 i = 0; i < ARRAYSIZE_UNSAFE(extensions); ++i) { |
| 1255 if (mime_type == extensions[i].mime_type) | 1259 if (mime_type == extensions[i].mime_type) |
| 1256 return extensions[i].suggested_extension; | 1260 return extensions[i].suggested_extension; |
| 1257 } | 1261 } |
| 1258 return FILE_PATH_LITERAL(""); | 1262 return FILE_PATH_LITERAL(""); |
| 1259 } | 1263 } |
| 1260 | 1264 |
| 1261 WebContents* SavePackage::web_contents() const { | 1265 WebContents* SavePackage::web_contents() const { |
| 1262 return WebContentsObserver::web_contents(); | 1266 return WebContentsObserver::web_contents(); |
| 1263 } | 1267 } |
| 1264 | 1268 |
| 1265 void SavePackage::GetSaveInfo() { | 1269 void SavePackage::GetSaveInfo() { |
| 1266 // Can't use web_contents_ in the file thread, so get the data that we need | 1270 // Can't use web_contents_ in the file thread, so get the data that we need |
| 1267 // before calling to it. | 1271 // before calling to it. |
| 1268 FilePath website_save_dir, download_save_dir; | 1272 base::FilePath website_save_dir, download_save_dir; |
| 1269 bool skip_dir_check; | 1273 bool skip_dir_check; |
| 1270 DCHECK(download_manager_); | 1274 DCHECK(download_manager_); |
| 1271 if (download_manager_->GetDelegate()) { | 1275 if (download_manager_->GetDelegate()) { |
| 1272 download_manager_->GetDelegate()->GetSaveDir( | 1276 download_manager_->GetDelegate()->GetSaveDir( |
| 1273 web_contents()->GetBrowserContext(), &website_save_dir, | 1277 web_contents()->GetBrowserContext(), &website_save_dir, |
| 1274 &download_save_dir, &skip_dir_check); | 1278 &download_save_dir, &skip_dir_check); |
| 1275 } | 1279 } |
| 1276 std::string mime_type = web_contents()->GetContentsMimeType(); | 1280 std::string mime_type = web_contents()->GetContentsMimeType(); |
| 1277 std::string accept_languages = | 1281 std::string accept_languages = |
| 1278 GetContentClient()->browser()->GetAcceptLangs( | 1282 GetContentClient()->browser()->GetAcceptLangs( |
| 1279 web_contents()->GetBrowserContext()); | 1283 web_contents()->GetBrowserContext()); |
| 1280 | 1284 |
| 1281 BrowserThread::PostTask( | 1285 BrowserThread::PostTask( |
| 1282 BrowserThread::FILE, FROM_HERE, | 1286 BrowserThread::FILE, FROM_HERE, |
| 1283 base::Bind(&SavePackage::CreateDirectoryOnFileThread, this, | 1287 base::Bind(&SavePackage::CreateDirectoryOnFileThread, this, |
| 1284 website_save_dir, download_save_dir, skip_dir_check, | 1288 website_save_dir, download_save_dir, skip_dir_check, |
| 1285 mime_type, accept_languages)); | 1289 mime_type, accept_languages)); |
| 1286 } | 1290 } |
| 1287 | 1291 |
| 1288 void SavePackage::CreateDirectoryOnFileThread( | 1292 void SavePackage::CreateDirectoryOnFileThread( |
| 1289 const FilePath& website_save_dir, | 1293 const base::FilePath& website_save_dir, |
| 1290 const FilePath& download_save_dir, | 1294 const base::FilePath& download_save_dir, |
| 1291 bool skip_dir_check, | 1295 bool skip_dir_check, |
| 1292 const std::string& mime_type, | 1296 const std::string& mime_type, |
| 1293 const std::string& accept_langs) { | 1297 const std::string& accept_langs) { |
| 1294 FilePath save_dir; | 1298 base::FilePath save_dir; |
| 1295 // If the default html/websites save folder doesn't exist... | 1299 // If the default html/websites save folder doesn't exist... |
| 1296 // We skip the directory check for gdata directories on ChromeOS. | 1300 // We skip the directory check for gdata directories on ChromeOS. |
| 1297 if (!skip_dir_check && !file_util::DirectoryExists(website_save_dir)) { | 1301 if (!skip_dir_check && !file_util::DirectoryExists(website_save_dir)) { |
| 1298 // If the default download dir doesn't exist, create it. | 1302 // If the default download dir doesn't exist, create it. |
| 1299 if (!file_util::DirectoryExists(download_save_dir)) { | 1303 if (!file_util::DirectoryExists(download_save_dir)) { |
| 1300 bool res = file_util::CreateDirectory(download_save_dir); | 1304 bool res = file_util::CreateDirectory(download_save_dir); |
| 1301 DCHECK(res); | 1305 DCHECK(res); |
| 1302 } | 1306 } |
| 1303 save_dir = download_save_dir; | 1307 save_dir = download_save_dir; |
| 1304 } else { | 1308 } else { |
| 1305 // If it does exist, use the default save dir param. | 1309 // If it does exist, use the default save dir param. |
| 1306 save_dir = website_save_dir; | 1310 save_dir = website_save_dir; |
| 1307 } | 1311 } |
| 1308 | 1312 |
| 1309 bool can_save_as_complete = CanSaveAsComplete(mime_type); | 1313 bool can_save_as_complete = CanSaveAsComplete(mime_type); |
| 1310 FilePath suggested_filename = GetSuggestedNameForSaveAs( | 1314 base::FilePath suggested_filename = GetSuggestedNameForSaveAs( |
| 1311 can_save_as_complete, mime_type, accept_langs); | 1315 can_save_as_complete, mime_type, accept_langs); |
| 1312 FilePath::StringType pure_file_name = | 1316 base::FilePath::StringType pure_file_name = |
| 1313 suggested_filename.RemoveExtension().BaseName().value(); | 1317 suggested_filename.RemoveExtension().BaseName().value(); |
| 1314 FilePath::StringType file_name_ext = suggested_filename.Extension(); | 1318 base::FilePath::StringType file_name_ext = suggested_filename.Extension(); |
| 1315 | 1319 |
| 1316 // Need to make sure the suggested file name is not too long. | 1320 // Need to make sure the suggested file name is not too long. |
| 1317 uint32 max_path = GetMaxPathLengthForDirectory(save_dir); | 1321 uint32 max_path = GetMaxPathLengthForDirectory(save_dir); |
| 1318 | 1322 |
| 1319 if (GetSafePureFileName(save_dir, file_name_ext, max_path, &pure_file_name)) { | 1323 if (GetSafePureFileName(save_dir, file_name_ext, max_path, &pure_file_name)) { |
| 1320 save_dir = save_dir.Append(pure_file_name + file_name_ext); | 1324 save_dir = save_dir.Append(pure_file_name + file_name_ext); |
| 1321 } else { | 1325 } else { |
| 1322 // Cannot create a shorter filename. This will cause the save as operation | 1326 // Cannot create a shorter filename. This will cause the save as operation |
| 1323 // to fail unless the user pick a shorter name. Continuing even though it | 1327 // to fail unless the user pick a shorter name. Continuing even though it |
| 1324 // will fail because returning means no save as popup for the user, which | 1328 // will fail because returning means no save as popup for the user, which |
| 1325 // is even more confusing. This case should be rare though. | 1329 // is even more confusing. This case should be rare though. |
| 1326 save_dir = save_dir.Append(suggested_filename); | 1330 save_dir = save_dir.Append(suggested_filename); |
| 1327 } | 1331 } |
| 1328 | 1332 |
| 1329 BrowserThread::PostTask( | 1333 BrowserThread::PostTask( |
| 1330 BrowserThread::UI, FROM_HERE, | 1334 BrowserThread::UI, FROM_HERE, |
| 1331 base::Bind(&SavePackage::ContinueGetSaveInfo, this, save_dir, | 1335 base::Bind(&SavePackage::ContinueGetSaveInfo, this, save_dir, |
| 1332 can_save_as_complete)); | 1336 can_save_as_complete)); |
| 1333 } | 1337 } |
| 1334 | 1338 |
| 1335 void SavePackage::ContinueGetSaveInfo(const FilePath& suggested_path, | 1339 void SavePackage::ContinueGetSaveInfo(const base::FilePath& suggested_path, |
| 1336 bool can_save_as_complete) { | 1340 bool can_save_as_complete) { |
| 1337 | 1341 |
| 1338 // The WebContents which owns this SavePackage may have disappeared during | 1342 // The WebContents which owns this SavePackage may have disappeared during |
| 1339 // the UI->FILE->UI thread hop of | 1343 // the UI->FILE->UI thread hop of |
| 1340 // GetSaveInfo->CreateDirectoryOnFileThread->ContinueGetSaveInfo. | 1344 // GetSaveInfo->CreateDirectoryOnFileThread->ContinueGetSaveInfo. |
| 1341 if (!web_contents() || !download_manager_->GetDelegate()) | 1345 if (!web_contents() || !download_manager_->GetDelegate()) |
| 1342 return; | 1346 return; |
| 1343 | 1347 |
| 1344 FilePath::StringType default_extension; | 1348 base::FilePath::StringType default_extension; |
| 1345 if (can_save_as_complete) | 1349 if (can_save_as_complete) |
| 1346 default_extension = kDefaultHtmlExtension; | 1350 default_extension = kDefaultHtmlExtension; |
| 1347 | 1351 |
| 1348 download_manager_->GetDelegate()->ChooseSavePath( | 1352 download_manager_->GetDelegate()->ChooseSavePath( |
| 1349 web_contents(), | 1353 web_contents(), |
| 1350 suggested_path, | 1354 suggested_path, |
| 1351 default_extension, | 1355 default_extension, |
| 1352 can_save_as_complete, | 1356 can_save_as_complete, |
| 1353 base::Bind(&SavePackage::OnPathPicked, AsWeakPtr())); | 1357 base::Bind(&SavePackage::OnPathPicked, AsWeakPtr())); |
| 1354 } | 1358 } |
| 1355 | 1359 |
| 1356 void SavePackage::OnPathPicked( | 1360 void SavePackage::OnPathPicked( |
| 1357 const FilePath& final_name, | 1361 const base::FilePath& final_name, |
| 1358 SavePageType type, | 1362 SavePageType type, |
| 1359 const SavePackageDownloadCreatedCallback& download_created_callback) { | 1363 const SavePackageDownloadCreatedCallback& download_created_callback) { |
| 1360 // Ensure the filename is safe. | 1364 // Ensure the filename is safe. |
| 1361 saved_main_file_path_ = final_name; | 1365 saved_main_file_path_ = final_name; |
| 1362 // TODO(asanka): This call may block on IO and shouldn't be made | 1366 // TODO(asanka): This call may block on IO and shouldn't be made |
| 1363 // from the UI thread. See http://crbug.com/61827. | 1367 // from the UI thread. See http://crbug.com/61827. |
| 1364 net::GenerateSafeFileName(web_contents()->GetContentsMimeType(), false, | 1368 net::GenerateSafeFileName(web_contents()->GetContentsMimeType(), false, |
| 1365 &saved_main_file_path_); | 1369 &saved_main_file_path_); |
| 1366 | 1370 |
| 1367 saved_main_directory_path_ = saved_main_file_path_.DirName(); | 1371 saved_main_directory_path_ = saved_main_file_path_.DirName(); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 1391 | 1395 |
| 1392 void SavePackage::FinalizeDownloadEntry() { | 1396 void SavePackage::FinalizeDownloadEntry() { |
| 1393 DCHECK(download_); | 1397 DCHECK(download_); |
| 1394 DCHECK(download_manager_); | 1398 DCHECK(download_manager_); |
| 1395 | 1399 |
| 1396 download_manager_->OnSavePackageSuccessfullyFinished(download_); | 1400 download_manager_->OnSavePackageSuccessfullyFinished(download_); |
| 1397 StopObservation(); | 1401 StopObservation(); |
| 1398 } | 1402 } |
| 1399 | 1403 |
| 1400 } // namespace content | 1404 } // namespace content |
| OLD | NEW |