michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=2 et sw=2 tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "mozilla/DebugOnly.h" michael@0: michael@0: #include "ExternalHelperAppParent.h" michael@0: #include "nsIContent.h" michael@0: #include "nsCExternalHandlerService.h" michael@0: #include "nsIExternalHelperAppService.h" michael@0: #include "mozilla/dom/ContentParent.h" michael@0: #include "mozilla/dom/Element.h" michael@0: #include "mozilla/dom/TabParent.h" michael@0: #include "nsIBrowserDOMWindow.h" michael@0: #include "nsStringStream.h" michael@0: #include "mozilla/ipc/URIUtils.h" michael@0: #include "nsNetUtil.h" michael@0: #include "nsIDocument.h" michael@0: #include "mozilla/net/ChannelDiverterParent.h" michael@0: michael@0: #include "mozilla/unused.h" michael@0: michael@0: using namespace mozilla::ipc; michael@0: michael@0: namespace mozilla { michael@0: namespace dom { michael@0: michael@0: NS_IMPL_ISUPPORTS_INHERITED(ExternalHelperAppParent, michael@0: nsHashPropertyBag, michael@0: nsIRequest, michael@0: nsIChannel, michael@0: nsIMultiPartChannel, michael@0: nsIResumableChannel, michael@0: nsIStreamListener) michael@0: michael@0: ExternalHelperAppParent::ExternalHelperAppParent( michael@0: const OptionalURIParams& uri, michael@0: const int64_t& aContentLength) michael@0: : mURI(DeserializeURI(uri)) michael@0: , mPending(false) michael@0: , mDiverted(false) michael@0: , mIPCClosed(false) michael@0: , mLoadFlags(0) michael@0: , mStatus(NS_OK) michael@0: , mContentLength(aContentLength) michael@0: { michael@0: } michael@0: michael@0: void michael@0: ExternalHelperAppParent::Init(ContentParent *parent, michael@0: const nsCString& aMimeContentType, michael@0: const nsCString& aContentDispositionHeader, michael@0: const uint32_t& aContentDispositionHint, michael@0: const nsString& aContentDispositionFilename, michael@0: const bool& aForceSave, michael@0: const OptionalURIParams& aReferrer, michael@0: PBrowserParent* aBrowser) michael@0: { michael@0: nsCOMPtr helperAppService = michael@0: do_GetService(NS_EXTERNALHELPERAPPSERVICE_CONTRACTID); michael@0: NS_ASSERTION(helperAppService, "No Helper App Service!"); michael@0: michael@0: nsCOMPtr referrer = DeserializeURI(aReferrer); michael@0: if (referrer) michael@0: SetPropertyAsInterface(NS_LITERAL_STRING("docshell.internalReferrer"), referrer); michael@0: michael@0: mContentDispositionHeader = aContentDispositionHeader; michael@0: if (!mContentDispositionHeader.IsEmpty()) { michael@0: NS_GetFilenameFromDisposition(mContentDispositionFilename, michael@0: mContentDispositionHeader, michael@0: mURI); michael@0: mContentDisposition = michael@0: NS_GetContentDispositionFromHeader(mContentDispositionHeader, this); michael@0: } michael@0: else { michael@0: mContentDisposition = aContentDispositionHint; michael@0: mContentDispositionFilename = aContentDispositionFilename; michael@0: } michael@0: michael@0: nsCOMPtr window; michael@0: if (aBrowser) { michael@0: TabParent* tabParent = static_cast(aBrowser); michael@0: if (tabParent->GetOwnerElement()) michael@0: window = do_QueryInterface(tabParent->GetOwnerElement()->OwnerDoc()->GetWindow()); michael@0: } michael@0: michael@0: helperAppService->DoContent(aMimeContentType, this, window, michael@0: aForceSave, getter_AddRefs(mListener)); michael@0: } michael@0: michael@0: void michael@0: ExternalHelperAppParent::ActorDestroy(ActorDestroyReason why) michael@0: { michael@0: mIPCClosed = true; michael@0: } michael@0: michael@0: void michael@0: ExternalHelperAppParent::Delete() michael@0: { michael@0: if (!mIPCClosed) { michael@0: unused << Send__delete__(this); michael@0: } michael@0: } michael@0: michael@0: bool michael@0: ExternalHelperAppParent::RecvOnStartRequest(const nsCString& entityID) michael@0: { michael@0: MOZ_ASSERT(!mDiverted, "child forwarding callbacks after request was diverted"); michael@0: michael@0: mEntityID = entityID; michael@0: mPending = true; michael@0: mStatus = mListener->OnStartRequest(this, nullptr); michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: ExternalHelperAppParent::RecvOnDataAvailable(const nsCString& data, michael@0: const uint64_t& offset, michael@0: const uint32_t& count) michael@0: { michael@0: if (NS_FAILED(mStatus)) michael@0: return true; michael@0: michael@0: MOZ_ASSERT(!mDiverted, "child forwarding callbacks after request was diverted"); michael@0: MOZ_ASSERT(mPending, "must be pending!"); michael@0: michael@0: nsCOMPtr stringStream; michael@0: DebugOnly rv = NS_NewByteInputStream(getter_AddRefs(stringStream), data.get(), count, NS_ASSIGNMENT_DEPEND); michael@0: NS_ASSERTION(NS_SUCCEEDED(rv), "failed to create dependent string!"); michael@0: mStatus = mListener->OnDataAvailable(this, nullptr, stringStream, offset, count); michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: ExternalHelperAppParent::RecvOnStopRequest(const nsresult& code) michael@0: { michael@0: MOZ_ASSERT(!mDiverted, "child forwarding callbacks after request was diverted"); michael@0: michael@0: mPending = false; michael@0: mListener->OnStopRequest(this, nullptr, michael@0: (NS_SUCCEEDED(code) && NS_FAILED(mStatus)) ? mStatus : code); michael@0: Delete(); michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: ExternalHelperAppParent::RecvDivertToParentUsing(PChannelDiverterParent* diverter) michael@0: { michael@0: MOZ_ASSERT(diverter); michael@0: auto p = static_cast(diverter); michael@0: p->DivertTo(this); michael@0: mDiverted = true; michael@0: unused << p->Send__delete__(p); michael@0: return true; michael@0: } michael@0: michael@0: // michael@0: // nsIStreamListener michael@0: // michael@0: michael@0: NS_IMETHODIMP michael@0: ExternalHelperAppParent::OnDataAvailable(nsIRequest *request, michael@0: nsISupports *ctx, michael@0: nsIInputStream *input, michael@0: uint64_t offset, michael@0: uint32_t count) michael@0: { michael@0: MOZ_ASSERT(mDiverted); michael@0: return mListener->OnDataAvailable(request, ctx, input, offset, count); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ExternalHelperAppParent::OnStartRequest(nsIRequest *request, nsISupports *ctx) michael@0: { michael@0: MOZ_ASSERT(mDiverted); michael@0: return mListener->OnStartRequest(request, ctx); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ExternalHelperAppParent::OnStopRequest(nsIRequest *request, michael@0: nsISupports *ctx, michael@0: nsresult status) michael@0: { michael@0: MOZ_ASSERT(mDiverted); michael@0: nsresult rv = mListener->OnStopRequest(request, ctx, status); michael@0: Delete(); michael@0: return rv; michael@0: } michael@0: michael@0: ExternalHelperAppParent::~ExternalHelperAppParent() michael@0: { michael@0: } michael@0: michael@0: // michael@0: // nsIRequest implementation... michael@0: // michael@0: michael@0: NS_IMETHODIMP michael@0: ExternalHelperAppParent::GetName(nsACString& aResult) michael@0: { michael@0: if (!mURI) { michael@0: aResult.Truncate(); michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: mURI->GetAsciiSpec(aResult); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ExternalHelperAppParent::IsPending(bool *aResult) michael@0: { michael@0: *aResult = mPending; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ExternalHelperAppParent::GetStatus(nsresult *aResult) michael@0: { michael@0: *aResult = mStatus; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ExternalHelperAppParent::Cancel(nsresult aStatus) michael@0: { michael@0: mStatus = aStatus; michael@0: unused << SendCancel(aStatus); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ExternalHelperAppParent::Suspend() michael@0: { michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ExternalHelperAppParent::Resume() michael@0: { michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: // michael@0: // nsIChannel implementation michael@0: // michael@0: michael@0: NS_IMETHODIMP michael@0: ExternalHelperAppParent::GetOriginalURI(nsIURI * *aURI) michael@0: { michael@0: NS_IF_ADDREF(*aURI = mURI); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ExternalHelperAppParent::SetOriginalURI(nsIURI *aURI) michael@0: { michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ExternalHelperAppParent::GetURI(nsIURI **aURI) michael@0: { michael@0: NS_IF_ADDREF(*aURI = mURI); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ExternalHelperAppParent::Open(nsIInputStream **aResult) michael@0: { michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ExternalHelperAppParent::AsyncOpen(nsIStreamListener *aListener, michael@0: nsISupports *aContext) michael@0: { michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: ExternalHelperAppParent::GetLoadFlags(nsLoadFlags *aLoadFlags) michael@0: { michael@0: *aLoadFlags = mLoadFlags; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ExternalHelperAppParent::SetLoadFlags(nsLoadFlags aLoadFlags) michael@0: { michael@0: mLoadFlags = aLoadFlags; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ExternalHelperAppParent::GetLoadGroup(nsILoadGroup* *aLoadGroup) michael@0: { michael@0: *aLoadGroup = nullptr; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ExternalHelperAppParent::SetLoadGroup(nsILoadGroup* aLoadGroup) michael@0: { michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ExternalHelperAppParent::GetOwner(nsISupports* *aOwner) michael@0: { michael@0: *aOwner = nullptr; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ExternalHelperAppParent::SetOwner(nsISupports* aOwner) michael@0: { michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ExternalHelperAppParent::GetNotificationCallbacks(nsIInterfaceRequestor* *aCallbacks) michael@0: { michael@0: *aCallbacks = nullptr; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ExternalHelperAppParent::SetNotificationCallbacks(nsIInterfaceRequestor* aCallbacks) michael@0: { michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ExternalHelperAppParent::GetSecurityInfo(nsISupports * *aSecurityInfo) michael@0: { michael@0: *aSecurityInfo = nullptr; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ExternalHelperAppParent::GetContentType(nsACString& aContentType) michael@0: { michael@0: aContentType.Truncate(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ExternalHelperAppParent::SetContentType(const nsACString& aContentType) michael@0: { michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ExternalHelperAppParent::GetContentCharset(nsACString& aContentCharset) michael@0: { michael@0: aContentCharset.Truncate(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ExternalHelperAppParent::SetContentCharset(const nsACString& aContentCharset) michael@0: { michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ExternalHelperAppParent::GetContentDisposition(uint32_t *aContentDisposition) michael@0: { michael@0: if (mContentDispositionHeader.IsEmpty()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: *aContentDisposition = mContentDisposition; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ExternalHelperAppParent::SetContentDisposition(uint32_t aContentDisposition) michael@0: { michael@0: mContentDisposition = aContentDisposition; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ExternalHelperAppParent::GetContentDispositionFilename(nsAString& aContentDispositionFilename) michael@0: { michael@0: if (mContentDispositionFilename.IsEmpty()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: aContentDispositionFilename = mContentDispositionFilename; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ExternalHelperAppParent::SetContentDispositionFilename(const nsAString& aContentDispositionFilename) michael@0: { michael@0: mContentDispositionFilename = aContentDispositionFilename; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ExternalHelperAppParent::GetContentDispositionHeader(nsACString& aContentDispositionHeader) michael@0: { michael@0: if (mContentDispositionHeader.IsEmpty()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: aContentDispositionHeader = mContentDispositionHeader; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ExternalHelperAppParent::GetContentLength(int64_t *aContentLength) michael@0: { michael@0: if (mContentLength < 0) michael@0: *aContentLength = -1; michael@0: else michael@0: *aContentLength = mContentLength; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ExternalHelperAppParent::SetContentLength(int64_t aContentLength) michael@0: { michael@0: mContentLength = aContentLength; michael@0: return NS_OK; michael@0: } michael@0: michael@0: // michael@0: // nsIResumableChannel implementation michael@0: // michael@0: michael@0: NS_IMETHODIMP michael@0: ExternalHelperAppParent::ResumeAt(uint64_t startPos, const nsACString& entityID) michael@0: { michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ExternalHelperAppParent::GetEntityID(nsACString& aEntityID) michael@0: { michael@0: aEntityID = mEntityID; michael@0: return NS_OK; michael@0: } michael@0: michael@0: // michael@0: // nsIMultiPartChannel implementation michael@0: // michael@0: michael@0: NS_IMETHODIMP michael@0: ExternalHelperAppParent::GetBaseChannel(nsIChannel* *aChannel) michael@0: { michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ExternalHelperAppParent::GetPartID(uint32_t* aPartID) michael@0: { michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ExternalHelperAppParent::GetIsLastPart(bool* aIsLastPart) michael@0: { michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: } // namespace dom michael@0: } // namespace mozilla