save_package.cc revision c5cede9ae108bb15f6b7a8aea21c7e1fefa2834c
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/download/save_package.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/file_util.h" 112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/i18n/file_util_icu.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 149ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_util.h" 16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/strings/string_piece.h" 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_split.h" 18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/strings/sys_string_conversions.h" 19868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/download/download_item_impl.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/download/download_manager_impl.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/download/download_stats.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/download/save_file.h" 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/download/save_file_manager.h" 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/download/save_item.h" 272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/browser/loader/resource_dispatcher_host_impl.h" 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/renderer_host/render_process_host_impl.h" 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/renderer_host/render_view_host_delegate.h" 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/renderer_host/render_view_host_impl.h" 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/common/view_messages.h" 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_context.h" 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h" 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/content_browser_client.h" 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/download_manager_delegate.h" 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/navigation_entry.h" 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_service.h" 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_types.h" 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/resource_context.h" 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_contents.h" 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/common/url_constants.h" 42c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "net/base/filename_util.h" 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/io_buffer.h" 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/mime_util.h" 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_request_context.h" 467d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "third_party/WebKit/public/web/WebPageSerializerClient.h" 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::Time; 49f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using blink::WebPageSerializerClient; 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace content { 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A counter for uniquely identifying each save package. 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int g_save_package_id = 0; 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Default name which will be used when we can not get proper name from 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// resource URL. 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kDefaultSaveName[] = "saved_resource"; 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Maximum number of file ordinal number. I think it's big enough for resolving 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// name-conflict files which has same base file name. 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int32 kMaxFileOrdinalNumber = 9999; 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Maximum length for file path. Since Windows have MAX_PATH limitation for 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// file path, we need to make sure length of file path of every saved file 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// is less than MAX_PATH 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN) 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const uint32 kMaxFilePathLength = MAX_PATH - 1; 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_POSIX) 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const uint32 kMaxFilePathLength = PATH_MAX - 1; 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Maximum length for file ordinal number part. Since we only support the 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// maximum 9999 for ordinal number, which means maximum file ordinal number part 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// should be "(9998)", so the value is 6. 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const uint32 kMaxFileOrdinalNumberPartLength = 6; 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Strip current ordinal number, if any. Should only be used on pure 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// file names, i.e. those stripped of their extensions. 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(estade): improve this to not choke on alternate encodings. 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath::StringType StripOrdinalNumber( 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath::StringType& pure_file_name) { 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath::StringType::size_type r_paren_index = 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pure_file_name.rfind(FILE_PATH_LITERAL(')')); 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath::StringType::size_type l_paren_index = 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pure_file_name.rfind(FILE_PATH_LITERAL('(')); 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (l_paren_index >= r_paren_index) 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return pure_file_name; 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (base::FilePath::StringType::size_type i = l_paren_index + 1; 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i != r_paren_index; ++i) { 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!IsAsciiDigit(pure_file_name[i])) 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return pure_file_name; 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return pure_file_name.substr(0, l_paren_index); 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Check whether we can save page as complete-HTML for the contents which 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// have specified a MIME type. Now only contents which have the MIME type 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// "text/html" can be saved as complete-HTML. 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CanSaveAsComplete(const std::string& contents_mime_type) { 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return contents_mime_type == "text/html" || 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) contents_mime_type == "application/xhtml+xml"; 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Request handle for SavePackage downloads. Currently doesn't support 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// pause/resume/cancel, but returns a WebContents. 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class SavePackageRequestHandle : public DownloadRequestHandleInterface { 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public: 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SavePackageRequestHandle(base::WeakPtr<SavePackage> save_package) 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : save_package_(save_package) {} 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // DownloadRequestHandleInterface 1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual WebContents* GetWebContents() const OVERRIDE { 1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return save_package_.get() ? save_package_->web_contents() : NULL; 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual DownloadManager* GetDownloadManager() const OVERRIDE { 1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return NULL; 1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual void PauseRequest() const OVERRIDE {} 1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual void ResumeRequest() const OVERRIDE {} 1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual void CancelRequest() const OVERRIDE {} 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual std::string DebugString() const OVERRIDE { 1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return "SavePackage DownloadRequestHandle"; 1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private: 1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::WeakPtr<SavePackage> save_package_; 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const base::FilePath::CharType SavePackage::kDefaultHtmlExtension[] = 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN) 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FILE_PATH_LITERAL("htm"); 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FILE_PATH_LITERAL("html"); 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SavePackage::SavePackage(WebContents* web_contents, 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SavePageType save_type, 1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath& file_full_path, 1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath& directory_full_path) 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : WebContentsObserver(web_contents), 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_manager_(NULL), 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) download_manager_(NULL), 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) download_(NULL), 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) page_url_(GetUrlToBeSaved()), 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) saved_main_file_path_(file_full_path), 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) saved_main_directory_path_(directory_full_path), 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) title_(web_contents->GetTitle()), 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) start_tick_(base::TimeTicks::Now()), 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) finished_(false), 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mhtml_finishing_(false), 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) user_canceled_(false), 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) disk_error_occurred_(false), 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) save_type_(save_type), 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) all_save_items_count_(0), 1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) file_name_set_(&base::FilePath::CompareLessIgnoreCase), 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wait_state_(INITIALIZE), 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) contents_id_(web_contents->GetRenderProcessHost()->GetID()), 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unique_id_(g_save_package_id++), 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wrote_to_completed_file_(false), 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wrote_to_failed_file_(false) { 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(page_url_.is_valid()); 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK((save_type_ == SAVE_PAGE_TYPE_AS_ONLY_HTML) || 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (save_type_ == SAVE_PAGE_TYPE_AS_MHTML) || 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (save_type_ == SAVE_PAGE_TYPE_AS_COMPLETE_HTML)); 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!saved_main_file_path_.empty() && 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) saved_main_file_path_.value().length() <= kMaxFilePathLength); 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!saved_main_directory_path_.empty() && 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) saved_main_directory_path_.value().length() < kMaxFilePathLength); 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InternalInit(); 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SavePackage::SavePackage(WebContents* web_contents) 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : WebContentsObserver(web_contents), 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_manager_(NULL), 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) download_manager_(NULL), 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) download_(NULL), 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) page_url_(GetUrlToBeSaved()), 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) title_(web_contents->GetTitle()), 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) start_tick_(base::TimeTicks::Now()), 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) finished_(false), 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mhtml_finishing_(false), 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) user_canceled_(false), 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) disk_error_occurred_(false), 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) save_type_(SAVE_PAGE_TYPE_UNKNOWN), 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) all_save_items_count_(0), 1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) file_name_set_(&base::FilePath::CompareLessIgnoreCase), 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wait_state_(INITIALIZE), 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) contents_id_(web_contents->GetRenderProcessHost()->GetID()), 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unique_id_(g_save_package_id++), 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wrote_to_completed_file_(false), 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wrote_to_failed_file_(false) { 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(page_url_.is_valid()); 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InternalInit(); 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This is for testing use. Set |finished_| as true because we don't want 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// method Cancel to be be called in destructor in test mode. 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We also don't call InternalInit(). 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SavePackage::SavePackage(WebContents* web_contents, 2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath& file_full_path, 2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath& directory_full_path) 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : WebContentsObserver(web_contents), 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_manager_(NULL), 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) download_manager_(NULL), 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) download_(NULL), 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) saved_main_file_path_(file_full_path), 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) saved_main_directory_path_(directory_full_path), 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) start_tick_(base::TimeTicks::Now()), 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) finished_(true), 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mhtml_finishing_(false), 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) user_canceled_(false), 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) disk_error_occurred_(false), 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) save_type_(SAVE_PAGE_TYPE_UNKNOWN), 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) all_save_items_count_(0), 2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) file_name_set_(&base::FilePath::CompareLessIgnoreCase), 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wait_state_(INITIALIZE), 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) contents_id_(0), 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unique_id_(g_save_package_id++), 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wrote_to_completed_file_(false), 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wrote_to_failed_file_(false) { 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SavePackage::~SavePackage() { 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Stop receiving saving job's updates 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!finished_ && !canceled()) { 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Unexpected quit. 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Cancel(true); 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We should no longer be observing the DownloadItem at this point. 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(!download_); 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(all_save_items_count_ == (waiting_item_queue_.size() + 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) completed_count() + 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) in_process_count())); 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Free all SaveItems. 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (!waiting_item_queue_.empty()) { 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We still have some items which are waiting for start to save. 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SaveItem* save_item = waiting_item_queue_.front(); 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) waiting_item_queue_.pop(); 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delete save_item; 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) STLDeleteValues(&saved_success_items_); 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) STLDeleteValues(&in_progress_items_); 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) STLDeleteValues(&saved_failed_items_); 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_manager_ = NULL; 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GURL SavePackage::GetUrlToBeSaved() { 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Instead of using web_contents_.GetURL here, we use url() (which is the 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // "real" url of the page) from the NavigationEntry because it reflects its 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // origin rather than the displayed one (returned by GetURL) which may be 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // different (like having "view-source:" on the front). 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NavigationEntry* active_entry = 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) web_contents()->GetController().GetActiveEntry(); 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return active_entry->GetURL(); 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SavePackage::Cancel(bool user_action) { 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!canceled()) { 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (user_action) 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) user_canceled_ = true; 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) disk_error_occurred_ = true; 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Stop(); 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RecordSavePackageEvent(SAVE_PACKAGE_CANCELLED); 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Init() can be called directly, or indirectly via GetSaveInfo(). In both 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// cases, we need file_manager_ to be initialized, so we do this first. 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SavePackage::InternalInit() { 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ResourceDispatcherHostImpl* rdh = ResourceDispatcherHostImpl::Get(); 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!rdh) { 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_manager_ = rdh->save_file_manager(); 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(file_manager_); 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) download_manager_ = static_cast<DownloadManagerImpl*>( 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserContext::GetDownloadManager( 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) web_contents()->GetBrowserContext())); 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(download_manager_); 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RecordSavePackageEvent(SAVE_PACKAGE_STARTED); 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SavePackage::Init( 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const SavePackageDownloadCreatedCallback& download_created_callback) { 3007dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Set proper running state. 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (wait_state_ != INITIALIZE) 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wait_state_ = START_PROCESS; 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Initialize the request context and resource dispatcher. 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserContext* browser_context = web_contents()->GetBrowserContext(); 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!browser_context) { 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_ptr<DownloadRequestHandleInterface> request_handle( 3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) new SavePackageRequestHandle(AsWeakPtr())); 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The download manager keeps ownership but adds us as an observer. 3177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch download_manager_->CreateSavePackageDownloadItem( 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) saved_main_file_path_, 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) page_url_, 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ((save_type_ == SAVE_PAGE_TYPE_AS_MHTML) ? 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "multipart/related" : "text/html"), 3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) request_handle.Pass(), 3237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch base::Bind(&SavePackage::InitWithDownloadItem, AsWeakPtr(), 3247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch download_created_callback)); 3257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch return true; 3267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch} 3277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 3287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid SavePackage::InitWithDownloadItem( 3297dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch const SavePackageDownloadCreatedCallback& download_created_callback, 3307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch DownloadItemImpl* item) { 3317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 3327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch DCHECK(item); 3337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch download_ = item; 3347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch download_->AddObserver(this); 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Confirm above didn't delete the tab out from under us. 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!download_created_callback.is_null()) 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) download_created_callback.Run(download_); 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check save type and process the save page job. 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (save_type_ == SAVE_PAGE_TYPE_AS_COMPLETE_HTML) { 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Get directory 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!saved_main_directory_path_.empty()); 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetAllSavableResourceLinksForCurrentPage(); 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (save_type_ == SAVE_PAGE_TYPE_AS_MHTML) { 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) web_contents()->GenerateMHTML(saved_main_file_path_, base::Bind( 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &SavePackage::OnMHTMLGenerated, this)); 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK_EQ(SAVE_PAGE_TYPE_AS_ONLY_HTML, save_type_) << save_type_; 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wait_state_ = NET_FILES; 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SaveFileCreateInfo::SaveFileSource save_source = page_url_.SchemeIsFile() ? 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SaveFileCreateInfo::SAVE_FILE_FROM_FILE : 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SaveFileCreateInfo::SAVE_FILE_FROM_NET; 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SaveItem* save_item = new SaveItem(page_url_, 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Referrer(), 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this, 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) save_source); 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Add this item to waiting list. 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) waiting_item_queue_.push(save_item); 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) all_save_items_count_ = 1; 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) download_->SetTotalBytes(1); 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DoSavingProcess(); 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 366424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)void SavePackage::OnMHTMLGenerated(int64 size) { 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (size <= 0) { 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Cancel(false); 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wrote_to_completed_file_ = true; 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Hack to avoid touching download_ after user cancel. 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(rdsmith/benjhayden): Integrate canceling on DownloadItem 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // with SavePackage flow. 3767d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (download_->GetState() == DownloadItem::IN_PROGRESS) { 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) download_->SetTotalBytes(size); 37890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) download_->DestinationUpdate(size, 0, std::string()); 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Must call OnAllDataSaved here in order for 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // GDataDownloadObserver::ShouldUpload() to return true. 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ShouldCompleteDownload() may depend on the gdata uploader to finish. 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) download_->OnAllDataSaved(DownloadItem::kEmptyFileHash); 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!download_manager_->GetDelegate()) { 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Finish(); 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (download_manager_->GetDelegate()->ShouldCompleteDownload( 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) download_, base::Bind(&SavePackage::Finish, this))) { 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Finish(); 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// On POSIX, the length of |pure_file_name| + |file_name_ext| is further 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// restricted by NAME_MAX. The maximum allowed path looks like: 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// '/path/to/save_dir' + '/' + NAME_MAX. 3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)uint32 SavePackage::GetMaxPathLengthForDirectory( 4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath& base_dir) { 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_POSIX) 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return std::min(kMaxFilePathLength, 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<uint32>(base_dir.value().length()) + 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NAME_MAX + 1); 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return kMaxFilePathLength; 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// File name is considered being consist of pure file name, dot and file 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// extension name. File name might has no dot and file extension, or has 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// multiple dot inside file name. The dot, which separates the pure file 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// name and file extension name, is last dot in the whole file name. 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This function is for making sure the length of specified file path is not 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// great than the specified maximum length of file path and getting safe pure 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// file name part if the input pure file name is too long. 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The parameter |dir_path| specifies directory part of the specified 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// file path. The parameter |file_name_ext| specifies file extension 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// name part of the specified file path (including start dot). The parameter 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |max_file_path_len| specifies maximum length of the specified file path. 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The parameter |pure_file_name| input pure file name part of the specified 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// file path. If the length of specified file path is great than 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |max_file_path_len|, the |pure_file_name| will output new pure file name 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// part for making sure the length of specified file path is less than 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// specified maximum length of file path. Return false if the function can 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// not get a safe pure file name, otherwise it returns true. 4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SavePackage::GetSafePureFileName( 4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath& dir_path, 4292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath::StringType& file_name_ext, 4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) uint32 max_file_path_len, 4312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath::StringType* pure_file_name) { 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!pure_file_name->empty()); 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int available_length = static_cast<int>(max_file_path_len - 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dir_path.value().length() - 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_name_ext.length()); 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Need an extra space for the separator. 437c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!dir_path.EndsWithSeparator()) 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) --available_length; 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Plenty of room. 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (static_cast<int>(pure_file_name->length()) <= available_length) 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Limited room. Truncate |pure_file_name| to fit. 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (available_length > 0) { 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *pure_file_name = pure_file_name->substr(0, available_length); 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Not enough room to even use a shortened |pure_file_name|. 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pure_file_name->clear(); 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Generate name for saving resource. 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SavePackage::GenerateFileName(const std::string& disposition, 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GURL& url, 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool need_html_ext, 4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath::StringType* generated_name) { 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(jungshik): Figure out the referrer charset when having one 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // makes sense and pass it to GenerateFileName. 462c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::FilePath file_path = net::GenerateFileName(url, 463c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) disposition, 464c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::string(), 465c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::string(), 466c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::string(), 4672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) kDefaultSaveName); 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!file_path.empty()); 4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath::StringType pure_file_name = 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_path.RemoveExtension().BaseName().value(); 4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath::StringType file_name_ext = file_path.Extension(); 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If it is HTML resource, use ".htm{l,}" as its extension. 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (need_html_ext) { 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_name_ext = FILE_PATH_LITERAL("."); 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_name_ext.append(kDefaultHtmlExtension); 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Need to make sure the suggested file name is not too long. 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32 max_path = GetMaxPathLengthForDirectory(saved_main_directory_path_); 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Get safe pure file name. 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!GetSafePureFileName(saved_main_directory_path_, file_name_ext, 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) max_path, &pure_file_name)) 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath::StringType file_name = pure_file_name + file_name_ext; 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Check whether we already have same name in a case insensitive manner. 4912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FileNameSet::const_iterator iter = file_name_set_.find(file_name); 4922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (iter == file_name_set_.end()) { 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_name_set_.insert(file_name); 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Found same name, increase the ordinal number for the file name. 4962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pure_file_name = 4972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath(*iter).RemoveExtension().BaseName().value(); 4982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath::StringType base_file_name = 4992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) StripOrdinalNumber(pure_file_name); 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We need to make sure the length of base file name plus maximum ordinal 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // number path will be less than or equal to kMaxFilePathLength. 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!GetSafePureFileName(saved_main_directory_path_, file_name_ext, 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) max_path - kMaxFileOrdinalNumberPartLength, &base_file_name)) 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Prepare the new ordinal number. 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32 ordinal_number; 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FileNameCountMap::iterator it = file_name_count_map_.find(base_file_name); 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (it == file_name_count_map_.end()) { 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // First base-name-conflict resolving, use 1 as initial ordinal number. 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_name_count_map_[base_file_name] = 1; 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ordinal_number = 1; 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We have met same base-name conflict, use latest ordinal number. 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ordinal_number = it->second; 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ordinal_number > (kMaxFileOrdinalNumber - 1)) { 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Use a random file from temporary file. 5212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath temp_file; 522a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::CreateTemporaryFile(&temp_file); 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_name = temp_file.RemoveExtension().BaseName().value(); 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Get safe pure file name. 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!GetSafePureFileName(saved_main_directory_path_, 5262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath::StringType(), 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) max_path, &file_name)) 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = ordinal_number; i < kMaxFileOrdinalNumber; ++i) { 5312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath::StringType new_name = base_file_name + 5322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::StringPrintf(FILE_PATH_LITERAL("(%d)"), i) + file_name_ext; 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (file_name_set_.find(new_name) == file_name_set_.end()) { 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Resolved name conflict. 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_name = new_name; 5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_name_count_map_[base_file_name] = ++i; 5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_name_set_.insert(file_name); 5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!file_name.empty()); 5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) generated_name->assign(file_name); 5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We have received a message from SaveFileManager about a new saving job. We 5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// create a SaveItem and store it in our in_progress list. 5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SavePackage::StartSave(const SaveFileCreateInfo* info) { 5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(info && !info->url.is_empty()); 5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SaveUrlItemMap::iterator it = in_progress_items_.find(info->url.spec()); 5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (it == in_progress_items_.end()) { 5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If not found, we must have cancel action. 5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(canceled()); 5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SaveItem* save_item = it->second; 5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!saved_main_file_path_.empty()); 5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) save_item->SetSaveId(info->save_id); 5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) save_item->SetTotalBytes(info->total_bytes); 5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Determine the proper path for a saving job, by choosing either the default 5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // save directory, or prompting the user. 5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!save_item->has_final_name()); 5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (info->url != page_url_) { 5732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath::StringType generated_name; 5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // For HTML resource file, make sure it will have .htm as extension name, 5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // otherwise, when you open the saved page in Chrome again, download 5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // file manager will treat it as downloadable resource, and download it 5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // instead of opening it as HTML. 5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool need_html_ext = 5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) info->save_source == SaveFileCreateInfo::SAVE_FILE_FROM_DOM; 5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!GenerateFileName(info->content_disposition, 5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GURL(info->url), 5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) need_html_ext, 5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &generated_name)) { 5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We can not generate file name for this SaveItem, so we cancel the 5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // saving page job if the save source is from serialized DOM data. 5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Otherwise, it means this SaveItem is sub-resource type, we treat it 5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // as an error happened on saving. We can ignore this type error for 5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // sub-resource links which will be resolved as absolute links instead 5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // of local links in final saved contents. 5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (info->save_source == SaveFileCreateInfo::SAVE_FILE_FROM_DOM) 5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Cancel(true); 5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SaveFinished(save_item->save_id(), 0, false); 5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // When saving page as only-HTML, we only have a SaveItem whose url 5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // must be page_url_. 5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(save_type_ == SAVE_PAGE_TYPE_AS_COMPLETE_HTML); 6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!saved_main_directory_path_.empty()); 6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Now we get final name retrieved from GenerateFileName, we will use it 6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // rename the SaveItem. 6042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath final_name = 6052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) saved_main_directory_path_.Append(generated_name); 6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) save_item->Rename(final_name); 6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // It is the main HTML file, use the name chosen by the user. 6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) save_item->Rename(saved_main_file_path_); 6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the save source is from file system, inform SaveFileManager to copy 6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // corresponding file to the file path which this SaveItem specifies. 6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (info->save_source == SaveFileCreateInfo::SAVE_FILE_FROM_FILE) { 6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::PostTask( 6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::FILE, FROM_HERE, 6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&SaveFileManager::SaveLocalFile, 6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_manager_, 6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) save_item->url(), 6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) save_item->save_id(), 6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) contents_id())); 6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check whether we begin to require serialized HTML data. 6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (save_type_ == SAVE_PAGE_TYPE_AS_COMPLETE_HTML && 6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wait_state_ == HTML_DATA) { 6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Inform backend to serialize the all frames' DOM and send serialized 6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // HTML data back. 6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetSerializedHtmlDataForCurrentPageWithLocalLinks(); 6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SaveItem* SavePackage::LookupItemInProcessBySaveId(int32 save_id) { 6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (in_process_count()) { 6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (SaveUrlItemMap::iterator it = in_progress_items_.begin(); 6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != in_progress_items_.end(); ++it) { 6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SaveItem* save_item = it->second; 6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(save_item->state() == SaveItem::IN_PROGRESS); 6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (save_item->save_id() == save_id) 6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return save_item; 6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SavePackage::PutInProgressItemToSavedMap(SaveItem* save_item) { 6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SaveUrlItemMap::iterator it = in_progress_items_.find( 6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) save_item->url().spec()); 6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(it != in_progress_items_.end()); 6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(save_item == it->second); 6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) in_progress_items_.erase(it); 6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (save_item->success()) { 6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Add it to saved_success_items_. 6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(saved_success_items_.find(save_item->save_id()) == 6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) saved_success_items_.end()); 6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) saved_success_items_[save_item->save_id()] = save_item; 6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Add it to saved_failed_items_. 6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(saved_failed_items_.find(save_item->url().spec()) == 6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) saved_failed_items_.end()); 6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) saved_failed_items_[save_item->url().spec()] = save_item; 6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Called for updating saving state. 6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SavePackage::UpdateSaveProgress(int32 save_id, 6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int64 size, 6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool write_success) { 6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Because we might have canceled this saving job before, 6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // so we might not find corresponding SaveItem. 6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SaveItem* save_item = LookupItemInProcessBySaveId(save_id); 6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!save_item) 6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) save_item->Update(size); 6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we got disk error, cancel whole save page job. 6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!write_success) { 6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Cancel job with reason of disk error. 6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Cancel(false); 6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Stop all page saving jobs that are in progress and instruct the file thread 6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to delete all saved files. 6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SavePackage::Stop() { 6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we haven't moved out of the initial state, there's nothing to cancel and 6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // there won't be valid pointers for file_manager_ or download_. 6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (wait_state_ == INITIALIZE) 6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // When stopping, if it still has some items in in_progress, cancel them. 6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(canceled()); 6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (in_process_count()) { 6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SaveUrlItemMap::iterator it = in_progress_items_.begin(); 6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (; it != in_progress_items_.end(); ++it) { 7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SaveItem* save_item = it->second; 7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(save_item->state() == SaveItem::IN_PROGRESS); 7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) save_item->Cancel(); 7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Remove all in progress item to saved map. For failed items, they will 7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // be put into saved_failed_items_, for successful item, they will be put 7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // into saved_success_items_. 7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (in_process_count()) 7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PutInProgressItemToSavedMap(in_progress_items_.begin()->second); 7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This vector contains the save ids of the save files which SaveFileManager 7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // needs to remove from its save_file_map_. 7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SaveIDList save_ids; 7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (SavedItemMap::iterator it = saved_success_items_.begin(); 7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != saved_success_items_.end(); ++it) 7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) save_ids.push_back(it->first); 7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (SaveUrlItemMap::iterator it = saved_failed_items_.begin(); 7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != saved_failed_items_.end(); ++it) 7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) save_ids.push_back(it->second->save_id()); 7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::PostTask( 7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::FILE, FROM_HERE, 7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&SaveFileManager::RemoveSavedFileFromFileMap, 7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_manager_, 7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) save_ids)); 7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) finished_ = true; 7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wait_state_ = FAILED; 7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Inform the DownloadItem we have canceled whole save page job. 7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (download_) { 7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) download_->Cancel(false); 7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FinalizeDownloadEntry(); 7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SavePackage::CheckFinish() { 7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (in_process_count() || finished_) 7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath dir = (save_type_ == SAVE_PAGE_TYPE_AS_COMPLETE_HTML && 7422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) saved_success_items_.size() > 1) ? 7432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) saved_main_directory_path_ : base::FilePath(); 7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This vector contains the final names of all the successfully saved files 7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // along with their save ids. It will be passed to SaveFileManager to do the 7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // renaming job. 7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FinalNameList final_names; 7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (SavedItemMap::iterator it = saved_success_items_.begin(); 7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != saved_success_items_.end(); ++it) 7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) final_names.push_back(std::make_pair(it->first, 7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it->second->full_path())); 7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::PostTask( 7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::FILE, FROM_HERE, 7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&SaveFileManager::RenameAllFiles, 7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_manager_, 7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) final_names, 7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dir, 7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) web_contents()->GetRenderProcessHost()->GetID(), 7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) web_contents()->GetRenderViewHost()->GetRoutingID(), 7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) id())); 7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Successfully finished all items of this SavePackage. 7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SavePackage::Finish() { 7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // User may cancel the job when we're moving files to the final directory. 7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (canceled()) 7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wait_state_ = SUCCESSFUL; 7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) finished_ = true; 7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Record finish. 7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RecordSavePackageEvent(SAVE_PACKAGE_FINISHED); 7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Record any errors that occurred. 7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (wrote_to_completed_file_) { 7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RecordSavePackageEvent(SAVE_PACKAGE_WRITE_TO_COMPLETED); 7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (wrote_to_failed_file_) { 7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RecordSavePackageEvent(SAVE_PACKAGE_WRITE_TO_FAILED); 7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This vector contains the save ids of the save files which SaveFileManager 7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // needs to remove from its save_file_map_. 7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SaveIDList save_ids; 7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (SaveUrlItemMap::iterator it = saved_failed_items_.begin(); 7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != saved_failed_items_.end(); ++it) 7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) save_ids.push_back(it->second->save_id()); 7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::PostTask( 7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::FILE, FROM_HERE, 7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&SaveFileManager::RemoveSavedFileFromFileMap, 7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_manager_, 7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) save_ids)); 7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (download_) { 8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Hack to avoid touching download_ after user cancel. 8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(rdsmith/benjhayden): Integrate canceling on DownloadItem 8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // with SavePackage flow. 8037d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (download_->GetState() == DownloadItem::IN_PROGRESS) { 8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (save_type_ != SAVE_PAGE_TYPE_AS_MHTML) { 80590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) download_->DestinationUpdate( 806c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) all_save_items_count_, CurrentSpeed(), std::string()); 8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) download_->OnAllDataSaved(DownloadItem::kEmptyFileHash); 8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) download_->MarkAsComplete(); 8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FinalizeDownloadEntry(); 8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Called for updating end state. 8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SavePackage::SaveFinished(int32 save_id, int64 size, bool is_success) { 8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Because we might have canceled this saving job before, 8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // so we might not find corresponding SaveItem. Just ignore it. 8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SaveItem* save_item = LookupItemInProcessBySaveId(save_id); 8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!save_item) 8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Let SaveItem set end state. 8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) save_item->Finish(size, is_success); 8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Remove the associated save id and SavePackage. 8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_manager_->RemoveSaveFile(save_id, save_item->url(), this); 8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PutInProgressItemToSavedMap(save_item); 8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Inform the DownloadItem to update UI. 8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We use the received bytes as number of saved files. 8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Hack to avoid touching download_ after user cancel. 8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(rdsmith/benjhayden): Integrate canceling on DownloadItem 8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // with SavePackage flow. 8357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (download_ && (download_->GetState() == DownloadItem::IN_PROGRESS)) { 83690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) download_->DestinationUpdate( 83790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) completed_count(), CurrentSpeed(), std::string()); 83890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (save_item->save_source() == SaveFileCreateInfo::SAVE_FILE_FROM_DOM && 8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) save_item->url() == page_url_ && !save_item->received_bytes()) { 8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If size of main HTML page is 0, treat it as disk error. 8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Cancel(false); 8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (canceled()) { 8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(finished_); 8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Continue processing the save page job. 8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DoSavingProcess(); 8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check whether we can successfully finish whole job. 8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CheckFinish(); 8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Sometimes, the net io will only call SaveFileManager::SaveFinished with 8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// save id -1 when it encounters error. Since in this case, save id will be 8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// -1, so we can only use URL to find which SaveItem is associated with 8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// this error. 8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Saving an item failed. If it's a sub-resource, ignore it. If the error comes 8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// from serializing HTML data, then cancel saving page. 8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SavePackage::SaveFailed(const GURL& save_url) { 8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SaveUrlItemMap::iterator it = in_progress_items_.find(save_url.spec()); 8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (it == in_progress_items_.end()) { 8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); // Should not exist! 8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SaveItem* save_item = it->second; 8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) save_item->Finish(0, false); 8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PutInProgressItemToSavedMap(save_item); 8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Inform the DownloadItem to update UI. 8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We use the received bytes as number of saved files. 8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Hack to avoid touching download_ after user cancel. 8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(rdsmith/benjhayden): Integrate canceling on DownloadItem 8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // with SavePackage flow. 8827d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (download_ && (download_->GetState() == DownloadItem::IN_PROGRESS)) { 88390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) download_->DestinationUpdate( 88490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) completed_count(), CurrentSpeed(), std::string()); 88590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((save_type_ == SAVE_PAGE_TYPE_AS_ONLY_HTML) || 8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (save_type_ == SAVE_PAGE_TYPE_AS_MHTML) || 8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (save_item->save_source() == SaveFileCreateInfo::SAVE_FILE_FROM_DOM)) { 8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We got error when saving page. Treat it as disk error. 8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Cancel(true); 8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (canceled()) { 8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(finished_); 8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Continue processing the save page job. 9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DoSavingProcess(); 9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CheckFinish(); 9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SavePackage::SaveCanceled(SaveItem* save_item) { 9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Call the RemoveSaveFile in UI thread. 9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_manager_->RemoveSaveFile(save_item->save_id(), 9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) save_item->url(), 9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this); 9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (save_item->save_id() != -1) 9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::PostTask( 9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::FILE, FROM_HERE, 9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&SaveFileManager::CancelSave, 9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_manager_, 9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) save_item->save_id())); 9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Initiate a saving job of a specific URL. We send the request to 9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// SaveFileManager, which will dispatch it to different approach according to 9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the save source. Parameter process_all_remaining_items indicates whether 9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// we need to save all remaining items. 9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SavePackage::SaveNextFile(bool process_all_remaining_items) { 9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(web_contents()); 9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(waiting_item_queue_.size()); 9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) do { 9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Pop SaveItem from waiting list. 9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SaveItem* save_item = waiting_item_queue_.front(); 9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) waiting_item_queue_.pop(); 9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Add the item to in_progress_items_. 9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SaveUrlItemMap::iterator it = in_progress_items_.find( 9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) save_item->url().spec()); 9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(it == in_progress_items_.end()); 9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) in_progress_items_[save_item->url().spec()] = save_item; 9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) save_item->Start(); 9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_manager_->SaveURL(save_item->url(), 9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) save_item->referrer(), 9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) web_contents()->GetRenderProcessHost()->GetID(), 9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) routing_id(), 9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) save_item->save_source(), 9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) save_item->full_path(), 9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) web_contents()-> 9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetBrowserContext()->GetResourceContext(), 9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this); 9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } while (process_all_remaining_items && waiting_item_queue_.size()); 9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Calculate the percentage of whole save page job. 9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int SavePackage::PercentComplete() { 9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!all_save_items_count_) 9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else if (!in_process_count()) 9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 100; 9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return completed_count() / all_save_items_count_; 9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int64 SavePackage::CurrentSpeed() const { 9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::TimeDelta diff = base::TimeTicks::Now() - start_tick_; 9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int64 diff_ms = diff.InMilliseconds(); 9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return diff_ms == 0 ? 0 : completed_count() * 1000 / diff_ms; 9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Continue processing the save page job after one SaveItem has been 9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// finished. 9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SavePackage::DoSavingProcess() { 9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (save_type_ == SAVE_PAGE_TYPE_AS_COMPLETE_HTML) { 9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We guarantee that images and JavaScripts must be downloaded first. 9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // So when finishing all those sub-resources, we will know which 9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // sub-resource's link can be replaced with local file path, which 9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // sub-resource's link need to be replaced with absolute URL which 9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // point to its internet address because it got error when saving its data. 9743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Start a new SaveItem job if we still have job in waiting queue. 9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (waiting_item_queue_.size()) { 9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(wait_state_ == NET_FILES); 9783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) SaveItem* save_item = waiting_item_queue_.front(); 9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (save_item->save_source() != SaveFileCreateInfo::SAVE_FILE_FROM_DOM) { 9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SaveNextFile(false); 9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (!in_process_count()) { 9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If there is no in-process SaveItem, it means all sub-resources 9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // have been processed. Now we need to start serializing HTML DOM 9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // for the current page to get the generated HTML data. 9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wait_state_ = HTML_DATA; 9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // All non-HTML resources have been finished, start all remaining 9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // HTML files. 9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SaveNextFile(true); 9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (in_process_count()) { 9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Continue asking for HTML data. 9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(wait_state_ == HTML_DATA); 9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Save as HTML only or MHTML. 9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(wait_state_ == NET_FILES); 9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK((save_type_ == SAVE_PAGE_TYPE_AS_ONLY_HTML) || 9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (save_type_ == SAVE_PAGE_TYPE_AS_MHTML)); 9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (waiting_item_queue_.size()) { 10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(all_save_items_count_ == waiting_item_queue_.size()); 10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SaveNextFile(false); 10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SavePackage::OnMessageReceived(const IPC::Message& message) { 10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool handled = true; 10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC_BEGIN_MESSAGE_MAP(SavePackage, message) 10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC_MESSAGE_HANDLER(ViewHostMsg_SendCurrentPageAllSavableResourceLinks, 10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OnReceivedSavableResourceLinksForCurrentPage) 10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC_MESSAGE_HANDLER(ViewHostMsg_SendSerializedHtmlData, 10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OnReceivedSerializedHtmlData) 10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC_MESSAGE_UNHANDLED(handled = false) 10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC_END_MESSAGE_MAP() 10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return handled; 10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// After finishing all SaveItems which need to get data from net. 10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We collect all URLs which have local storage and send the 10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// map:(originalURL:currentLocalPath) to render process (backend). 10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Then render process will serialize DOM and send data to us. 10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SavePackage::GetSerializedHtmlDataForCurrentPageWithLocalLinks() { 10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (wait_state_ != HTML_DATA) 10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<GURL> saved_links; 10262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::vector<base::FilePath> saved_file_paths; 10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int successful_started_items_count = 0; 10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Collect all saved items which have local storage. 10305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // First collect the status of all the resource files and check whether they 10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // have created local files although they have not been completely saved. 10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If yes, the file can be saved. Otherwise, there is a disk error, so we 10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // need to cancel the page saving job. 10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (SaveUrlItemMap::iterator it = in_progress_items_.begin(); 10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != in_progress_items_.end(); ++it) { 10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(it->second->save_source() == 10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SaveFileCreateInfo::SAVE_FILE_FROM_DOM); 10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (it->second->has_final_name()) 10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) successful_started_items_count++; 10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) saved_links.push_back(it->second->url()); 10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) saved_file_paths.push_back(it->second->file_name()); 10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If not all file of HTML resource have been started, then wait. 10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (successful_started_items_count != in_process_count()) 10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Collect all saved success items. 10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (SavedItemMap::iterator it = saved_success_items_.begin(); 10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != saved_success_items_.end(); ++it) { 10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(it->second->has_final_name()); 10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) saved_links.push_back(it->second->url()); 10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) saved_file_paths.push_back(it->second->file_name()); 10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Get the relative directory name. 10572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath relative_dir_name = saved_main_directory_path_.BaseName(); 10585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Send(new ViewMsg_GetSerializedHtmlDataForCurrentPageWithLocalLinks( 10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) routing_id(), saved_links, saved_file_paths, relative_dir_name)); 10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Process the serialized HTML content data of a specified web page 10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// retrieved from render process. 10655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SavePackage::OnReceivedSerializedHtmlData(const GURL& frame_url, 10665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& data, 10675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int32 status) { 10685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WebPageSerializerClient::PageSerializationStatus flag = 10695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<WebPageSerializerClient::PageSerializationStatus>(status); 10705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check current state. 10715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (wait_state_ != HTML_DATA) 10725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 10735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int id = contents_id(); 10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the all frames are finished saving, we need to close the 10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // remaining SaveItems. 10775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (flag == WebPageSerializerClient::AllFramesAreFinished) { 10785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (SaveUrlItemMap::iterator it = in_progress_items_.begin(); 10795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != in_progress_items_.end(); ++it) { 10805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VLOG(20) << " " << __FUNCTION__ << "()" 10815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << " save_id = " << it->second->save_id() 10825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << " url = \"" << it->second->url().spec() << "\""; 10835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::PostTask( 10845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::FILE, FROM_HERE, 10855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&SaveFileManager::SaveFinished, 10865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_manager_, 10875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it->second->save_id(), 10885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it->second->url(), 10895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) id, 10905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) true)); 10915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SaveUrlItemMap::iterator it = in_progress_items_.find(frame_url.spec()); 10965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (it == in_progress_items_.end()) { 10975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (SavedItemMap::iterator saved_it = saved_success_items_.begin(); 10985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) saved_it != saved_success_items_.end(); ++saved_it) { 10995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (saved_it->second->url() == frame_url) { 11005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wrote_to_completed_file_ = true; 11015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 11025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it = saved_failed_items_.find(frame_url.spec()); 11065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (it != saved_failed_items_.end()) 11075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wrote_to_failed_file_ = true; 11085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 11105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SaveItem* save_item = it->second; 11135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(save_item->save_source() == SaveFileCreateInfo::SAVE_FILE_FROM_DOM); 11145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!data.empty()) { 11165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Prepare buffer for saving HTML data. 11175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<net::IOBuffer> new_data(new net::IOBuffer(data.size())); 11185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(new_data->data(), data.data(), data.size()); 11195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Call write file functionality in file thread. 11215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::PostTask( 11225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::FILE, FROM_HERE, 11235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&SaveFileManager::UpdateSaveProgress, 11245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_manager_, 11255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) save_item->save_id(), 11265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_data, 11275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<int>(data.size()))); 11285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Current frame is completed saving, call finish in file thread. 11315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (flag == WebPageSerializerClient::CurrentFrameIsFinished) { 11325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VLOG(20) << " " << __FUNCTION__ << "()" 11335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << " save_id = " << save_item->save_id() 11345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << " url = \"" << save_item->url().spec() << "\""; 11355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::PostTask( 11365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::FILE, FROM_HERE, 11375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&SaveFileManager::SaveFinished, 11385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_manager_, 11395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) save_item->save_id(), 11405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) save_item->url(), 11415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) id, 11425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) true)); 11435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 11455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Ask for all savable resource links from backend, include main frame and 11475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// sub-frame. 11485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SavePackage::GetAllSavableResourceLinksForCurrentPage() { 11495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (wait_state_ != START_PROCESS) 11505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 11515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wait_state_ = RESOURCES_LIST; 11535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Send(new ViewMsg_GetAllSavableResourceLinksForCurrentPage(routing_id(), 11545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) page_url_)); 11555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 11565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Give backend the lists which contain all resource links that have local 11585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// storage, after which, render process will serialize DOM for generating 11595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// HTML data. 11605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SavePackage::OnReceivedSavableResourceLinksForCurrentPage( 11615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::vector<GURL>& resources_list, 11625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::vector<Referrer>& referrers_list, 11635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::vector<GURL>& frames_list) { 11645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (wait_state_ != RESOURCES_LIST) 11655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 11665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (resources_list.size() != referrers_list.size()) 11682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 11692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 11705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) all_save_items_count_ = static_cast<int>(resources_list.size()) + 11715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<int>(frames_list.size()); 11725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We use total bytes as the total number of files we want to save. 11745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Hack to avoid touching download_ after user cancel. 11755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(rdsmith/benjhayden): Integrate canceling on DownloadItem 11765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // with SavePackage flow. 11777d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (download_ && (download_->GetState() == DownloadItem::IN_PROGRESS)) 11785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) download_->SetTotalBytes(all_save_items_count_); 11795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (all_save_items_count_) { 11815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Put all sub-resources to wait list. 11825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < static_cast<int>(resources_list.size()); ++i) { 11835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GURL& u = resources_list[i]; 11845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(u.is_valid()); 11855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SaveFileCreateInfo::SaveFileSource save_source = u.SchemeIsFile() ? 11865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SaveFileCreateInfo::SAVE_FILE_FROM_FILE : 11875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SaveFileCreateInfo::SAVE_FILE_FROM_NET; 11885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SaveItem* save_item = new SaveItem(u, referrers_list[i], 11895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this, save_source); 11905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) waiting_item_queue_.push(save_item); 11915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Put all HTML resources to wait list. 11935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < static_cast<int>(frames_list.size()); ++i) { 11945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GURL& u = frames_list[i]; 11955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(u.is_valid()); 11965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SaveItem* save_item = new SaveItem( 11975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) u, Referrer(), this, SaveFileCreateInfo::SAVE_FILE_FROM_DOM); 11985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) waiting_item_queue_.push(save_item); 11995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wait_state_ = NET_FILES; 12015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DoSavingProcess(); 12025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 12035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // No resource files need to be saved, treat it as user cancel. 12045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Cancel(true); 12055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 12075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath SavePackage::GetSuggestedNameForSaveAs( 12095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool can_save_as_complete, 12105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& contents_mime_type, 12115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& accept_langs) { 1212424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) base::FilePath name_with_proper_ext = base::FilePath::FromUTF16Unsafe(title_); 12135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the page's title matches its URL, use the URL. Try to use the last path 12155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // component or if there is none, the domain as the file name. 12165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Normally we want to base the filename on the page title, or if it doesn't 12175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // exist, on the URL. It's not easy to tell if the page has no title, because 12185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // if the page has no title, WebContents::GetTitle() will return the page's 12195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // URL (adjusted for display purposes). Therefore, we convert the "title" 12205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // back to a URL, and if it matches the original page URL, we know the page 12215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // had no title (or had a title equal to its URL, which is fine to treat 12225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // similarly). 12235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (title_ == net::FormatUrl(page_url_, accept_langs)) { 12245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string url_path; 12255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!page_url_.SchemeIs(kDataScheme)) { 12265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<std::string> url_parts; 12275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::SplitString(page_url_.path(), '/', &url_parts); 12285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!url_parts.empty()) { 12295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = static_cast<int>(url_parts.size()) - 1; i >= 0; --i) { 12305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url_path = url_parts[i]; 12315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!url_path.empty()) 12325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 12335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (url_path.empty()) 12365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url_path = page_url_.host(); 12375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 12385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url_path = "dataurl"; 12395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1240424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) name_with_proper_ext = base::FilePath::FromUTF8Unsafe(url_path); 12415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Ask user for getting final saving name. 12445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) name_with_proper_ext = EnsureMimeExtension(name_with_proper_ext, 12455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) contents_mime_type); 12465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Adjust extension for complete types. 12475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (can_save_as_complete) 12485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) name_with_proper_ext = EnsureHtmlExtension(name_with_proper_ext); 12495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath::StringType file_name = name_with_proper_ext.value(); 12515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_util::ReplaceIllegalCharactersInPath(&file_name, ' '); 12522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return base::FilePath(file_name); 12535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 12545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath SavePackage::EnsureHtmlExtension(const base::FilePath& name) { 12565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the file name doesn't have an extension suitable for HTML files, 12575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // append one. 12582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath::StringType ext = name.Extension(); 12595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!ext.empty()) 12605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ext.erase(ext.begin()); // Erase preceding '.'. 12615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string mime_type; 12625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!net::GetMimeTypeFromExtension(ext, &mime_type) || 12635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !CanSaveAsComplete(mime_type)) { 12642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return base::FilePath(name.value() + FILE_PATH_LITERAL(".") + 12652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) kDefaultHtmlExtension); 12665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return name; 12685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 12695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath SavePackage::EnsureMimeExtension(const base::FilePath& name, 12715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& contents_mime_type) { 12725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Start extension at 1 to skip over period if non-empty. 12732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath::StringType ext = name.Extension().length() ? 12745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) name.Extension().substr(1) : name.Extension(); 12752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath::StringType suggested_extension = 12765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ExtensionForMimeType(contents_mime_type); 12775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string mime_type; 12785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!suggested_extension.empty() && 12795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !net::GetMimeTypeFromExtension(ext, &mime_type)) { 12805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Extension is absent or needs to be updated. 12812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return base::FilePath(name.value() + FILE_PATH_LITERAL(".") + 12825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) suggested_extension); 12835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return name; 12855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 12865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const base::FilePath::CharType* SavePackage::ExtensionForMimeType( 12885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& contents_mime_type) { 12895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const struct { 12902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath::CharType *mime_type; 12912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath::CharType *suggested_extension; 12925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } extensions[] = { 12935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { FILE_PATH_LITERAL("text/html"), kDefaultHtmlExtension }, 12945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { FILE_PATH_LITERAL("text/xml"), FILE_PATH_LITERAL("xml") }, 12955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { FILE_PATH_LITERAL("application/xhtml+xml"), FILE_PATH_LITERAL("xhtml") }, 12965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { FILE_PATH_LITERAL("text/plain"), FILE_PATH_LITERAL("txt") }, 12975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { FILE_PATH_LITERAL("text/css"), FILE_PATH_LITERAL("css") }, 12985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 12995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_POSIX) 13002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath::StringType mime_type(contents_mime_type); 13015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_WIN) 13025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::FilePath::StringType mime_type(base::UTF8ToWide(contents_mime_type)); 13035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // OS_WIN 13045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (uint32 i = 0; i < ARRAYSIZE_UNSAFE(extensions); ++i) { 13055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (mime_type == extensions[i].mime_type) 13065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return extensions[i].suggested_extension; 13075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return FILE_PATH_LITERAL(""); 13095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 13105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WebContents* SavePackage::web_contents() const { 13125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return WebContentsObserver::web_contents(); 13135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 13145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SavePackage::GetSaveInfo() { 13165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Can't use web_contents_ in the file thread, so get the data that we need 13175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // before calling to it. 13182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath website_save_dir, download_save_dir; 1319a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) bool skip_dir_check = false; 13205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(download_manager_); 13215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (download_manager_->GetDelegate()) { 13225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) download_manager_->GetDelegate()->GetSaveDir( 13235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) web_contents()->GetBrowserContext(), &website_save_dir, 13245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &download_save_dir, &skip_dir_check); 13255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string mime_type = web_contents()->GetContentsMimeType(); 13275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string accept_languages = 13285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetContentClient()->browser()->GetAcceptLangs( 13295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) web_contents()->GetBrowserContext()); 13305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::PostTask( 13325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::FILE, FROM_HERE, 13335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&SavePackage::CreateDirectoryOnFileThread, this, 13345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) website_save_dir, download_save_dir, skip_dir_check, 13355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mime_type, accept_languages)); 13365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 13375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SavePackage::CreateDirectoryOnFileThread( 13392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath& website_save_dir, 13402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath& download_save_dir, 13415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool skip_dir_check, 13425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& mime_type, 13435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& accept_langs) { 13442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath save_dir; 13455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the default html/websites save folder doesn't exist... 13465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We skip the directory check for gdata directories on ChromeOS. 13477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if (!skip_dir_check && !base::DirectoryExists(website_save_dir)) { 13485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the default download dir doesn't exist, create it. 13497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if (!base::DirectoryExists(download_save_dir)) { 1350a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) bool res = base::CreateDirectory(download_save_dir); 13515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(res); 13525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) save_dir = download_save_dir; 13545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 13555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If it does exist, use the default save dir param. 13565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) save_dir = website_save_dir; 13575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool can_save_as_complete = CanSaveAsComplete(mime_type); 13602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath suggested_filename = GetSuggestedNameForSaveAs( 13615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) can_save_as_complete, mime_type, accept_langs); 13622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath::StringType pure_file_name = 13635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) suggested_filename.RemoveExtension().BaseName().value(); 13642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath::StringType file_name_ext = suggested_filename.Extension(); 13655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Need to make sure the suggested file name is not too long. 13675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32 max_path = GetMaxPathLengthForDirectory(save_dir); 13685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (GetSafePureFileName(save_dir, file_name_ext, max_path, &pure_file_name)) { 13705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) save_dir = save_dir.Append(pure_file_name + file_name_ext); 13715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 13725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Cannot create a shorter filename. This will cause the save as operation 13735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to fail unless the user pick a shorter name. Continuing even though it 13745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // will fail because returning means no save as popup for the user, which 13755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // is even more confusing. This case should be rare though. 13765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) save_dir = save_dir.Append(suggested_filename); 13775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::PostTask( 13805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::UI, FROM_HERE, 13815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&SavePackage::ContinueGetSaveInfo, this, save_dir, 13825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) can_save_as_complete)); 13835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 13845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SavePackage::ContinueGetSaveInfo(const base::FilePath& suggested_path, 13865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool can_save_as_complete) { 13875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The WebContents which owns this SavePackage may have disappeared during 13895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the UI->FILE->UI thread hop of 13905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // GetSaveInfo->CreateDirectoryOnFileThread->ContinueGetSaveInfo. 13915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!web_contents() || !download_manager_->GetDelegate()) 13925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 13935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath::StringType default_extension; 13955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (can_save_as_complete) 13965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default_extension = kDefaultHtmlExtension; 13975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) download_manager_->GetDelegate()->ChooseSavePath( 13995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) web_contents(), 14005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) suggested_path, 14015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default_extension, 14025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) can_save_as_complete, 14035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&SavePackage::OnPathPicked, AsWeakPtr())); 14045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 14055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SavePackage::OnPathPicked( 14072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath& final_name, 14085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SavePageType type, 14095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const SavePackageDownloadCreatedCallback& download_created_callback) { 14102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK((type == SAVE_PAGE_TYPE_AS_ONLY_HTML) || 14112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) (type == SAVE_PAGE_TYPE_AS_MHTML) || 14122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) (type == SAVE_PAGE_TYPE_AS_COMPLETE_HTML)) << type; 14135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Ensure the filename is safe. 14145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) saved_main_file_path_ = final_name; 14155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(asanka): This call may block on IO and shouldn't be made 14165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // from the UI thread. See http://crbug.com/61827. 14175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::GenerateSafeFileName(web_contents()->GetContentsMimeType(), false, 14185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &saved_main_file_path_); 14195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) saved_main_directory_path_ = saved_main_file_path_.DirName(); 14215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) save_type_ = type; 14225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (save_type_ == SAVE_PAGE_TYPE_AS_COMPLETE_HTML) { 14235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Make new directory for saving complete file. 14245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) saved_main_directory_path_ = saved_main_directory_path_.Append( 14255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) saved_main_file_path_.RemoveExtension().BaseName().value() + 14265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FILE_PATH_LITERAL("_files")); 14275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 14285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Init(download_created_callback); 14305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 14315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SavePackage::StopObservation() { 14335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(download_); 14345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(download_manager_); 14355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) download_->RemoveObserver(this); 14375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) download_ = NULL; 14385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) download_manager_ = NULL; 14395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 14405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SavePackage::OnDownloadDestroyed(DownloadItem* download) { 14425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StopObservation(); 14435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 14445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SavePackage::FinalizeDownloadEntry() { 14465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(download_); 14475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(download_manager_); 14485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) download_manager_->OnSavePackageSuccessfullyFinished(download_); 14505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StopObservation(); 14515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 14525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace content 1454