mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-18 15:55:36 +00:00
Bug 1574372 - Add support to nsDocumentOpenInfo for overriding some functionality that we want to modify in the parent. r=bzbarsky
Differential Revision: https://phabricator.services.mozilla.com/D56136 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
d1851fa263
commit
3f6ef264a3
@ -24,6 +24,7 @@
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsIThreadRetargetableStreamListener.h"
|
||||
#include "nsIChildChannel.h"
|
||||
#include "nsExternalHelperAppService.h"
|
||||
|
||||
#include "nsString.h"
|
||||
#include "nsThreadUtils.h"
|
||||
@ -77,6 +78,14 @@ nsDocumentOpenInfo::nsDocumentOpenInfo(nsIInterfaceRequestor* aWindowContext,
|
||||
mURILoader(aURILoader),
|
||||
mDataConversionDepthLimit(sConvertDataLimit) {}
|
||||
|
||||
nsDocumentOpenInfo::nsDocumentOpenInfo(uint32_t aFlags,
|
||||
bool aAllowListenerConversions)
|
||||
: m_originalContext(nullptr),
|
||||
mFlags(aFlags),
|
||||
mURILoader(nullptr),
|
||||
mDataConversionDepthLimit(sConvertDataLimit),
|
||||
mAllowListenerConversions(aAllowListenerConversions) {}
|
||||
|
||||
nsDocumentOpenInfo::~nsDocumentOpenInfo() {}
|
||||
|
||||
nsresult nsDocumentOpenInfo::Prepare() {
|
||||
@ -169,8 +178,8 @@ NS_IMETHODIMP nsDocumentOpenInfo::OnStartRequest(nsIRequest* request) {
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (NS_FAILED(status)) {
|
||||
LOG_ERROR(
|
||||
(" Request failed, status: 0x%08" PRIX32, static_cast<uint32_t>(rv)));
|
||||
LOG_ERROR((" Request failed, status: 0x%08" PRIX32,
|
||||
static_cast<uint32_t>(status)));
|
||||
|
||||
//
|
||||
// The transaction has already reported an error - so it will be torn
|
||||
@ -242,6 +251,7 @@ NS_IMETHODIMP nsDocumentOpenInfo::OnStopRequest(nsIRequest* request,
|
||||
mContentType.Truncate();
|
||||
listener->OnStopRequest(request, aStatus);
|
||||
}
|
||||
mUsedContentHandler = false;
|
||||
|
||||
// Remember...
|
||||
// In the case of multiplexed streams (such as multipart/x-mixed-replace)
|
||||
@ -300,7 +310,7 @@ nsresult nsDocumentOpenInfo::DispatchContent(nsIRequest* request,
|
||||
// First step: See whether m_contentListener wants to handle this
|
||||
// content type.
|
||||
//
|
||||
if (m_contentListener && TryContentListener(m_contentListener, aChannel)) {
|
||||
if (TryDefaultContentListener(aChannel)) {
|
||||
LOG((" Success! Our default listener likes this type"));
|
||||
// All done here
|
||||
return NS_OK;
|
||||
@ -313,7 +323,7 @@ nsresult nsDocumentOpenInfo::DispatchContent(nsIRequest* request,
|
||||
// Second step: See whether some other registered listener wants
|
||||
// to handle this content type.
|
||||
//
|
||||
int32_t count = mURILoader->m_listeners.Count();
|
||||
int32_t count = mURILoader ? mURILoader->m_listeners.Count() : 0;
|
||||
nsCOMPtr<nsIURIContentListener> listener;
|
||||
for (int32_t i = 0; i < count; i++) {
|
||||
listener = do_QueryReferent(mURILoader->m_listeners[i]);
|
||||
@ -364,6 +374,10 @@ nsresult nsDocumentOpenInfo::DispatchContent(nsIRequest* request,
|
||||
do_CreateInstance(handlerContractID.get());
|
||||
if (contentHandler) {
|
||||
LOG((" Content handler found"));
|
||||
// Note that m_originalContext can be nullptr when running this in
|
||||
// the parent process on behalf on a docshell in the content process,
|
||||
// and in that case we only support content handlers that don't need
|
||||
// the context.
|
||||
rv = contentHandler->HandleContent(mContentType.get(),
|
||||
m_originalContext, request);
|
||||
// XXXbz returning an error code to represent handling the
|
||||
@ -376,6 +390,7 @@ nsresult nsDocumentOpenInfo::DispatchContent(nsIRequest* request,
|
||||
request->Cancel(rv);
|
||||
} else {
|
||||
LOG((" Content handler taking over load"));
|
||||
mUsedContentHandler = true;
|
||||
}
|
||||
|
||||
return rv;
|
||||
@ -397,13 +412,7 @@ nsresult nsDocumentOpenInfo::DispatchContent(nsIRequest* request,
|
||||
// XXXbz have to be careful here; may end up in some sort of bizarre
|
||||
// infinite decoding loop.
|
||||
if (mContentType != anyType) {
|
||||
rv = ConvertData(request, m_contentListener, mContentType, anyType);
|
||||
if (NS_FAILED(rv)) {
|
||||
m_targetStreamListener = nullptr;
|
||||
} else if (m_targetStreamListener) {
|
||||
// We found a converter for this MIME type. We'll just pump data into
|
||||
// it and let the downstream nsDocumentOpenInfo handle things.
|
||||
LOG((" Converter taking over now"));
|
||||
if (TryStreamConversion(aChannel)) {
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
@ -455,10 +464,7 @@ nsresult nsDocumentOpenInfo::DispatchContent(nsIRequest* request,
|
||||
aChannel->SetContentType(NS_LITERAL_CSTRING(APPLICATION_GUESS_FROM_EXT));
|
||||
}
|
||||
|
||||
rv = helperAppService->DoContent(mContentType, request, m_originalContext,
|
||||
false, nullptr,
|
||||
getter_AddRefs(m_targetStreamListener));
|
||||
if (NS_FAILED(rv)) {
|
||||
if (!TryExternalHelperApp(helperAppService, aChannel)) {
|
||||
request->SetLoadFlags(loadFlags);
|
||||
m_targetStreamListener = nullptr;
|
||||
}
|
||||
@ -470,6 +476,14 @@ nsresult nsDocumentOpenInfo::DispatchContent(nsIRequest* request,
|
||||
return rv;
|
||||
}
|
||||
|
||||
bool nsDocumentOpenInfo::TryExternalHelperApp(
|
||||
nsIExternalHelperAppService* aHelperAppService, nsIChannel* aChannel) {
|
||||
nsresult rv = aHelperAppService->DoContent(
|
||||
mContentType, aChannel, m_originalContext, false, nullptr,
|
||||
getter_AddRefs(m_targetStreamListener));
|
||||
return NS_SUCCEEDED(rv);
|
||||
}
|
||||
|
||||
nsresult nsDocumentOpenInfo::ConvertData(nsIRequest* request,
|
||||
nsIURIContentListener* aListener,
|
||||
const nsACString& aSrcContentType,
|
||||
@ -479,9 +493,10 @@ nsresult nsDocumentOpenInfo::ConvertData(nsIRequest* request,
|
||||
PromiseFlatCString(aOutContentType).get()));
|
||||
|
||||
if (mDataConversionDepthLimit == 0) {
|
||||
LOG((
|
||||
"[0x%p] nsDocumentOpenInfo::ConvertData - reached the recursion limit!",
|
||||
this));
|
||||
LOG(
|
||||
("[0x%p] nsDocumentOpenInfo::ConvertData - reached the recursion "
|
||||
"limit!",
|
||||
this));
|
||||
// This will fall back to external helper app handling.
|
||||
return NS_ERROR_ABORT;
|
||||
}
|
||||
@ -505,16 +520,15 @@ nsresult nsDocumentOpenInfo::ConvertData(nsIRequest* request,
|
||||
// stream is split up into multiple destination streams. This
|
||||
// intermediate instance is used to target these "decoded" streams...
|
||||
//
|
||||
RefPtr<nsDocumentOpenInfo> nextLink =
|
||||
new nsDocumentOpenInfo(m_originalContext, mFlags, mURILoader);
|
||||
RefPtr<nsDocumentOpenInfo> nextLink = Clone();
|
||||
|
||||
LOG((" Downstream DocumentOpenInfo would be: 0x%p", nextLink.get()));
|
||||
|
||||
// Decrease the conversion recursion limit by one to prevent infinite loops.
|
||||
nextLink->mDataConversionDepthLimit = mDataConversionDepthLimit - 1;
|
||||
|
||||
// Make sure nextLink starts with the contentListener that said it wanted the
|
||||
// results of this decode.
|
||||
// Make sure nextLink starts with the contentListener that said it wanted
|
||||
// the results of this decode.
|
||||
nextLink->m_contentListener = aListener;
|
||||
// Also make sure it has to look for a stream listener to pump data into.
|
||||
nextLink->m_targetStreamListener = nullptr;
|
||||
@ -536,6 +550,20 @@ nsresult nsDocumentOpenInfo::ConvertData(nsIRequest* request,
|
||||
getter_AddRefs(m_targetStreamListener));
|
||||
}
|
||||
|
||||
bool nsDocumentOpenInfo::TryStreamConversion(nsIChannel* aChannel) {
|
||||
NS_NAMED_LITERAL_CSTRING(anyType, "*/*");
|
||||
nsresult rv = ConvertData(aChannel, m_contentListener, mContentType, anyType);
|
||||
if (NS_FAILED(rv)) {
|
||||
m_targetStreamListener = nullptr;
|
||||
} else if (m_targetStreamListener) {
|
||||
// We found a converter for this MIME type. We'll just pump data into
|
||||
// it and let the downstream nsDocumentOpenInfo handle things.
|
||||
LOG((" Converter taking over now"));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool nsDocumentOpenInfo::TryContentListener(nsIURIContentListener* aListener,
|
||||
nsIChannel* aChannel) {
|
||||
LOG(("[0x%p] nsDocumentOpenInfo::TryContentListener; mFlags = 0x%x", this,
|
||||
@ -563,7 +591,10 @@ bool nsDocumentOpenInfo::TryContentListener(nsIURIContentListener* aListener,
|
||||
if (!typeToUse.IsEmpty() && typeToUse != mContentType) {
|
||||
// Need to do a conversion here.
|
||||
|
||||
nsresult rv = ConvertData(aChannel, aListener, mContentType, typeToUse);
|
||||
nsresult rv = NS_ERROR_NOT_AVAILABLE;
|
||||
if (mAllowListenerConversions) {
|
||||
rv = ConvertData(aChannel, aListener, mContentType, typeToUse);
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
// No conversion path -- we don't want this listener, if we got one
|
||||
@ -625,6 +656,13 @@ bool nsDocumentOpenInfo::TryContentListener(nsIURIContentListener* aListener,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool nsDocumentOpenInfo::TryDefaultContentListener(nsIChannel* aChannel) {
|
||||
if (m_contentListener) {
|
||||
return TryContentListener(m_contentListener, aChannel);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of nsURILoader
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -680,8 +718,9 @@ NS_IMETHODIMP nsURILoader::OpenURI(nsIChannel* channel, uint32_t aFlags,
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
if (aFlags & nsIURILoader::REDIRECTED_CHANNEL) {
|
||||
// Our channel was redirected from another process, so doesn't need to be
|
||||
// opened again. However, it does need its listener hooked up correctly.
|
||||
// Our channel was redirected from another process, so doesn't need to
|
||||
// be opened again. However, it does need its listener hooked up
|
||||
// correctly.
|
||||
nsCOMPtr<nsIChildChannel> childChannel = do_QueryInterface(channel);
|
||||
MOZ_ASSERT(childChannel);
|
||||
if (!childChannel) {
|
||||
@ -726,7 +765,7 @@ nsresult nsURILoader::OpenChannel(nsIChannel* channel, uint32_t aFlags,
|
||||
LOG(("nsURILoader::OpenChannel for %s", spec.get()));
|
||||
}
|
||||
|
||||
// Let the window context's uriListener know that the open is starting. This
|
||||
// Let the window context's uriListener know that the open is starting. This
|
||||
// gives that window a chance to abort the load process.
|
||||
nsCOMPtr<nsIURIContentListener> winContextListener(
|
||||
do_GetInterface(aWindowContext));
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsIThreadRetargetableStreamListener.h"
|
||||
#include "nsIExternalHelperAppService.h"
|
||||
|
||||
#include "mozilla/Logging.h"
|
||||
|
||||
@ -62,13 +63,14 @@ class nsURILoader final : public nsIURILoader {
|
||||
* Each instance remains alive until its target URL has been loaded
|
||||
* (or aborted).
|
||||
*/
|
||||
class nsDocumentOpenInfo final : public nsIStreamListener,
|
||||
public nsIThreadRetargetableStreamListener {
|
||||
class nsDocumentOpenInfo : public nsIStreamListener,
|
||||
public nsIThreadRetargetableStreamListener {
|
||||
public:
|
||||
// Real constructor
|
||||
// aFlags is a combination of the flags on nsIURILoader
|
||||
nsDocumentOpenInfo(nsIInterfaceRequestor* aWindowContext, uint32_t aFlags,
|
||||
nsURILoader* aURILoader);
|
||||
nsDocumentOpenInfo(uint32_t aFlags, bool aAllowListenerConversions);
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
@ -99,6 +101,44 @@ class nsDocumentOpenInfo final : public nsIStreamListener,
|
||||
bool TryContentListener(nsIURIContentListener* aListener,
|
||||
nsIChannel* aChannel);
|
||||
|
||||
/**
|
||||
* Virtual helper functions for content that we expect to be
|
||||
* overriden when running in the parent process on behalf of
|
||||
* a content process docshell.
|
||||
* We also expect nsIStreamListener functions to be overriden
|
||||
* to add functionality.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Attempt to create a steam converter converting from the
|
||||
* current mContentType into something else.
|
||||
* Sets m_targetStreamListener if it succeeds.
|
||||
*/
|
||||
virtual bool TryStreamConversion(nsIChannel* aChannel);
|
||||
|
||||
/**
|
||||
* Attempt to use the default content listener as our stream
|
||||
* listener.
|
||||
* Sets m_targetStreamListener if it succeeds.
|
||||
*/
|
||||
virtual bool TryDefaultContentListener(nsIChannel* aChannel);
|
||||
|
||||
/**
|
||||
* Attempt to pass aChannel onto the external helper app service.
|
||||
* Sets m_targetStreamListener if it succeeds.
|
||||
*/
|
||||
virtual bool TryExternalHelperApp(
|
||||
nsIExternalHelperAppService* aHelperAppService, nsIChannel* aChannel);
|
||||
|
||||
/**
|
||||
* Create another nsDocumentOpenInfo like this one, so that we can chain
|
||||
* them together when we use a stream converter and don't know what the
|
||||
* converted content type is until the converter outputs OnStartRequest.
|
||||
*/
|
||||
virtual nsDocumentOpenInfo* Clone() {
|
||||
return new nsDocumentOpenInfo(m_originalContext, mFlags, mURILoader);
|
||||
}
|
||||
|
||||
// nsIRequestObserver methods:
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
|
||||
@ -107,13 +147,16 @@ class nsDocumentOpenInfo final : public nsIStreamListener,
|
||||
|
||||
// nsIThreadRetargetableStreamListener
|
||||
NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
|
||||
|
||||
protected:
|
||||
~nsDocumentOpenInfo();
|
||||
virtual ~nsDocumentOpenInfo();
|
||||
|
||||
protected:
|
||||
/**
|
||||
* The first content listener to try dispatching data to. Typically
|
||||
* the listener associated with the entity that originated the load.
|
||||
* This can be nullptr when running in the parent process for a content
|
||||
* process docshell.
|
||||
*/
|
||||
nsCOMPtr<nsIURIContentListener> m_contentListener;
|
||||
|
||||
@ -126,6 +169,8 @@ class nsDocumentOpenInfo final : public nsIStreamListener,
|
||||
/**
|
||||
* A pointer to the entity that originated the load. We depend on getting
|
||||
* things like nsIURIContentListeners, nsIDOMWindows, etc off of it.
|
||||
* This can be nullptr when running in the parent process for a content
|
||||
* process docshell.
|
||||
*/
|
||||
nsCOMPtr<nsIInterfaceRequestor> m_originalContext;
|
||||
|
||||
@ -145,6 +190,8 @@ class nsDocumentOpenInfo final : public nsIStreamListener,
|
||||
/**
|
||||
* Reference to the URILoader service so we can access its list of
|
||||
* nsIURIContentListeners.
|
||||
* This can be nullptr when running in the parent process for a content
|
||||
* process docshell.
|
||||
*/
|
||||
RefPtr<nsURILoader> mURILoader;
|
||||
|
||||
@ -152,6 +199,21 @@ class nsDocumentOpenInfo final : public nsIStreamListener,
|
||||
* Limit of data conversion depth to prevent infinite conversion loops
|
||||
*/
|
||||
uint32_t mDataConversionDepthLimit;
|
||||
|
||||
/**
|
||||
* Set to true if OnStartRequest handles the content using an
|
||||
* nsIContentHandler, and the content is consumed despite
|
||||
* m_targetStreamListener being nullptr.
|
||||
*/
|
||||
bool mUsedContentHandler = false;
|
||||
|
||||
/**
|
||||
* True if we allow nsIURIContentListeners to return a requested
|
||||
* input typeToUse, and attempt to create a matching stream converter.
|
||||
* This is false when running in the parent process for a content process
|
||||
* docshell
|
||||
*/
|
||||
bool mAllowListenerConversions = true;
|
||||
};
|
||||
|
||||
#endif /* nsURILoader_h__ */
|
||||
|
Loading…
Reference in New Issue
Block a user