Bug 241972 (new window opened by window.open('xxx.exe') or target="_blank" isn't closed automatically when a download begins). Fix stores state on the channel indicating whether a window was opened specifically for the download. The external helper app service then closes the window if there is no refresh header and if the window was opened specifically for the download. r=cbiesinger, sr=darin
This commit is contained in:
Родитель
c4fc4c0291
Коммит
eaafa1a039
|
@ -819,6 +819,9 @@ nsDocShell::LoadURI(nsIURI * aURI,
|
|||
if (aLoadFlags & LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP)
|
||||
flags |= INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
|
||||
|
||||
if (aLoadFlags & LOAD_FLAGS_NEW_WINDOW)
|
||||
flags |= INTERNAL_LOAD_FLAGS_NEW_WINDOW;
|
||||
|
||||
rv = InternalLoad(aURI,
|
||||
referrer,
|
||||
owner,
|
||||
|
@ -4530,6 +4533,9 @@ NS_IMETHODIMP nsDocShell::SetupRefreshURI(nsIChannel * aChannel)
|
|||
if (!refreshHeader.IsEmpty()) {
|
||||
SetupReferrerFromChannel(aChannel);
|
||||
rv = SetupRefreshURIFromHeader(mCurrentURI, refreshHeader);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
return NS_REFRESHURI_HEADER_FOUND;
|
||||
}
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
|
@ -6372,6 +6378,8 @@ nsDocShell::InternalLoad(nsIURI * aURI,
|
|||
NS_ENSURE_TRUE(win, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
isNewWindow = PR_TRUE;
|
||||
aFlags |= INTERNAL_LOAD_FLAGS_NEW_WINDOW;
|
||||
|
||||
nsDependentString name(aWindowTarget);
|
||||
nsCOMPtr<nsIDOMWindow> newWin;
|
||||
rv = win->Open(EmptyString(), // URL to load
|
||||
|
@ -6718,7 +6726,8 @@ nsDocShell::InternalLoad(nsIURI * aURI,
|
|||
rv = DoURILoad(aURI, aReferrer,
|
||||
!(aFlags & INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER),
|
||||
owner, aTypeHint, aPostData, aHeadersData, aFirstParty,
|
||||
aDocShell, getter_AddRefs(req));
|
||||
aDocShell, getter_AddRefs(req),
|
||||
aFlags & INTERNAL_LOAD_FLAGS_NEW_WINDOW);
|
||||
if (req && aRequest)
|
||||
NS_ADDREF(*aRequest = req);
|
||||
|
||||
|
@ -6778,7 +6787,8 @@ nsDocShell::DoURILoad(nsIURI * aURI,
|
|||
nsIInputStream * aHeadersData,
|
||||
PRBool aFirstParty,
|
||||
nsIDocShell ** aDocShell,
|
||||
nsIRequest ** aRequest)
|
||||
nsIRequest ** aRequest,
|
||||
PRBool aIsNewWindowTarget)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIURILoader> uriLoader;
|
||||
|
@ -6948,6 +6958,15 @@ nsDocShell::DoURILoad(nsIURI * aURI,
|
|||
channel->SetOwner(aOwner);
|
||||
}
|
||||
|
||||
if (aIsNewWindowTarget) {
|
||||
nsCOMPtr<nsIWritablePropertyBag2> props = do_QueryInterface(channel);
|
||||
if (props) {
|
||||
props->SetPropertyAsBool(
|
||||
NS_LITERAL_STRING("docshell.newWindowTarget"),
|
||||
PR_TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
rv = DoChannelLoad(channel, uriLoader);
|
||||
|
||||
//
|
||||
|
|
|
@ -241,7 +241,8 @@ protected:
|
|||
nsIInputStream * aHeadersData,
|
||||
PRBool firstParty,
|
||||
nsIDocShell ** aDocShell,
|
||||
nsIRequest ** aRequest);
|
||||
nsIRequest ** aRequest,
|
||||
PRBool aIsNewWindowTarget);
|
||||
NS_IMETHOD AddHeadersToChannel(nsIInputStream * aHeadersData,
|
||||
nsIChannel * aChannel);
|
||||
virtual nsresult DoChannelLoad(nsIChannel * aChannel,
|
||||
|
|
|
@ -122,6 +122,9 @@ interface nsIDocShell : nsISupports
|
|||
const long INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER = 0x2;
|
||||
const long INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP = 0x4;
|
||||
|
||||
// This flag marks the first load in a new window.
|
||||
const long INTERNAL_LOAD_FLAGS_NEW_WINDOW = 0x8;
|
||||
|
||||
/**
|
||||
* Loads the given URI. This method is identical to loadURI(...) except
|
||||
* that its parameter list is broken out instead of being packaged inside
|
||||
|
|
|
@ -183,6 +183,11 @@ interface nsIWebNavigation : nsISupports
|
|||
*/
|
||||
const unsigned long LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP = 0x2000;
|
||||
|
||||
/**
|
||||
* This flag specifies that this load is the first load in a new window.
|
||||
*/
|
||||
const unsigned long LOAD_FLAGS_NEW_WINDOW = 0x4000;
|
||||
|
||||
/**
|
||||
* Loads a given URI. This will give priority to loading the requested URI
|
||||
* in the object implementing this interface. If it can't be loaded here
|
||||
|
|
|
@ -844,7 +844,8 @@ nsWindowWatcher::OpenWindowJSInternal(nsIDOMWindow *aParent,
|
|||
}
|
||||
|
||||
newDocShell->LoadURI(uriToLoad, loadInfo,
|
||||
nsIWebNavigation::LOAD_FLAGS_NONE, PR_TRUE);
|
||||
windowIsNew ? nsIWebNavigation::LOAD_FLAGS_NEW_WINDOW :
|
||||
nsIWebNavigation::LOAD_FLAGS_NONE, PR_TRUE);
|
||||
}
|
||||
|
||||
if (isNewToplevelWindow)
|
||||
|
|
|
@ -79,6 +79,7 @@ REQUIRES = xpcom \
|
|||
docshell \
|
||||
windowwatcher \
|
||||
embed_base \
|
||||
dom \
|
||||
$(NULL)
|
||||
|
||||
ifdef MOZ_PHOENIX
|
||||
|
|
|
@ -112,6 +112,10 @@
|
|||
#include "nsIGlobalHistory.h" // to mark downloads as visited
|
||||
#include "nsIGlobalHistory2.h" // to mark downloads as visited
|
||||
|
||||
#include "nsIDOMWindow.h"
|
||||
#include "nsIDOMWindowInternal.h"
|
||||
#include "nsIDocShell.h"
|
||||
|
||||
#include "nsCRT.h"
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
|
@ -1343,6 +1347,8 @@ nsExternalAppHandler::nsExternalAppHandler(nsIMIMEInfo * aMIMEInfo,
|
|||
, mWindowContext(aWindowContext)
|
||||
, mSuggestedFileName(aSuggestedFilename)
|
||||
, mCanceled(PR_FALSE)
|
||||
, mHasRefreshHeader(PR_FALSE)
|
||||
, mShouldCloseWindow(PR_FALSE)
|
||||
, mReceivedDispositionInfo(PR_FALSE)
|
||||
, mStopRequestIssued(PR_FALSE)
|
||||
, mProgressListenerInitialized(PR_FALSE)
|
||||
|
@ -1610,6 +1616,12 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest *request, nsISuppo
|
|||
mContentLength = len;
|
||||
}
|
||||
|
||||
// Determine whether a new window was opened specifically for this request
|
||||
if (props) {
|
||||
props->GetPropertyAsBool(NS_LITERAL_STRING("docshell.newWindowTarget"),
|
||||
&mShouldCloseWindow);
|
||||
}
|
||||
|
||||
// Now get the URI
|
||||
if (aChannel)
|
||||
{
|
||||
|
@ -2066,6 +2078,10 @@ nsresult nsExternalAppHandler::ExecuteDesiredAction()
|
|||
}
|
||||
mWebProgressListener->OnStateChange(nsnull, nsnull, nsIWebProgressListener::STATE_STOP, NS_OK);
|
||||
}
|
||||
|
||||
// Close the underlying DOMWindow if there is no refresh header
|
||||
// and it was opened specifically for the download
|
||||
MaybeCloseWindow();
|
||||
}
|
||||
|
||||
return rv;
|
||||
|
@ -2452,6 +2468,10 @@ NS_IMETHODIMP nsExternalAppHandler::Cancel(nsresult aReason)
|
|||
NS_ENSURE_ARG(NS_FAILED(aReason));
|
||||
// XXX should not ignore the reason
|
||||
|
||||
// Close the underlying DOMWindow if there is no refresh header
|
||||
// and it was opened specifically for the download
|
||||
MaybeCloseWindow();
|
||||
|
||||
mCanceled = PR_TRUE;
|
||||
// Break our reference cycle with the helper app dialog (set up in
|
||||
// OnStartRequest)
|
||||
|
@ -2497,8 +2517,12 @@ void nsExternalAppHandler::ProcessAnyRefreshTags()
|
|||
if (mWindowContext && mOriginalChannel)
|
||||
{
|
||||
nsCOMPtr<nsIRefreshURI> refreshHandler (do_GetInterface(mWindowContext));
|
||||
if (refreshHandler)
|
||||
refreshHandler->SetupRefreshURI(mOriginalChannel);
|
||||
if (refreshHandler) {
|
||||
nsresult rv = refreshHandler->SetupRefreshURI(mOriginalChannel);
|
||||
if (rv == NS_REFRESHURI_HEADER_FOUND) {
|
||||
mHasRefreshHeader = PR_TRUE;
|
||||
}
|
||||
}
|
||||
mOriginalChannel = nsnull;
|
||||
}
|
||||
}
|
||||
|
@ -2530,6 +2554,21 @@ PRBool nsExternalAppHandler::GetNeverAskFlagFromPref(const char * prefName, cons
|
|||
return PR_TRUE;
|
||||
}
|
||||
|
||||
nsresult nsExternalAppHandler::MaybeCloseWindow()
|
||||
{
|
||||
nsCOMPtr<nsIDOMWindow> window(do_GetInterface(mWindowContext));
|
||||
nsCOMPtr<nsIDOMWindowInternal> internalWindow = do_QueryInterface(window);
|
||||
NS_ENSURE_STATE(internalWindow);
|
||||
|
||||
// Only close the page if there is no refresh header and if the window
|
||||
// was opened specifically for the download
|
||||
if (!mHasRefreshHeader && mShouldCloseWindow) {
|
||||
internalWindow->Close();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// The following section contains our nsIMIMEService implementation and related methods.
|
||||
//
|
||||
|
@ -2871,4 +2910,3 @@ PRBool nsExternalHelperAppService::GetTypeFromExtras(const nsACString& aExtensio
|
|||
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
|
|
|
@ -367,6 +367,19 @@ protected:
|
|||
*/
|
||||
PRPackedBool mCanceled;
|
||||
|
||||
/**
|
||||
* This flag is set if a refresh header was found. In this case, we
|
||||
* don't want to close the dom window after handling the content.
|
||||
*/
|
||||
PRPackedBool mHasRefreshHeader;
|
||||
|
||||
/**
|
||||
* This is set based on whether the channel indicates that a new window
|
||||
* was opened specifically for this download. If so, then we
|
||||
* close it.
|
||||
*/
|
||||
PRBool mShouldCloseWindow;
|
||||
|
||||
/**
|
||||
* have we received information from the user about how they want to
|
||||
* dispose of this content
|
||||
|
@ -468,7 +481,14 @@ protected:
|
|||
* Utility function to send proper error notification to web progress listener
|
||||
*/
|
||||
void SendStatusChange(ErrorType type, nsresult aStatus, nsIRequest *aRequest, const nsAFlatString &path);
|
||||
|
||||
|
||||
/**
|
||||
* Closes the window context if it does not have a refresh header
|
||||
* and it never displayed content before the external helper app
|
||||
* service was invoked.
|
||||
*/
|
||||
nsresult MaybeCloseWindow();
|
||||
|
||||
nsCOMPtr<nsIWebProgressListener2> mWebProgressListener;
|
||||
nsCOMPtr<nsIChannel> mOriginalChannel; /**< in the case of a redirect, this will be the pre-redirect channel. */
|
||||
nsCOMPtr<nsIHelperAppLauncherDialog> mDialog;
|
||||
|
|
|
@ -62,6 +62,9 @@ interface nsIRefreshURI : nsISupports {
|
|||
* request will be queued and executed when the current page
|
||||
* finishes loading.
|
||||
*
|
||||
* Returns the NS_REFRESHURI_HEADER_FOUND success code if a refresh
|
||||
* header was found and successfully setup.
|
||||
*
|
||||
* @param aChannel The channel to be parsed.
|
||||
*/
|
||||
void setupRefreshURI(in nsIChannel aChannel);
|
||||
|
@ -82,3 +85,14 @@ interface nsIRefreshURI : nsISupports {
|
|||
*/
|
||||
void cancelRefreshURITimers();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* This success code indicates that a refresh header was found and
|
||||
* successfully setup.
|
||||
*/
|
||||
%{C++
|
||||
#define NS_REFRESHURI_HEADER_FOUND \
|
||||
NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_URILOADER, \
|
||||
2)
|
||||
%}
|
||||
|
|
Загрузка…
Ссылка в новой задаче