OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/download/save_package.h" | 5 #include "content/browser/download/save_package.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/file_path.h" | 9 #include "base/file_path.h" |
10 #include "base/file_util.h" | 10 #include "base/file_util.h" |
11 #include "base/i18n/file_util_icu.h" | 11 #include "base/i18n/file_util_icu.h" |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/message_loop.h" | 13 #include "base/message_loop.h" |
14 #include "base/stl_util.h" | 14 #include "base/stl_util.h" |
15 #include "base/string_piece.h" | 15 #include "base/string_piece.h" |
16 #include "base/string_split.h" | 16 #include "base/string_split.h" |
17 #include "base/sys_string_conversions.h" | 17 #include "base/sys_string_conversions.h" |
18 #include "base/task.h" | 18 #include "base/task.h" |
19 #include "base/threading/thread.h" | 19 #include "base/threading/thread.h" |
20 #include "base/utf_string_conversions.h" | 20 #include "base/utf_string_conversions.h" |
| 21 #include "chrome/browser/download/download_history.h" |
21 #include "chrome/browser/download/download_item.h" | 22 #include "chrome/browser/download/download_item.h" |
22 #include "chrome/browser/download/download_item_model.h" | 23 #include "chrome/browser/download/download_item_model.h" |
23 #include "chrome/browser/download/download_manager.h" | 24 #include "chrome/browser/download/download_manager.h" |
24 #include "chrome/browser/download/download_util.h" | 25 #include "chrome/browser/download/download_util.h" |
25 #include "chrome/browser/prefs/pref_member.h" | 26 #include "chrome/browser/prefs/pref_member.h" |
26 #include "chrome/browser/prefs/pref_service.h" | 27 #include "chrome/browser/prefs/pref_service.h" |
27 #include "chrome/browser/profiles/profile.h" | 28 #include "chrome/browser/profiles/profile.h" |
28 #include "chrome/common/pref_names.h" | 29 #include "chrome/common/pref_names.h" |
29 #include "content/browser/browser_thread.h" | 30 #include "content/browser/browser_thread.h" |
30 #include "content/browser/content_browser_client.h" | 31 #include "content/browser/content_browser_client.h" |
31 #include "content/browser/download/save_file.h" | 32 #include "content/browser/download/save_file.h" |
32 #include "content/browser/download/save_file_manager.h" | 33 #include "content/browser/download/save_file_manager.h" |
33 #include "content/browser/download/save_item.h" | 34 #include "content/browser/download/save_item.h" |
34 #include "content/browser/renderer_host/render_process_host.h" | 35 #include "content/browser/renderer_host/render_process_host.h" |
35 #include "content/browser/renderer_host/render_view_host.h" | 36 #include "content/browser/renderer_host/render_view_host.h" |
36 #include "content/browser/renderer_host/render_view_host_delegate.h" | 37 #include "content/browser/renderer_host/render_view_host_delegate.h" |
37 #include "content/browser/renderer_host/resource_dispatcher_host.h" | 38 #include "content/browser/renderer_host/resource_dispatcher_host.h" |
38 #include "content/browser/tab_contents/tab_contents.h" | 39 #include "content/browser/tab_contents/tab_contents.h" |
39 #include "content/common/content_notification_types.h" | |
40 #include "content/common/notification_service.h" | |
41 #include "content/common/url_constants.h" | 40 #include "content/common/url_constants.h" |
42 #include "content/common/view_messages.h" | 41 #include "content/common/view_messages.h" |
43 #include "net/base/io_buffer.h" | 42 #include "net/base/io_buffer.h" |
44 #include "net/base/mime_util.h" | 43 #include "net/base/mime_util.h" |
45 #include "net/base/net_util.h" | 44 #include "net/base/net_util.h" |
46 #include "net/url_request/url_request_context.h" | 45 #include "net/url_request/url_request_context.h" |
47 #include "third_party/WebKit/Source/WebKit/chromium/public/WebPageSerializerClie
nt.h" | 46 #include "third_party/WebKit/Source/WebKit/chromium/public/WebPageSerializerClie
nt.h" |
48 | 47 |
49 using base::Time; | 48 using base::Time; |
50 using WebKit::WebPageSerializerClient; | 49 using WebKit::WebPageSerializerClient; |
51 | 50 |
52 namespace { | 51 namespace { |
53 | 52 |
| 53 /* |
| 54 Race analysis: |
| 55 + The actions that can race against each other are: |
| 56 * History callback |
| 57 * Completion (save page as finishes) |
| 58 * Cancel (SavePackage::Stop()) |
| 59 * Shutdown |
| 60 * Remove |
| 61 + Cancel and completion can be considered equivalent for race |
| 62 processing, as they have the same effect on the download manager, and |
| 63 SavePackage won't produce any more events after either of them. I'll |
| 64 refer to the OR of these two events as "Finishing". |
| 65 + Anything that occurs after both History callback and Finishing is |
| 66 uninteresting, as there won't be anything in the queues anymore. |
| 67 + Only the History Callback or Remove can occur after Shutdown (the |
| 68 SavePackage system won't produce any more events after these two). |
| 69 + Remove does not cancel (probably not a mistake you'd make, but it |
| 70 does on downloads, so I'm noting it for myself). |
| 71 + Shutdown can only occur after Finishing(Cancel) (destroying a |
| 72 profile happens strictly after destroying all TabContents associated |
| 73 with the profile). |
| 74 + Remove can only occur after the History Callback. |
| 75 |
| 76 This leads to the following possible orders of events: |
| 77 -- Finishing, History Callback |
| 78 Variations on the basic one. Ok. |
| 79 -- Finishing(Cancel), Shutdown, History Callback |
| 80 The cancel leaves the DI in the queue, shutdown removes and deletes |
| 81 it, and the history callback doesn't find it, leaving it in the DB |
| 82 as IN_PROGRESS, which will be turned into Cancelled on next load. |
| 83 Ok. |
| 84 -- History Callback, Finishing |
| 85 The basic order. Ok. |
| 86 -- History Callback, Remove, Finishing |
| 87 This results in a lack of update of the database to indicate |
| 88 that the download has completed (if the finishing action is |
| 89 completed), but that's not solvable until we cancel on Remove |
| 90 (which would update the DB). |
| 91 */ |
| 92 |
54 // A counter for uniquely identifying each save package. | 93 // A counter for uniquely identifying each save package. |
55 int g_save_package_id = 0; | 94 int g_save_package_id = 0; |
56 | 95 |
57 // Default name which will be used when we can not get proper name from | 96 // Default name which will be used when we can not get proper name from |
58 // resource URL. | 97 // resource URL. |
59 const char kDefaultSaveName[] = "saved_resource"; | 98 const char kDefaultSaveName[] = "saved_resource"; |
60 | 99 |
61 // Maximum number of file ordinal number. I think it's big enough for resolving | 100 // Maximum number of file ordinal number. I think it's big enough for resolving |
62 // name-conflict files which has same base file name. | 101 // name-conflict files which has same base file name. |
63 const int32 kMaxFileOrdinalNumber = 9999; | 102 const int32 kMaxFileOrdinalNumber = 9999; |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
113 #else | 152 #else |
114 FILE_PATH_LITERAL("html"); | 153 FILE_PATH_LITERAL("html"); |
115 #endif | 154 #endif |
116 | 155 |
117 SavePackage::SavePackage(TabContents* tab_contents, | 156 SavePackage::SavePackage(TabContents* tab_contents, |
118 SavePackageType save_type, | 157 SavePackageType save_type, |
119 const FilePath& file_full_path, | 158 const FilePath& file_full_path, |
120 const FilePath& directory_full_path) | 159 const FilePath& directory_full_path) |
121 : TabContentsObserver(tab_contents), | 160 : TabContentsObserver(tab_contents), |
122 file_manager_(NULL), | 161 file_manager_(NULL), |
| 162 download_manager_(NULL), |
123 download_(NULL), | 163 download_(NULL), |
124 page_url_(GetUrlToBeSaved()), | 164 page_url_(GetUrlToBeSaved()), |
125 saved_main_file_path_(file_full_path), | 165 saved_main_file_path_(file_full_path), |
126 saved_main_directory_path_(directory_full_path), | 166 saved_main_directory_path_(directory_full_path), |
127 title_(tab_contents->GetTitle()), | 167 title_(tab_contents->GetTitle()), |
128 finished_(false), | 168 finished_(false), |
129 user_canceled_(false), | 169 user_canceled_(false), |
130 disk_error_occurred_(false), | 170 disk_error_occurred_(false), |
131 save_type_(save_type), | 171 save_type_(save_type), |
132 all_save_items_count_(0), | 172 all_save_items_count_(0), |
133 wait_state_(INITIALIZE), | 173 wait_state_(INITIALIZE), |
134 tab_id_(tab_contents->GetRenderProcessHost()->id()), | 174 tab_id_(tab_contents->GetRenderProcessHost()->id()), |
135 unique_id_(g_save_package_id++), | 175 unique_id_(g_save_package_id++), |
136 ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { | 176 ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { |
137 DCHECK(page_url_.is_valid()); | 177 DCHECK(page_url_.is_valid()); |
138 DCHECK(save_type_ == SAVE_AS_ONLY_HTML || | 178 DCHECK(save_type_ == SAVE_AS_ONLY_HTML || |
139 save_type_ == SAVE_AS_COMPLETE_HTML); | 179 save_type_ == SAVE_AS_COMPLETE_HTML); |
140 DCHECK(!saved_main_file_path_.empty() && | 180 DCHECK(!saved_main_file_path_.empty() && |
141 saved_main_file_path_.value().length() <= kMaxFilePathLength); | 181 saved_main_file_path_.value().length() <= kMaxFilePathLength); |
142 DCHECK(!saved_main_directory_path_.empty() && | 182 DCHECK(!saved_main_directory_path_.empty() && |
143 saved_main_directory_path_.value().length() < kMaxFilePathLength); | 183 saved_main_directory_path_.value().length() < kMaxFilePathLength); |
144 InternalInit(); | 184 InternalInit(); |
145 } | 185 } |
146 | 186 |
147 SavePackage::SavePackage(TabContents* tab_contents) | 187 SavePackage::SavePackage(TabContents* tab_contents) |
148 : TabContentsObserver(tab_contents), | 188 : TabContentsObserver(tab_contents), |
149 file_manager_(NULL), | 189 file_manager_(NULL), |
| 190 download_manager_(NULL), |
150 download_(NULL), | 191 download_(NULL), |
151 page_url_(GetUrlToBeSaved()), | 192 page_url_(GetUrlToBeSaved()), |
152 title_(tab_contents->GetTitle()), | 193 title_(tab_contents->GetTitle()), |
153 finished_(false), | 194 finished_(false), |
154 user_canceled_(false), | 195 user_canceled_(false), |
155 disk_error_occurred_(false), | 196 disk_error_occurred_(false), |
156 save_type_(SAVE_TYPE_UNKNOWN), | 197 save_type_(SAVE_TYPE_UNKNOWN), |
157 all_save_items_count_(0), | 198 all_save_items_count_(0), |
158 wait_state_(INITIALIZE), | 199 wait_state_(INITIALIZE), |
159 tab_id_(tab_contents->GetRenderProcessHost()->id()), | 200 tab_id_(tab_contents->GetRenderProcessHost()->id()), |
160 unique_id_(g_save_package_id++), | 201 unique_id_(g_save_package_id++), |
161 ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { | 202 ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { |
162 DCHECK(page_url_.is_valid()); | 203 DCHECK(page_url_.is_valid()); |
163 InternalInit(); | 204 InternalInit(); |
164 } | 205 } |
165 | 206 |
166 // This is for testing use. Set |finished_| as true because we don't want | 207 // This is for testing use. Set |finished_| as true because we don't want |
167 // method Cancel to be be called in destructor in test mode. | 208 // method Cancel to be be called in destructor in test mode. |
168 // We also don't call InternalInit(). | 209 // We also don't call InternalInit(). |
169 SavePackage::SavePackage(TabContents* tab_contents, | 210 SavePackage::SavePackage(TabContents* tab_contents, |
170 const FilePath& file_full_path, | 211 const FilePath& file_full_path, |
171 const FilePath& directory_full_path) | 212 const FilePath& directory_full_path) |
172 : TabContentsObserver(tab_contents), | 213 : TabContentsObserver(tab_contents), |
173 file_manager_(NULL), | 214 file_manager_(NULL), |
| 215 download_manager_(NULL), |
174 download_(NULL), | 216 download_(NULL), |
175 saved_main_file_path_(file_full_path), | 217 saved_main_file_path_(file_full_path), |
176 saved_main_directory_path_(directory_full_path), | 218 saved_main_directory_path_(directory_full_path), |
177 finished_(true), | 219 finished_(true), |
178 user_canceled_(false), | 220 user_canceled_(false), |
179 disk_error_occurred_(false), | 221 disk_error_occurred_(false), |
180 save_type_(SAVE_TYPE_UNKNOWN), | 222 save_type_(SAVE_TYPE_UNKNOWN), |
181 all_save_items_count_(0), | 223 all_save_items_count_(0), |
182 wait_state_(INITIALIZE), | 224 wait_state_(INITIALIZE), |
183 tab_id_(0), | 225 tab_id_(0), |
184 unique_id_(g_save_package_id++), | 226 unique_id_(g_save_package_id++), |
185 ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { | 227 ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { |
186 } | 228 } |
187 | 229 |
188 SavePackage::~SavePackage() { | 230 SavePackage::~SavePackage() { |
189 // Stop receiving saving job's updates | 231 // Stop receiving saving job's updates |
190 if (!finished_ && !canceled()) { | 232 if (!finished_ && !canceled()) { |
191 // Unexpected quit. | 233 // Unexpected quit. |
192 Cancel(true); | 234 Cancel(true); |
193 } | 235 } |
194 | 236 |
| 237 // We should no longer be observing the DownloadManager at this point. |
| 238 CHECK(!download_manager_); |
| 239 CHECK(!download_); |
| 240 |
195 DCHECK(all_save_items_count_ == (waiting_item_queue_.size() + | 241 DCHECK(all_save_items_count_ == (waiting_item_queue_.size() + |
196 completed_count() + | 242 completed_count() + |
197 in_process_count())); | 243 in_process_count())); |
198 // Free all SaveItems. | 244 // Free all SaveItems. |
199 while (!waiting_item_queue_.empty()) { | 245 while (!waiting_item_queue_.empty()) { |
200 // We still have some items which are waiting for start to save. | 246 // We still have some items which are waiting for start to save. |
201 SaveItem* save_item = waiting_item_queue_.front(); | 247 SaveItem* save_item = waiting_item_queue_.front(); |
202 waiting_item_queue_.pop(); | 248 waiting_item_queue_.pop(); |
203 delete save_item; | 249 delete save_item; |
204 } | 250 } |
205 | 251 |
206 STLDeleteValues(&saved_success_items_); | 252 STLDeleteValues(&saved_success_items_); |
207 STLDeleteValues(&in_progress_items_); | 253 STLDeleteValues(&in_progress_items_); |
208 STLDeleteValues(&saved_failed_items_); | 254 STLDeleteValues(&saved_failed_items_); |
209 | 255 |
210 // The DownloadItem is owned by DownloadManager. | |
211 download_ = NULL; | |
212 | |
213 file_manager_ = NULL; | 256 file_manager_ = NULL; |
214 } | 257 } |
215 | 258 |
216 GURL SavePackage::GetUrlToBeSaved() { | 259 GURL SavePackage::GetUrlToBeSaved() { |
217 // Instead of using tab_contents_.GetURL here, we use url() | 260 // Instead of using tab_contents_.GetURL here, we use url() |
218 // (which is the "real" url of the page) | 261 // (which is the "real" url of the page) |
219 // from the NavigationEntry because it reflects its' origin | 262 // from the NavigationEntry because it reflects its' origin |
220 // rather than the displayed one (returned by GetURL) which may be | 263 // rather than the displayed one (returned by GetURL) which may be |
221 // different (like having "view-source:" on the front). | 264 // different (like having "view-source:" on the front). |
222 NavigationEntry* active_entry = | 265 NavigationEntry* active_entry = |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
258 | 301 |
259 wait_state_ = START_PROCESS; | 302 wait_state_ = START_PROCESS; |
260 | 303 |
261 // Initialize the request context and resource dispatcher. | 304 // Initialize the request context and resource dispatcher. |
262 Profile* profile = tab_contents()->profile(); | 305 Profile* profile = tab_contents()->profile(); |
263 if (!profile) { | 306 if (!profile) { |
264 NOTREACHED(); | 307 NOTREACHED(); |
265 return false; | 308 return false; |
266 } | 309 } |
267 | 310 |
268 // Create the fake DownloadItem and display the view. | 311 // Get the download manager and add ourselves as an observer. |
269 DownloadManager* download_manager = | 312 download_manager_ = tab_contents()->profile()->GetDownloadManager(); |
270 tab_contents()->profile()->GetDownloadManager(); | 313 if (!download_manager_) { |
271 download_ = new DownloadItem(download_manager, | 314 NOTREACHED(); |
| 315 return false; |
| 316 } |
| 317 |
| 318 // Create the download item. |
| 319 download_ = new DownloadItem(download_manager_, |
272 saved_main_file_path_, | 320 saved_main_file_path_, |
273 page_url_, | 321 page_url_, |
274 profile->IsOffTheRecord()); | 322 profile->IsOffTheRecord()); |
| 323 download_->AddObserver(this); |
275 | 324 |
276 // Transfer the ownership to the download manager. We need the DownloadItem | 325 // Transfer ownership to the download manager. |
277 // to be alive as long as the Profile is alive. | 326 download_manager_->SavePageDownloadStarted(download_); |
278 download_manager->SavePageAsDownloadStarted(download_); | |
279 | |
280 tab_contents()->OnStartDownload(download_); | |
281 | 327 |
282 // Check save type and process the save page job. | 328 // Check save type and process the save page job. |
283 if (save_type_ == SAVE_AS_COMPLETE_HTML) { | 329 if (save_type_ == SAVE_AS_COMPLETE_HTML) { |
284 // Get directory | 330 // Get directory |
285 DCHECK(!saved_main_directory_path_.empty()); | 331 DCHECK(!saved_main_directory_path_.empty()); |
286 GetAllSavableResourceLinksForCurrentPage(); | 332 GetAllSavableResourceLinksForCurrentPage(); |
287 } else { | 333 } else { |
288 wait_state_ = NET_FILES; | 334 wait_state_ = NET_FILES; |
289 SaveFileCreateInfo::SaveFileSource save_source = page_url_.SchemeIsFile() ? | 335 SaveFileCreateInfo::SaveFileSource save_source = page_url_.SchemeIsFile() ? |
290 SaveFileCreateInfo::SAVE_FILE_FROM_FILE : | 336 SaveFileCreateInfo::SAVE_FILE_FROM_FILE : |
(...skipping 341 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
632 BrowserThread::PostTask( | 678 BrowserThread::PostTask( |
633 BrowserThread::FILE, FROM_HERE, | 679 BrowserThread::FILE, FROM_HERE, |
634 NewRunnableMethod(file_manager_, | 680 NewRunnableMethod(file_manager_, |
635 &SaveFileManager::RemoveSavedFileFromFileMap, | 681 &SaveFileManager::RemoveSavedFileFromFileMap, |
636 save_ids)); | 682 save_ids)); |
637 | 683 |
638 finished_ = true; | 684 finished_ = true; |
639 wait_state_ = FAILED; | 685 wait_state_ = FAILED; |
640 | 686 |
641 // Inform the DownloadItem we have canceled whole save page job. | 687 // Inform the DownloadItem we have canceled whole save page job. |
642 download_->Cancel(false); | 688 if (download_) { |
| 689 download_->Cancel(false); |
| 690 FinalizeDownloadEntry(); |
| 691 } |
643 } | 692 } |
644 | 693 |
645 void SavePackage::CheckFinish() { | 694 void SavePackage::CheckFinish() { |
646 if (in_process_count() || finished_) | 695 if (in_process_count() || finished_) |
647 return; | 696 return; |
648 | 697 |
649 FilePath dir = (save_type_ == SAVE_AS_COMPLETE_HTML && | 698 FilePath dir = (save_type_ == SAVE_AS_COMPLETE_HTML && |
650 saved_success_items_.size() > 1) ? | 699 saved_success_items_.size() > 1) ? |
651 saved_main_directory_path_ : FilePath(); | 700 saved_main_directory_path_ : FilePath(); |
652 | 701 |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
685 for (SaveUrlItemMap::iterator it = saved_failed_items_.begin(); | 734 for (SaveUrlItemMap::iterator it = saved_failed_items_.begin(); |
686 it != saved_failed_items_.end(); ++it) | 735 it != saved_failed_items_.end(); ++it) |
687 save_ids.push_back(it->second->save_id()); | 736 save_ids.push_back(it->second->save_id()); |
688 | 737 |
689 BrowserThread::PostTask( | 738 BrowserThread::PostTask( |
690 BrowserThread::FILE, FROM_HERE, | 739 BrowserThread::FILE, FROM_HERE, |
691 NewRunnableMethod(file_manager_, | 740 NewRunnableMethod(file_manager_, |
692 &SaveFileManager::RemoveSavedFileFromFileMap, | 741 &SaveFileManager::RemoveSavedFileFromFileMap, |
693 save_ids)); | 742 save_ids)); |
694 | 743 |
695 download_->OnAllDataSaved(all_save_items_count_); | 744 if (download_) { |
696 download_->MarkAsComplete(); | 745 download_->OnAllDataSaved(all_save_items_count_); |
697 | 746 download_->MarkAsComplete(); |
698 NotificationService::current()->Notify( | 747 FinalizeDownloadEntry(); |
699 content::NOTIFICATION_SAVE_PACKAGE_SUCCESSFULLY_FINISHED, | 748 } |
700 Source<SavePackage>(this), | |
701 Details<GURL>(&page_url_)); | |
702 } | 749 } |
703 | 750 |
704 // Called for updating end state. | 751 // Called for updating end state. |
705 void SavePackage::SaveFinished(int32 save_id, int64 size, bool is_success) { | 752 void SavePackage::SaveFinished(int32 save_id, int64 size, bool is_success) { |
706 // Because we might have canceled this saving job before, | 753 // Because we might have canceled this saving job before, |
707 // so we might not find corresponding SaveItem. Just ignore it. | 754 // so we might not find corresponding SaveItem. Just ignore it. |
708 SaveItem* save_item = LookupItemInProcessBySaveId(save_id); | 755 SaveItem* save_item = LookupItemInProcessBySaveId(save_id); |
709 if (!save_item) | 756 if (!save_item) |
710 return; | 757 return; |
711 | 758 |
712 // Let SaveItem set end state. | 759 // Let SaveItem set end state. |
713 save_item->Finish(size, is_success); | 760 save_item->Finish(size, is_success); |
714 // Remove the associated save id and SavePackage. | 761 // Remove the associated save id and SavePackage. |
715 file_manager_->RemoveSaveFile(save_id, save_item->url(), this); | 762 file_manager_->RemoveSaveFile(save_id, save_item->url(), this); |
716 | 763 |
717 PutInProgressItemToSavedMap(save_item); | 764 PutInProgressItemToSavedMap(save_item); |
718 | 765 |
719 // Inform the DownloadItem to update UI. | 766 // Inform the DownloadItem to update UI. |
720 // We use the received bytes as number of saved files. | 767 // We use the received bytes as number of saved files. |
721 download_->Update(completed_count()); | 768 if (download_) |
| 769 download_->Update(completed_count()); |
722 | 770 |
723 if (save_item->save_source() == SaveFileCreateInfo::SAVE_FILE_FROM_DOM && | 771 if (save_item->save_source() == SaveFileCreateInfo::SAVE_FILE_FROM_DOM && |
724 save_item->url() == page_url_ && !save_item->received_bytes()) { | 772 save_item->url() == page_url_ && !save_item->received_bytes()) { |
725 // If size of main HTML page is 0, treat it as disk error. | 773 // If size of main HTML page is 0, treat it as disk error. |
726 Cancel(false); | 774 Cancel(false); |
727 return; | 775 return; |
728 } | 776 } |
729 | 777 |
730 if (canceled()) { | 778 if (canceled()) { |
731 DCHECK(finished_); | 779 DCHECK(finished_); |
(...skipping 20 matching lines...) Expand all Loading... |
752 return; | 800 return; |
753 } | 801 } |
754 SaveItem* save_item = it->second; | 802 SaveItem* save_item = it->second; |
755 | 803 |
756 save_item->Finish(0, false); | 804 save_item->Finish(0, false); |
757 | 805 |
758 PutInProgressItemToSavedMap(save_item); | 806 PutInProgressItemToSavedMap(save_item); |
759 | 807 |
760 // Inform the DownloadItem to update UI. | 808 // Inform the DownloadItem to update UI. |
761 // We use the received bytes as number of saved files. | 809 // We use the received bytes as number of saved files. |
762 download_->Update(completed_count()); | 810 if (download_) |
| 811 download_->Update(completed_count()); |
763 | 812 |
764 if (save_type_ == SAVE_AS_ONLY_HTML || | 813 if (save_type_ == SAVE_AS_ONLY_HTML || |
765 save_item->save_source() == SaveFileCreateInfo::SAVE_FILE_FROM_DOM) { | 814 save_item->save_source() == SaveFileCreateInfo::SAVE_FILE_FROM_DOM) { |
766 // We got error when saving page. Treat it as disk error. | 815 // We got error when saving page. Treat it as disk error. |
767 Cancel(true); | 816 Cancel(true); |
768 } | 817 } |
769 | 818 |
770 if (canceled()) { | 819 if (canceled()) { |
771 DCHECK(finished_); | 820 DCHECK(finished_); |
772 return; | 821 return; |
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1016 const std::vector<GURL>& referrers_list, | 1065 const std::vector<GURL>& referrers_list, |
1017 const std::vector<GURL>& frames_list) { | 1066 const std::vector<GURL>& frames_list) { |
1018 if (wait_state_ != RESOURCES_LIST) | 1067 if (wait_state_ != RESOURCES_LIST) |
1019 return; | 1068 return; |
1020 | 1069 |
1021 DCHECK(resources_list.size() == referrers_list.size()); | 1070 DCHECK(resources_list.size() == referrers_list.size()); |
1022 all_save_items_count_ = static_cast<int>(resources_list.size()) + | 1071 all_save_items_count_ = static_cast<int>(resources_list.size()) + |
1023 static_cast<int>(frames_list.size()); | 1072 static_cast<int>(frames_list.size()); |
1024 | 1073 |
1025 // We use total bytes as the total number of files we want to save. | 1074 // We use total bytes as the total number of files we want to save. |
1026 download_->set_total_bytes(all_save_items_count_); | 1075 if (download_) |
| 1076 download_->set_total_bytes(all_save_items_count_); |
1027 | 1077 |
1028 if (all_save_items_count_) { | 1078 if (all_save_items_count_) { |
1029 // Put all sub-resources to wait list. | 1079 // Put all sub-resources to wait list. |
1030 for (int i = 0; i < static_cast<int>(resources_list.size()); ++i) { | 1080 for (int i = 0; i < static_cast<int>(resources_list.size()); ++i) { |
1031 const GURL& u = resources_list[i]; | 1081 const GURL& u = resources_list[i]; |
1032 DCHECK(u.is_valid()); | 1082 DCHECK(u.is_valid()); |
1033 SaveFileCreateInfo::SaveFileSource save_source = u.SchemeIsFile() ? | 1083 SaveFileCreateInfo::SaveFileSource save_source = u.SchemeIsFile() ? |
1034 SaveFileCreateInfo::SAVE_FILE_FROM_FILE : | 1084 SaveFileCreateInfo::SAVE_FILE_FROM_FILE : |
1035 SaveFileCreateInfo::SAVE_FILE_FROM_NET; | 1085 SaveFileCreateInfo::SAVE_FILE_FROM_NET; |
1036 SaveItem* save_item = new SaveItem(u, referrers_list[i], | 1086 SaveItem* save_item = new SaveItem(u, referrers_list[i], |
(...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1304 bool SavePackage::IsSavableContents(const std::string& contents_mime_type) { | 1354 bool SavePackage::IsSavableContents(const std::string& contents_mime_type) { |
1305 // WebKit creates Document object when MIME type is application/xhtml+xml, | 1355 // WebKit creates Document object when MIME type is application/xhtml+xml, |
1306 // so we also support this MIME type. | 1356 // so we also support this MIME type. |
1307 return contents_mime_type == "text/html" || | 1357 return contents_mime_type == "text/html" || |
1308 contents_mime_type == "text/xml" || | 1358 contents_mime_type == "text/xml" || |
1309 contents_mime_type == "application/xhtml+xml" || | 1359 contents_mime_type == "application/xhtml+xml" || |
1310 contents_mime_type == "text/plain" || | 1360 contents_mime_type == "text/plain" || |
1311 contents_mime_type == "text/css" || | 1361 contents_mime_type == "text/css" || |
1312 net::IsSupportedJavascriptMimeType(contents_mime_type.c_str()); | 1362 net::IsSupportedJavascriptMimeType(contents_mime_type.c_str()); |
1313 } | 1363 } |
| 1364 |
| 1365 void SavePackage::StopObservation() { |
| 1366 DCHECK(download_); |
| 1367 DCHECK(download_manager_); |
| 1368 |
| 1369 download_->RemoveObserver(this); |
| 1370 download_ = NULL; |
| 1371 download_manager_ = NULL; |
| 1372 } |
| 1373 |
| 1374 void SavePackage::OnDownloadUpdated(DownloadItem* download) { |
| 1375 DCHECK(download_); |
| 1376 DCHECK(download_ == download); |
| 1377 DCHECK(download_manager_); |
| 1378 |
| 1379 // Check for removal. |
| 1380 if (download->state() == DownloadItem::REMOVING) |
| 1381 StopObservation(); |
| 1382 } |
| 1383 |
| 1384 void SavePackage::FinalizeDownloadEntry() { |
| 1385 DCHECK(download_); |
| 1386 DCHECK(download_manager_); |
| 1387 |
| 1388 download_manager_->SavePageDownloadFinished(download_); |
| 1389 StopObservation(); |
| 1390 } |
OLD | NEW |