diff --git a/mozilla/docshell/base/nsDocShell.cpp b/mozilla/docshell/base/nsDocShell.cpp index 765f4d79663..66fb25dfb40 100644 --- a/mozilla/docshell/base/nsDocShell.cpp +++ b/mozilla/docshell/base/nsDocShell.cpp @@ -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 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 uriLoader; @@ -6948,6 +6958,15 @@ nsDocShell::DoURILoad(nsIURI * aURI, channel->SetOwner(aOwner); } + if (aIsNewWindowTarget) { + nsCOMPtr props = do_QueryInterface(channel); + if (props) { + props->SetPropertyAsBool( + NS_LITERAL_STRING("docshell.newWindowTarget"), + PR_TRUE); + } + } + rv = DoChannelLoad(channel, uriLoader); // diff --git a/mozilla/docshell/base/nsDocShell.h b/mozilla/docshell/base/nsDocShell.h index bb8125ff1fa..b333c375eaf 100644 --- a/mozilla/docshell/base/nsDocShell.h +++ b/mozilla/docshell/base/nsDocShell.h @@ -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, diff --git a/mozilla/docshell/base/nsIDocShell.idl b/mozilla/docshell/base/nsIDocShell.idl index 9e864d3ee6d..234e1b022da 100644 --- a/mozilla/docshell/base/nsIDocShell.idl +++ b/mozilla/docshell/base/nsIDocShell.idl @@ -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 diff --git a/mozilla/docshell/base/nsIWebNavigation.idl b/mozilla/docshell/base/nsIWebNavigation.idl index 823a9b877b9..e988652aa05 100644 --- a/mozilla/docshell/base/nsIWebNavigation.idl +++ b/mozilla/docshell/base/nsIWebNavigation.idl @@ -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 diff --git a/mozilla/embedding/components/windowwatcher/src/nsWindowWatcher.cpp b/mozilla/embedding/components/windowwatcher/src/nsWindowWatcher.cpp index d4a067dddca..1b85832fe2d 100644 --- a/mozilla/embedding/components/windowwatcher/src/nsWindowWatcher.cpp +++ b/mozilla/embedding/components/windowwatcher/src/nsWindowWatcher.cpp @@ -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) diff --git a/mozilla/uriloader/exthandler/Makefile.in b/mozilla/uriloader/exthandler/Makefile.in index d26c2e62f5d..81f79edb182 100644 --- a/mozilla/uriloader/exthandler/Makefile.in +++ b/mozilla/uriloader/exthandler/Makefile.in @@ -79,6 +79,7 @@ REQUIRES = xpcom \ docshell \ windowwatcher \ embed_base \ + dom \ $(NULL) ifdef MOZ_PHOENIX diff --git a/mozilla/uriloader/exthandler/nsExternalHelperAppService.cpp b/mozilla/uriloader/exthandler/nsExternalHelperAppService.cpp index 9e6e223edcb..2187e224f5d 100644 --- a/mozilla/uriloader/exthandler/nsExternalHelperAppService.cpp +++ b/mozilla/uriloader/exthandler/nsExternalHelperAppService.cpp @@ -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 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 window(do_GetInterface(mWindowContext)); + nsCOMPtr 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; } - diff --git a/mozilla/uriloader/exthandler/nsExternalHelperAppService.h b/mozilla/uriloader/exthandler/nsExternalHelperAppService.h index 803fecb1db1..5d80eeb219e 100644 --- a/mozilla/uriloader/exthandler/nsExternalHelperAppService.h +++ b/mozilla/uriloader/exthandler/nsExternalHelperAppService.h @@ -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 mWebProgressListener; nsCOMPtr mOriginalChannel; /**< in the case of a redirect, this will be the pre-redirect channel. */ nsCOMPtr mDialog; diff --git a/mozilla/webshell/public/nsIRefreshURI.idl b/mozilla/webshell/public/nsIRefreshURI.idl index 01538a5aa88..c00a5298ddd 100644 --- a/mozilla/webshell/public/nsIRefreshURI.idl +++ b/mozilla/webshell/public/nsIRefreshURI.idl @@ -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) +%}