diff options
author | ananta@chromium.org <ananta@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-12-03 21:32:19 +0000 |
---|---|---|
committer | ananta@chromium.org <ananta@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-12-03 21:32:19 +0000 |
commit | 3eb8a7049a1678c35845c10e95ecc4bf303b59e2 (patch) | |
tree | ac63296aaca85259b015036af4d34acccbb62ea1 /chrome_frame | |
parent | 2d8099cf56475b6989911ea8e573cbeb26724f3d (diff) | |
download | chromium_src-3eb8a7049a1678c35845c10e95ecc4bf303b59e2.zip chromium_src-3eb8a7049a1678c35845c10e95ecc4bf303b59e2.tar.gz chromium_src-3eb8a7049a1678c35845c10e95ecc4bf303b59e2.tar.bz2 |
Refreshing a ChromeFrame page which was received in response to a top level POST to a page
in IE should reissue the POST request after bringing up a confirmation dialog.
This CL adds support to ChromeFrame to achieve this. Ideally we would want IE to display
the confirmation dialog for the POST. However the doc object host which is implemented by
IEFrame expects the doc object to implement the IHTMLDocument interface and a bunch of private
interfaces.
To reissue the POST request we save away the POST data and headers in the navigation manager
instance which is per BHO. When we refresh the page in ChromeFrame the active document on
seeing that we have posted data issues a navigation back to the URL with the posted data
and saved headers. All other refreshes continue to work the same way as before, i.e. the
refresh request is sent to Chrome on the automation channel. The confirmation dialog is
put up by the active document with the same text and caption as that in Chrome.
Fixes bug http://code.google.com/p/chromium/issues/detail?id=64901
BUG=64901
TEST=Covered by new ChromeFrame unit test
Review URL: http://codereview.chromium.org/5595002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@68213 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome_frame')
-rw-r--r-- | chrome_frame/bho.cc | 2 | ||||
-rw-r--r-- | chrome_frame/chrome_active_document.cc | 32 | ||||
-rw-r--r-- | chrome_frame/chrome_frame_activex_base.h | 11 | ||||
-rw-r--r-- | chrome_frame/test/navigation_test.cc | 77 | ||||
-rw-r--r-- | chrome_frame/urlmon_moniker.h | 30 |
5 files changed, 143 insertions, 9 deletions
diff --git a/chrome_frame/bho.cc b/chrome_frame/bho.cc index 5e74881..35623b3 100644 --- a/chrome_frame/bho.cc +++ b/chrome_frame/bho.cc @@ -132,6 +132,8 @@ STDMETHODIMP Bho::BeforeNavigate2(IDispatch* dispatch, VARIANT* url, if (is_top_level) { set_url(url->bstrVal); set_referrer(""); + set_post_data(post_data); + set_headers(headers); } return S_OK; } diff --git a/chrome_frame/chrome_active_document.cc b/chrome_frame/chrome_active_document.cc index 6000505..deee511 100644 --- a/chrome_frame/chrome_active_document.cc +++ b/chrome_frame/chrome_active_document.cc @@ -74,6 +74,7 @@ HRESULT ChromeActiveDocument::FinalConstruct() { // optimization to get Chrome active documents to load faster. ChromeActiveDocument* cached_document = g_active_doc_cache.Get(); if (cached_document && cached_document->IsValid()) { + SetResourceModule(); DCHECK(automation_client_.get() == NULL); automation_client_.swap(cached_document->automation_client_); DVLOG(1) << "Reusing automation client instance from " << cached_document; @@ -1070,6 +1071,37 @@ HRESULT ChromeActiveDocument::OnRefreshPage(const GUID* cmd_group_guid, 0x80000000 | OLECMDIDF_WINDOWSTATE_USERVISIBLE_VALID, NULL, NULL); } + NavigationManager* mgr = NavigationManager::GetThreadInstance(); + DLOG_IF(ERROR, !mgr) << "Couldn't get instance of NavigationManager"; + + // If ChromeFrame was activated on this page as a result of a document + // received in response to a top level post, then we ask the user for + // permission to repost and issue a navigation with the saved post data + // which reinitates the whole sequence, i.e. the server receives the top + // level post and chrome frame will be reactivated in response. + if (mgr && mgr->post_data().type() != VT_EMPTY) { + if (MessageBox( + SimpleResourceLoader::Get(IDS_HTTP_POST_WARNING).c_str(), + SimpleResourceLoader::Get(IDS_HTTP_POST_WARNING_TITLE).c_str(), + MB_YESNO | MB_ICONEXCLAMATION) == IDYES) { + base::win::ScopedComPtr<IWebBrowser2> web_browser2; + DoQueryService(SID_SWebBrowserApp, m_spClientSite, + web_browser2.Receive()); + DCHECK(web_browser2); + VARIANT empty = base::win::ScopedVariant::kEmptyVariant; + VARIANT flags = { VT_I4 }; + V_I4(&flags) = navNoHistory; + + return web_browser2->Navigate2(base::win::ScopedVariant(url_).AsInput(), + &flags, + &empty, + const_cast<VARIANT*>(&mgr->post_data()), + const_cast<VARIANT*>(&mgr->headers())); + } else { + return S_OK; + } + } + TabProxy* tab_proxy = GetTabProxy(); if (tab_proxy) { tab_proxy->ReloadAsync(); diff --git a/chrome_frame/chrome_frame_activex_base.h b/chrome_frame/chrome_frame_activex_base.h index 1dd2755..c7dd5cf 100644 --- a/chrome_frame/chrome_frame_activex_base.h +++ b/chrome_frame/chrome_frame_activex_base.h @@ -251,17 +251,12 @@ END_MSG_MAP() DECLARE_PROTECT_FINAL_CONSTRUCT() - virtual void SetResourceModule() { + void SetResourceModule() { DCHECK(NULL == prev_resource_instance_); SimpleResourceLoader* loader_instance = SimpleResourceLoader::instance(); DCHECK(loader_instance); HMODULE res_dll = loader_instance->GetResourceModuleHandle(); - prev_resource_instance_ = _AtlBaseModule.SetResourceInstance(res_dll); - } - - virtual void ClearResourceModule() { - _AtlBaseModule.SetResourceInstance(prev_resource_instance_); - prev_resource_instance_ = NULL; + _AtlBaseModule.SetResourceInstance(res_dll); } HRESULT FinalConstruct() { @@ -286,8 +281,6 @@ END_MSG_MAP() void FinalRelease() { Uninitialize(); - - ClearResourceModule(); } void ResetUrlRequestManager() { diff --git a/chrome_frame/test/navigation_test.cc b/chrome_frame/test/navigation_test.cc index 0918037..457793d 100644 --- a/chrome_frame/test/navigation_test.cc +++ b/chrome_frame/test/navigation_test.cc @@ -1026,5 +1026,82 @@ TEST_F(FullTabSeleniumTest, Core) { LaunchIENavigateAndLoop(url, kSeleniumTestTimeout); } +// See bug http://code.google.com/p/chromium/issues/detail?id=64901 +// This test does the following:- +// Navigates IE to a non ChromeFrame URL. +// Performs a top level form post in the document +// In response to the POST send over a html document containing a meta tag +// This would cause IE to switch to ChromeFrame. +// Refresh the page in ChromeFrame. +// This should bring up a confirmation dialog which we hit yes on. This should +// reissue the top level post request in response to which the html content +// containing the meta tag is sent again. +TEST_F(FullTabDownloadTest, TopLevelPostReissueFromChromeFramePage) { + chrome_frame_test::MockWindowObserver post_reissue_watcher; + post_reissue_watcher.WatchWindow("Confirm Form Resubmission", ""); + + EXPECT_CALL(server_mock_, Get(_, StrEq(L"/post_source.html"), _)) + .WillOnce(SendFast( + "HTTP/1.1 200 OK\r\n" + "Content-Type: text/html\r\n", + "<html>" + "<head>" + " <script type=\"text/javascript\">" + " function onLoad() {" + " document.getElementById(\"myform\").submit();}</script></head>" + " <body onload=\"setTimeout(onLoad, 2000);\">" + " <form id=\"myform\" action=\"post_target.html\" method=\"POST\">" + "</form></body></html>")); + + EXPECT_CALL(server_mock_, Post(_, StrEq(L"/post_target.html"), _)) + .Times(2) + .WillRepeatedly( + SendFast( + "HTTP/1.1 200 OK\r\n" + "Content-Type: text/html\r\n", + "<html>" + "<head><meta http-equiv=\"x-ua-compatible\" content=\"chrome=1\" />" + "</head>" + "<body> Target page in ChromeFrame </body>" + "</html>")); + + EXPECT_CALL(post_reissue_watcher, OnWindowOpen(_)) + .WillOnce(DelayAccDoDefaultAction( + AccObjectMatcher(L"Yes", L"push button"), + 1000)); + + EXPECT_CALL(post_reissue_watcher, OnWindowClose(_)); + + std::wstring src_url = server_mock_.Resolve(L"/post_source.html"); + std::wstring tgt_url = server_mock_.Resolve(L"/post_target.html"); + + EXPECT_CALL(ie_mock_, OnFileDownload(_, _)).Times(testing::AnyNumber()); + + EXPECT_CALL(ie_mock_, OnBeforeNavigate2(_, + testing::Field(&VARIANT::bstrVal, + StrEq(src_url)), _, _, _, _, _)); + EXPECT_CALL(ie_mock_, OnNavigateComplete2(_, + testing::Field(&VARIANT::bstrVal, + StrEq(src_url)))); + EXPECT_CALL(ie_mock_, OnLoad(false, StrEq(src_url))); + + EXPECT_CALL(ie_mock_, OnLoad(true, StrEq(tgt_url))) + .Times(2); + + EXPECT_CALL(ie_mock_, OnBeforeNavigate2(_, + testing::Field(&VARIANT::bstrVal, + StrEq(tgt_url)), _, _, _, _, _)) + .Times(2); + + EXPECT_CALL(ie_mock_, OnNavigateComplete2(_, + testing::Field(&VARIANT::bstrVal, + StrEq(tgt_url)))) + .Times(2) + .WillOnce(testing::DoAll(DelayRefresh(&ie_mock_, &loop_, 2000), + DelayCloseBrowserMock(&loop_, 4000, &ie_mock_))) + .WillOnce(testing::Return()); + + LaunchIENavigateAndLoop(src_url, kChromeFrameLongNavigationTimeoutInSeconds); +} } // namespace chrome_frame_test diff --git a/chrome_frame/urlmon_moniker.h b/chrome_frame/urlmon_moniker.h index a5b7fdf..dde70adb 100644 --- a/chrome_frame/urlmon_moniker.h +++ b/chrome_frame/urlmon_moniker.h @@ -13,6 +13,7 @@ #include "base/lazy_instance.h" #include "base/logging.h" #include "base/thread_local.h" +#include "base/win/scoped_variant.h" #include "googleurl/src/gurl.h" #include "chrome_frame/utils.h" @@ -122,9 +123,38 @@ class NavigationManager { // and need to switch over from mshtml to CF. virtual HRESULT NavigateToCurrentUrlInCF(IBrowserService* browser); + void set_post_data(VARIANT* post_data) { + post_data_.Reset(); + if (post_data) { + if (V_VT(post_data) == (VT_BYREF | VT_VARIANT)) { + post_data_.Set(*post_data->pvarVal); + } else { + NOTREACHED() << "unexpected type for post_data: " + << std::hex << post_data->vt; + } + } + } + + const base::win::ScopedVariant& post_data() const { + return post_data_; + } + + void set_headers(VARIANT* headers) { + headers_.Reset(); + if (headers) { + headers_ = *headers; + } + } + + const base::win::ScopedVariant& headers() const { + return headers_; + } + protected: std::string referrer_; std::wstring url_; + base::win::ScopedVariant post_data_; + base::win::ScopedVariant headers_; static base::LazyInstance<base::ThreadLocalPointer<NavigationManager> > thread_singleton_; |