Bug 1350058 - Update the content context if we close the downloading window. r=mconley
MozReview-Commit-ID: A5LsapsljMY
--- a/uriloader/exthandler/ExternalHelperAppChild.cpp
+++ b/uriloader/exthandler/ExternalHelperAppChild.cpp
@@ -1,16 +1,17 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ExternalHelperAppChild.h"
#include "mozilla/net/ChannelDiverterChild.h"
+#include "mozilla/dom/TabChild.h"
#include "nsIDivertableChannel.h"
#include "nsIInputStream.h"
#include "nsIFTPChannel.h"
#include "nsIRequest.h"
#include "nsIResumableChannel.h"
#include "nsNetUtil.h"
namespace mozilla {
@@ -58,27 +59,35 @@ ExternalHelperAppChild::OnDataAvailable(
//////////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP
ExternalHelperAppChild::OnStartRequest(nsIRequest *request, nsISupports *ctx)
{
nsresult rv = mHandler->OnStartRequest(request, ctx);
NS_ENSURE_SUCCESS(rv, NS_ERROR_UNEXPECTED);
+ // Calling OnStartRequest could cause mHandler to close the window it was
+ // loaded for. In that case, the TabParent in the parent context might then
+ // point to the wrong window. Re-send the window context along with either
+ // DivertToParent or SendOnStartRequest just in case.
+ nsCOMPtr<nsPIDOMWindowOuter> window =
+ do_GetInterface(mHandler->GetDialogParent());
+ TabChild *tabChild = window ? mozilla::dom::TabChild::GetFrom(window) : nullptr;
+
nsCOMPtr<nsIDivertableChannel> divertable = do_QueryInterface(request);
if (divertable) {
- return DivertToParent(divertable, request);
+ return DivertToParent(divertable, request, tabChild);
}
nsCString entityID;
nsCOMPtr<nsIResumableChannel> resumable(do_QueryInterface(request));
if (resumable) {
resumable->GetEntityID(entityID);
}
- SendOnStartRequest(entityID);
+ SendOnStartRequest(entityID, tabChild);
return NS_OK;
}
NS_IMETHODIMP
ExternalHelperAppChild::OnStopRequest(nsIRequest *request,
nsISupports *ctx,
nsresult status)
{
@@ -89,30 +98,31 @@ ExternalHelperAppChild::OnStopRequest(ns
NS_ENSURE_SUCCESS(rv, NS_ERROR_UNEXPECTED);
}
return NS_OK;
}
nsresult
ExternalHelperAppChild::DivertToParent(nsIDivertableChannel *divertable,
- nsIRequest *request)
+ nsIRequest *request,
+ TabChild *tabChild)
{
// nsIDivertable must know about content conversions before being diverted.
MOZ_ASSERT(mHandler);
mHandler->MaybeApplyDecodingForExtension(request);
mozilla::net::ChannelDiverterChild *diverter = nullptr;
nsresult rv = divertable->DivertToParent(&diverter);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
MOZ_ASSERT(diverter);
- if (SendDivertToParentUsing(diverter)) {
+ if (SendDivertToParentUsing(diverter, tabChild)) {
mHandler->DidDivertRequest(request);
mHandler = nullptr;
return NS_OK;
}
return NS_ERROR_FAILURE;
}
--- a/uriloader/exthandler/ExternalHelperAppChild.h
+++ b/uriloader/exthandler/ExternalHelperAppChild.h
@@ -11,16 +11,18 @@
#include "nsExternalHelperAppService.h"
#include "nsIStreamListener.h"
class nsIDivertableChannel;
namespace mozilla {
namespace dom {
+class TabChild;
+
class ExternalHelperAppChild : public PExternalHelperAppChild
, public nsIStreamListener
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSIREQUESTOBSERVER
@@ -28,17 +30,19 @@ public:
// Give the listener a real nsExternalAppHandler to complete processing on
// the child.
void SetHandler(nsExternalAppHandler *handler) { mHandler = handler; }
virtual mozilla::ipc::IPCResult RecvCancel(const nsresult& aStatus) override;
private:
virtual ~ExternalHelperAppChild();
- MOZ_MUST_USE nsresult DivertToParent(nsIDivertableChannel *divertable, nsIRequest *request);
+ MOZ_MUST_USE nsresult DivertToParent(nsIDivertableChannel *divertable,
+ nsIRequest *request,
+ TabChild *tabChild);
RefPtr<nsExternalAppHandler> mHandler;
nsresult mStatus;
};
} // namespace dom
} // namespace mozilla
--- a/uriloader/exthandler/ExternalHelperAppParent.cpp
+++ b/uriloader/exthandler/ExternalHelperAppParent.cpp
@@ -49,16 +49,40 @@ ExternalHelperAppParent::ExternalHelperA
, mIPCClosed(false)
, mLoadFlags(0)
, mStatus(NS_OK)
, mContentLength(aContentLength)
, mWasFileChannel(aWasFileChannel)
{
}
+already_AddRefed<nsIInterfaceRequestor>
+GetWindowFromTabParent(PBrowserParent* aBrowser)
+{
+ if (!aBrowser) {
+ return nullptr;
+ }
+
+ nsCOMPtr<nsIInterfaceRequestor> window;
+ TabParent* tabParent = TabParent::GetFrom(aBrowser);
+ if (tabParent->GetOwnerElement()) {
+ window = do_QueryInterface(tabParent->GetOwnerElement()->OwnerDoc()->GetWindow());
+ }
+
+ return window.forget();
+}
+
+void
+UpdateContentContext(nsIStreamListener* aListener, PBrowserParent* aBrowser)
+{
+ MOZ_ASSERT(aListener);
+ nsCOMPtr<nsIInterfaceRequestor> window = GetWindowFromTabParent(aBrowser);
+ static_cast<nsExternalAppHandler *>(aListener)->SetContentContext(window);
+}
+
void
ExternalHelperAppParent::Init(ContentParent *parent,
const nsCString& aMimeContentType,
const nsCString& aContentDispositionHeader,
const uint32_t& aContentDispositionHint,
const nsString& aContentDispositionFilename,
const bool& aForceSave,
const OptionalURIParams& aReferrer,
@@ -112,20 +136,23 @@ void
ExternalHelperAppParent::Delete()
{
if (!mIPCClosed) {
Unused << Send__delete__(this);
}
}
mozilla::ipc::IPCResult
-ExternalHelperAppParent::RecvOnStartRequest(const nsCString& entityID)
+ExternalHelperAppParent::RecvOnStartRequest(const nsCString& entityID,
+ PBrowserParent* contentContext)
{
MOZ_ASSERT(!mDiverted, "child forwarding callbacks after request was diverted");
+ UpdateContentContext(mListener, contentContext);
+
mEntityID = entityID;
mPending = true;
mStatus = mListener->OnStartRequest(this, nullptr);
return IPC_OK();
}
mozilla::ipc::IPCResult
ExternalHelperAppParent::RecvOnDataAvailable(const nsCString& data,
@@ -154,19 +181,21 @@ ExternalHelperAppParent::RecvOnStopReque
mPending = false;
mListener->OnStopRequest(this, nullptr,
(NS_SUCCEEDED(code) && NS_FAILED(mStatus)) ? mStatus : code);
Delete();
return IPC_OK();
}
mozilla::ipc::IPCResult
-ExternalHelperAppParent::RecvDivertToParentUsing(PChannelDiverterParent* diverter)
+ExternalHelperAppParent::RecvDivertToParentUsing(PChannelDiverterParent* diverter,
+ PBrowserParent* contentContext)
{
MOZ_ASSERT(diverter);
+ UpdateContentContext(mListener, contentContext);
auto p = static_cast<mozilla::net::ChannelDiverterParent*>(diverter);
p->DivertTo(this);
#ifdef DEBUG
mDiverted = true;
#endif
Unused << p->Send__delete__(p);
return IPC_OK();
}
--- a/uriloader/exthandler/ExternalHelperAppParent.h
+++ b/uriloader/exthandler/ExternalHelperAppParent.h
@@ -63,23 +63,25 @@ public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIREQUEST
NS_DECL_NSICHANNEL
NS_DECL_NSIMULTIPARTCHANNEL
NS_DECL_NSIRESUMABLECHANNEL
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSIREQUESTOBSERVER
- mozilla::ipc::IPCResult RecvOnStartRequest(const nsCString& entityID) override;
+ mozilla::ipc::IPCResult RecvOnStartRequest(const nsCString& entityID,
+ PBrowserParent* aBrowser) override;
mozilla::ipc::IPCResult RecvOnDataAvailable(const nsCString& data,
const uint64_t& offset,
const uint32_t& count) override;
mozilla::ipc::IPCResult RecvOnStopRequest(const nsresult& code) override;
- mozilla::ipc::IPCResult RecvDivertToParentUsing(PChannelDiverterParent* diverter) override;
+ mozilla::ipc::IPCResult RecvDivertToParentUsing(PChannelDiverterParent* diverter,
+ PBrowserParent* aBrowser) override;
bool WasFileChannel() override {
return mWasFileChannel;
}
ExternalHelperAppParent(const OptionalURIParams& uri, const int64_t& contentLength,
const bool& wasFileChannel);
void Init(ContentParent *parent,
--- a/uriloader/exthandler/PExternalHelperApp.ipdl
+++ b/uriloader/exthandler/PExternalHelperApp.ipdl
@@ -1,28 +1,30 @@
+/* vim: set ft=cpp: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+include protocol PBrowser;
include protocol PContent;
include protocol PChannelDiverter;
namespace mozilla {
namespace dom {
protocol PExternalHelperApp
{
manager PContent;
parent:
- async OnStartRequest(nsCString entityID);
+ async OnStartRequest(nsCString entityID, PBrowser windowContext);
async OnDataAvailable(nsCString data, uint64_t offset, uint32_t count);
async OnStopRequest(nsresult code);
- async DivertToParentUsing(PChannelDiverter diverter);
+ async DivertToParentUsing(PChannelDiverter diverter, PBrowser windowContext);
child:
async Cancel(nsresult aStatus);
async __delete__();
};
} // namespace dom
--- a/uriloader/exthandler/nsExternalHelperAppService.cpp
+++ b/uriloader/exthandler/nsExternalHelperAppService.cpp
@@ -835,16 +835,18 @@ NS_IMETHODIMP nsExternalHelperAppService
}
*aStreamListener = nullptr;
// We want the mimeInfo's primary extension to pass it to
// nsExternalAppHandler
nsAutoCString buf;
mimeInfo->GetPrimaryExtension(buf);
+ // NB: ExternalHelperAppParent depends on this listener always being an
+ // nsExternalAppHandler. If this changes, make sure to update that code.
nsExternalAppHandler * handler = new nsExternalAppHandler(mimeInfo,
buf,
aContentContext,
aWindowContext,
this,
fileName,
reason,
aForceSave);
--- a/uriloader/exthandler/nsExternalHelperAppService.h
+++ b/uriloader/exthandler/nsExternalHelperAppService.h
@@ -240,23 +240,31 @@ public:
*/
void DidDivertRequest(nsIRequest *request);
/**
* Apply content conversions if needed.
*/
void MaybeApplyDecodingForExtension(nsIRequest *request);
-protected:
- ~nsExternalAppHandler();
-
+ /**
+ * Get the dialog parent. Public for ExternalHelperAppChild::OnStartRequest.
+ */
nsIInterfaceRequestor* GetDialogParent() {
return mWindowContext ? mWindowContext : mContentContext;
}
+ void SetContentContext(nsIInterfaceRequestor* context) {
+ MOZ_ASSERT(!mWindowContext);
+ mContentContext = context;
+ }
+
+protected:
+ ~nsExternalAppHandler();
+
nsCOMPtr<nsIFile> mTempFile;
nsCOMPtr<nsIURI> mSourceUrl;
nsString mTempFileExtension;
nsString mTempLeafName;
/**
* The MIME Info for this load. Will never be null.
*/