diff options
-rw-r--r-- | chrome/browser/chromeos/imageburner/burn_manager.cc | 1 | ||||
-rw-r--r-- | chrome/browser/download/download_browsertest.cc | 58 | ||||
-rw-r--r-- | chrome/browser/extensions/webstore_installer.cc | 2 | ||||
-rw-r--r-- | chrome/browser/tab_contents/render_view_context_menu.cc | 48 | ||||
-rw-r--r-- | chrome/test/data/downloads/form_page_to_post.html | 17 | ||||
-rw-r--r-- | content/browser/download/download_manager_impl.cc | 20 | ||||
-rw-r--r-- | content/browser/download/download_manager_impl.h | 1 | ||||
-rw-r--r-- | content/browser/download/drag_download_file.cc | 1 | ||||
-rw-r--r-- | content/browser/renderer_host/resource_dispatcher_host.cc | 9 | ||||
-rw-r--r-- | content/browser/tab_contents/tab_contents.cc | 48 | ||||
-rw-r--r-- | content/browser/tab_contents/tab_contents.h | 3 | ||||
-rw-r--r-- | content/public/browser/download_manager.h | 6 | ||||
-rw-r--r-- | content/test/mock_download_manager.h | 3 |
13 files changed, 177 insertions, 40 deletions
diff --git a/chrome/browser/chromeos/imageburner/burn_manager.cc b/chrome/browser/chromeos/imageburner/burn_manager.cc index 502b588..ffb35eb 100644 --- a/chrome/browser/chromeos/imageburner/burn_manager.cc +++ b/chrome/browser/chromeos/imageburner/burn_manager.cc @@ -432,6 +432,7 @@ void Downloader::OnFileStreamCreated(const GURL& url, web_contents->GetURL(), web_contents->GetEncoding(), false, + -1, save_info, web_contents); } else { diff --git a/chrome/browser/download/download_browsertest.cc b/chrome/browser/download/download_browsertest.cc index 1cf1b05..f2ac365 100644 --- a/chrome/browser/download/download_browsertest.cc +++ b/chrome/browser/download/download_browsertest.cc @@ -44,9 +44,11 @@ #include "content/browser/download/download_persistent_store_info.h" #include "content/browser/net/url_request_mock_http_job.h" #include "content/browser/net/url_request_slow_download_job.h" +#include "content/browser/renderer_host/render_view_host.h" #include "content/browser/renderer_host/resource_dispatcher_host.h" #include "content/public/browser/download_item.h" #include "content/public/browser/download_manager.h" +#include "content/public/browser/notification_source.h" #include "content/public/browser/web_contents.h" #include "content/public/common/page_transition_types.h" #include "net/base/net_util.h" @@ -1701,7 +1703,7 @@ IN_PROC_BROWSER_TEST_F(DownloadTest, DownloadUrl) { DownloadSaveInfo save_info; save_info.prompt_for_save_location = true; DownloadManagerForBrowser(browser())->DownloadUrl( - url, GURL(""), "", false, save_info, web_contents); + url, GURL(""), "", false, -1, save_info, web_contents); observer->WaitForFinished(); EXPECT_TRUE(observer->select_file_dialog_seen()); @@ -1728,7 +1730,7 @@ IN_PROC_BROWSER_TEST_F(DownloadTest, DownloadUrlToPath) { DownloadTestObserver* observer(CreateWaiter(browser(), 1)); DownloadManagerForBrowser(browser())->DownloadUrl( - url, GURL(""), "", false, save_info, web_contents); + url, GURL(""), "", false, -1, save_info, web_contents); observer->WaitForFinished(); // Check state. @@ -1774,3 +1776,55 @@ IN_PROC_BROWSER_TEST_F(DownloadTest, SavePageNonHTMLViaGet) { ASSERT_EQ(1u, download_items.size()); ASSERT_EQ(url, download_items[0]->GetOriginalUrl()); } + +IN_PROC_BROWSER_TEST_F(DownloadTest, SavePageNonHTMLViaPost) { + // Do initial setup. + ASSERT_TRUE(InitialSetup(false)); + ASSERT_TRUE(test_server()->Start()); + NullSelectFile(browser()); + std::vector<DownloadItem*> download_items; + GetDownloads(browser(), &download_items); + ASSERT_TRUE(download_items.empty()); + + // Navigate to a form page. + GURL form_url = test_server()->GetURL( + "files/downloads/form_page_to_post.html"); + ASSERT_TRUE(form_url.is_valid()); + ui_test_utils::NavigateToURL(browser(), form_url); + + // Submit the form. This will send a POST reqeuest, and the response is a + // JPEG image. The resource also has Cache-Control: no-cache set, + // which normally requires revalidation each time. + GURL jpeg_url = test_server()->GetURL("files/post/downloads/image.jpg"); + ASSERT_TRUE(jpeg_url.is_valid()); + WebContents* web_contents = browser()->GetSelectedWebContents(); + ASSERT_TRUE(web_contents != NULL); + ui_test_utils::WindowedNotificationObserver observer( + content::NOTIFICATION_NAV_ENTRY_COMMITTED, + content::Source<content::NavigationController>( + &web_contents->GetController())); + RenderViewHost* render_view_host = web_contents->GetRenderViewHost(); + ASSERT_TRUE(render_view_host != NULL); + render_view_host->ExecuteJavascriptInWebFrame( + string16(), ASCIIToUTF16("SubmitForm()")); + observer.Wait(); + EXPECT_EQ(jpeg_url, web_contents->GetURL()); + + // Stop the test server, and then try to save the page. If cache validation + // is not bypassed then this will fail since the server is no longer + // reachable. This will also fail if it tries to be retrieved via "GET" + // rather than "POST". + ASSERT_TRUE(test_server()->Stop()); + scoped_ptr<DownloadTestObserver> waiter( + new DownloadTestObserver( + DownloadManagerForBrowser(browser()), 1, DownloadItem::COMPLETE, + false, DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL)); + browser()->SavePage(); + waiter->WaitForFinished(); + + // Validate that the correct file was downloaded. + GetDownloads(browser(), &download_items); + EXPECT_TRUE(waiter->select_file_dialog_seen()); + ASSERT_EQ(1u, download_items.size()); + ASSERT_EQ(jpeg_url, download_items[0]->GetOriginalUrl()); +} diff --git a/chrome/browser/extensions/webstore_installer.cc b/chrome/browser/extensions/webstore_installer.cc index cb9a9b03..57f1493 100644 --- a/chrome/browser/extensions/webstore_installer.cc +++ b/chrome/browser/extensions/webstore_installer.cc @@ -215,7 +215,7 @@ void WebstoreInstaller::StartDownload(FilePath file) { download_util::INITIATED_BY_WEBSTORE_INSTALLER_COUNT); profile_->GetDownloadManager()->DownloadUrl( download_url_, referrer, "", - false, save_info, controller_->GetWebContents()); + false, -1, save_info, controller_->GetWebContents()); } void WebstoreInstaller::ReportFailure(const std::string& error) { diff --git a/chrome/browser/tab_contents/render_view_context_menu.cc b/chrome/browser/tab_contents/render_view_context_menu.cc index e24f65e..af82831 100644 --- a/chrome/browser/tab_contents/render_view_context_menu.cc +++ b/chrome/browser/tab_contents/render_view_context_menu.cc @@ -1484,27 +1484,51 @@ void RenderViewContextMenu::ExecuteCommand(int id, int event_flags) { content::PAGE_TRANSITION_LINK); break; - case IDC_CONTENT_CONTEXT_SAVEAVAS: - case IDC_CONTENT_CONTEXT_SAVEIMAGEAS: case IDC_CONTENT_CONTEXT_SAVELINKAS: { download_util::RecordDownloadCount( download_util::INITIATED_BY_CONTEXT_MENU_COUNT); const GURL& referrer = params_.frame_url.is_empty() ? params_.page_url : params_.frame_url; - const GURL& url = - (id == IDC_CONTENT_CONTEXT_SAVELINKAS ? params_.link_url : - params_.src_url); + const GURL& url = params_.link_url; + DownloadSaveInfo save_info; + save_info.prompt_for_save_location = true; DownloadManager* dlm = DownloadServiceFactory::GetForProfile(profile_)->GetDownloadManager(); - // For images and AV "Save As" context menu commands, save the cached - // data even if it is no longer valid. This helps ensure that the content - // that is visible on the page is what is saved. For links, this behavior - // is not desired since the content being linked to is not visible. - bool prefer_cache = (id != IDC_CONTENT_CONTEXT_SAVELINKAS); + dlm->DownloadUrl(url, + referrer, + params_.frame_charset, + false, // Don't prefer_cache + -1, // No POST id + save_info, + source_web_contents_); + break; + } + + case IDC_CONTENT_CONTEXT_SAVEAVAS: + case IDC_CONTENT_CONTEXT_SAVEIMAGEAS: { + download_util::RecordDownloadCount( + download_util::INITIATED_BY_CONTEXT_MENU_COUNT); + const GURL& referrer = + params_.frame_url.is_empty() ? params_.page_url : params_.frame_url; + const GURL& url = params_.src_url; DownloadSaveInfo save_info; save_info.prompt_for_save_location = true; - dlm->DownloadUrl(url, referrer, params_.frame_charset, - prefer_cache, save_info, source_web_contents_); + int64 post_id = -1; + if (url == source_web_contents_->GetURL()) { + const NavigationEntry* entry = + source_web_contents_->GetController().GetActiveEntry(); + if (entry) + post_id = entry->GetPostID(); + } + DownloadManager* dlm = + DownloadServiceFactory::GetForProfile(profile_)->GetDownloadManager(); + dlm->DownloadUrl(url, + referrer, + "", + true, // prefer_cache + post_id, + save_info, + source_web_contents_); break; } diff --git a/chrome/test/data/downloads/form_page_to_post.html b/chrome/test/data/downloads/form_page_to_post.html new file mode 100644 index 0000000..8202505 --- /dev/null +++ b/chrome/test/data/downloads/form_page_to_post.html @@ -0,0 +1,17 @@ +<html> +<head> + <title>Page with POST form</title> + +<script> + function SubmitForm() { + document.forms['doit'].submit(); + } +</script> + +</head> +<body> + <form id="doit" action="/files/post/downloads/image.jpg" method="post"> + <input type="Submit" value="Do It"/> + </form> +</body> +</html> diff --git a/content/browser/download/download_manager_impl.cc b/content/browser/download/download_manager_impl.cc index aee4d14..ae29289 100644 --- a/content/browser/download/download_manager_impl.cc +++ b/content/browser/download/download_manager_impl.cc @@ -34,6 +34,7 @@ #include "content/public/browser/notification_types.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/web_contents_delegate.h" +#include "net/base/upload_data.h" // TODO(benjhayden): Change this to DCHECK when we have more debugging // information from the next dev cycle, before the next stable/beta branch is @@ -54,10 +55,11 @@ namespace { // Param structs exist because base::Bind can only handle 6 args. struct URLParams { - URLParams(const GURL& url, const GURL& referrer) - : url_(url), referrer_(referrer) {} + URLParams(const GURL& url, const GURL& referrer, int64 post_id) + : url_(url), referrer_(referrer), post_id_(post_id) {} GURL url_; GURL referrer_; + int64 post_id_; }; struct RenderParams { @@ -76,6 +78,17 @@ void BeginDownload(const URLParams& url_params, scoped_ptr<net::URLRequest> request( new net::URLRequest(url_params.url_, resource_dispatcher_host)); request->set_referrer(url_params.referrer_.spec()); + if (url_params.post_id_ >= 0) { + // The POST in this case does not have an actual body, and only works + // when retrieving data from cache. This is done because we don't want + // to do a re-POST without user consent, and currently don't have a good + // plan on how to display the UI for that. + DCHECK(prefer_cache); + request->set_method("POST"); + scoped_refptr<net::UploadData> upload_data = new net::UploadData(); + upload_data->set_identifier(url_params.post_id_); + request->set_upload(upload_data); + } resource_dispatcher_host->BeginDownload( request.Pass(), prefer_cache, save_info, DownloadResourceHandler::OnStartedCallback(), @@ -814,6 +827,7 @@ void DownloadManagerImpl::DownloadUrl( const GURL& referrer, const std::string& referrer_charset, bool prefer_cache, + int64 post_id, const DownloadSaveInfo& save_info, WebContents* web_contents) { ResourceDispatcherHost* resource_dispatcher_host = @@ -826,7 +840,7 @@ void DownloadManagerImpl::DownloadUrl( BrowserThread::IO, FROM_HERE, base::Bind( &BeginDownload, - URLParams(url, referrer), + URLParams(url, referrer, post_id), prefer_cache, save_info, resource_dispatcher_host, diff --git a/content/browser/download/download_manager_impl.h b/content/browser/download/download_manager_impl.h index 7fda51b..ce28cc8 100644 --- a/content/browser/download/download_manager_impl.h +++ b/content/browser/download/download_manager_impl.h @@ -59,6 +59,7 @@ class CONTENT_EXPORT DownloadManagerImpl const GURL& referrer, const std::string& referrer_encoding, bool prefer_cache, + int64 post_id, const DownloadSaveInfo& save_info, content::WebContents* web_contents) OVERRIDE; virtual void AddObserver(Observer* observer) OVERRIDE; diff --git a/content/browser/download/drag_download_file.cc b/content/browser/download/drag_download_file.cc index 81f9d12..cecb9be 100644 --- a/content/browser/download/drag_download_file.cc +++ b/content/browser/download/drag_download_file.cc @@ -137,6 +137,7 @@ void DragDownloadFile::InitiateDownload() { referrer_, referrer_encoding_, false, + -1, save_info, web_contents_); download_stats::RecordDownloadCount( diff --git a/content/browser/renderer_host/resource_dispatcher_host.cc b/content/browser/renderer_host/resource_dispatcher_host.cc index d915806..1d8c8df 100644 --- a/content/browser/renderer_host/resource_dispatcher_host.cc +++ b/content/browser/renderer_host/resource_dispatcher_host.cc @@ -894,7 +894,14 @@ net::Error ResourceDispatcherHost::BeginDownload( request->set_context(request_context); int extra_load_flags = net::LOAD_IS_DOWNLOAD; if (prefer_cache) { - extra_load_flags |= net::LOAD_PREFERRING_CACHE; + // If there is upload data attached, only retrieve from cache because there + // is no current mechanism to prompt the user for their consent for a + // re-post. For GETs, try to retrieve data from the cache and skip + // validating the entry if present. + if (request->get_upload() != NULL) + extra_load_flags |= net::LOAD_ONLY_FROM_CACHE; + else + extra_load_flags |= net::LOAD_PREFERRING_CACHE; } else { extra_load_flags |= net::LOAD_DISABLE_CACHE; } diff --git a/content/browser/tab_contents/tab_contents.cc b/content/browser/tab_contents/tab_contents.cc index 1fc4bfa..fa0e657 100644 --- a/content/browser/tab_contents/tab_contents.cc +++ b/content/browser/tab_contents/tab_contents.cc @@ -934,21 +934,10 @@ bool TabContents::IsSavable() { void TabContents::OnSavePage() { // If we can not save the page, try to download it. if (!IsSavable()) { - DownloadManager* dlm = GetBrowserContext()->GetDownloadManager(); - const GURL& current_page_url = GetURL(); - if (dlm && current_page_url.is_valid()) { - DownloadSaveInfo save_info; - save_info.prompt_for_save_location = true; - dlm->DownloadUrl(current_page_url, - GURL(), - "", - true, // prefer_cache - save_info, - this); - download_stats::RecordDownloadCount( - download_stats::INITIATED_BY_SAVE_PACKAGE_FAILURE_COUNT); - return; - } + SaveURL(GetURL(), GURL()); + download_stats::RecordDownloadCount( + download_stats::INITIATED_BY_SAVE_PACKAGE_FAILURE_COUNT); + return; } Stop(); @@ -1425,10 +1414,7 @@ void TabContents::OnUpdateZoomLimits(int minimum_percent, } void TabContents::OnSaveURL(const GURL& url) { - DownloadManager* dlm = GetBrowserContext()->GetDownloadManager(); - DownloadSaveInfo save_info; - save_info.prompt_for_save_location = true; - dlm->DownloadUrl(url, GetURL(), "", true, save_info, this); + SaveURL(url, GetURL()); } void TabContents::OnEnumerateDirectory(int request_id, @@ -2288,6 +2274,30 @@ void TabContents::SetEncoding(const std::string& encoding) { GetCanonicalEncodingNameByAliasName(encoding); } +void TabContents::SaveURL(const GURL& url, const GURL& referrer) { + DownloadManager* dlm = GetBrowserContext()->GetDownloadManager(); + if (!dlm) + return; + int64 post_id = -1; + // Check if the URL to save matches the URL of the page itself. One + // circumstance where this may not happen is when a Pepper plugin initiates + // a save. + if (url == GetURL()) { + const NavigationEntry* entry = controller_.GetActiveEntry(); + if (entry) + post_id = entry->GetPostID(); + } + DownloadSaveInfo save_info; + save_info.prompt_for_save_location = true; + dlm->DownloadUrl(url, + referrer, + "", + true, // prefer_cache + post_id, + save_info, + this); +} + void TabContents::CreateViewAndSetSizeForRVH(RenderViewHost* rvh) { RenderWidgetHostView* rwh_view = GetView()->CreateViewForWidget(rvh); // Can be NULL during tests. diff --git a/content/browser/tab_contents/tab_contents.h b/content/browser/tab_contents/tab_contents.h index 2ec9aba..db170eb 100644 --- a/content/browser/tab_contents/tab_contents.h +++ b/content/browser/tab_contents/tab_contents.h @@ -496,6 +496,9 @@ class CONTENT_EXPORT TabContents void SetEncoding(const std::string& encoding); + // Save a URL to the local filesystem. + void SaveURL(const GURL& url, const GURL& referrer); + // Stores random bits of data for others to associate with this object. // WARNING: this needs to be deleted after NavigationController. base::PropertyBag property_bag_; diff --git a/content/public/browser/download_manager.h b/content/public/browser/download_manager.h index b91f517..52a5437 100644 --- a/content/public/browser/download_manager.h +++ b/content/public/browser/download_manager.h @@ -167,7 +167,10 @@ class CONTENT_EXPORT DownloadManager // Downloads the content at |url|. |referrer| and |referrer_encoding| are the // referrer for the download, and may be empty. If |prefer_cache| is true, // then if the response to |url| is in the HTTP cache it will be used without - // revalidation. |save_info| specifies where the downloaded file should be + // revalidation. If |post_id| is non-negative, then it identifies the post + // transaction used to originally retrieve the |url| resource - it also + // requires |prefer_cache| to be |true| since re-post'ing is not done. + // |save_info| specifies where the downloaded file should be // saved, and whether the user should be prompted about the download. // |web_contents| is the web page that the download is done in context of, // and must be non-NULL. @@ -175,6 +178,7 @@ class CONTENT_EXPORT DownloadManager const GURL& referrer, const std::string& referrer_encoding, bool prefer_cache, + int64 post_id, const DownloadSaveInfo& save_info, content::WebContents* web_contents) = 0; diff --git a/content/test/mock_download_manager.h b/content/test/mock_download_manager.h index 280bc8aa..be946b5 100644 --- a/content/test/mock_download_manager.h +++ b/content/test/mock_download_manager.h @@ -51,10 +51,11 @@ class MockDownloadManager : public content::DownloadManager { base::Time remove_end)); MOCK_METHOD1(RemoveDownloads, int(base::Time remove_begin)); MOCK_METHOD0(RemoveAllDownloads, int()); - MOCK_METHOD6(DownloadUrl, void(const GURL& url, + MOCK_METHOD7(DownloadUrl, void(const GURL& url, const GURL& referrer, const std::string& referrer_encoding, bool prefer_cache, + int64 post_id, const DownloadSaveInfo& save_info, content::WebContents* web_contents)); MOCK_METHOD1(AddObserver, void(Observer* observer)); |