Bug 1478171 - [1.0] Forward channel redirect to nsILoadURIDelegate to allow external handling. r=smaug,snorp

This commit is contained in:
Dylan Roeh 2018-08-21 12:52:39 -05:00
Родитель d3673a24f2
Коммит ee984e1e49
2 изменённых файлов: 106 добавлений и 0 удалений

Просмотреть файл

@ -52,6 +52,13 @@ interface nsIChannelEventSink : nsISupports
*/
const unsigned long REDIRECT_STS_UPGRADE = 1 << 3;
/**
* This redirect has already been presented to the nsILoadURIDelegate
* for possible handling; if this flag is set we may safely skip checking
* if the nsILoadURIDelegate will handle the redirect.
*/
const unsigned long REDIRECT_DELEGATES_CHECKED = 1 << 4;
/**
* Called when a redirect occurs. This may happen due to an HTTP 3xx status
* code. The purpose of this method is to notify the sink that a redirect

Просмотреть файл

@ -6,6 +6,8 @@
#include "nspr.h"
#include "mozilla/Logging.h"
#include "mozilla/IntegerPrintfMacros.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/PromiseNativeHandler.h"
#include "nsDocLoader.h"
#include "nsCURILoader.h"
@ -34,6 +36,8 @@
#include "nsIDocument.h"
#include "nsPresContext.h"
#include "nsIAsyncVerifyRedirectCallback.h"
#include "nsILoadURIDelegate.h"
#include "nsIBrowserDOMWindow.h"
using mozilla::DebugOnly;
using mozilla::LogLevel;
@ -1421,11 +1425,106 @@ int64_t nsDocLoader::CalculateMaxProgress()
return max;
}
class LoadURIDelegateRedirectHandler final : public mozilla::dom::PromiseNativeHandler
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS(LoadURIDelegateRedirectHandler)
LoadURIDelegateRedirectHandler(nsDocLoader* aDocLoader,
nsIChannel* aOldChannel,
nsIChannel* aNewChannel,
uint32_t aFlags,
nsIAsyncVerifyRedirectCallback* aCallback)
: mDocLoader(aDocLoader)
, mOldChannel(aOldChannel)
, mNewChannel(aNewChannel)
, mFlags(aFlags)
, mCallback(aCallback)
{}
void
ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
{
if (aValue.isBoolean() && aValue.toBoolean()) {
// The app handled the redirect, notify the callback
mCallback->OnRedirectVerifyCallback(NS_ERROR_ABORT);
} else {
UnhandledCallback();
}
}
void
RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
{
UnhandledCallback();
}
private:
~LoadURIDelegateRedirectHandler()
{}
void UnhandledCallback()
{
// If the redirect wasn't handled by the nsILoadURIDelegate, let Gecko
// handle it.
mFlags |= nsIChannelEventSink::REDIRECT_DELEGATES_CHECKED;
mDocLoader->AsyncOnChannelRedirect(mOldChannel, mNewChannel, mFlags,
mCallback);
}
RefPtr<nsDocLoader> mDocLoader;
nsCOMPtr<nsIChannel> mOldChannel;
nsCOMPtr<nsIChannel> mNewChannel;
uint32_t mFlags;
nsCOMPtr<nsIAsyncVerifyRedirectCallback> mCallback;
};
NS_IMPL_CYCLE_COLLECTION(LoadURIDelegateRedirectHandler, mDocLoader,
mOldChannel, mNewChannel, mCallback)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(LoadURIDelegateRedirectHandler)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(LoadURIDelegateRedirectHandler)
NS_IMPL_CYCLE_COLLECTING_RELEASE(LoadURIDelegateRedirectHandler)
NS_IMETHODIMP nsDocLoader::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
nsIChannel *aNewChannel,
uint32_t aFlags,
nsIAsyncVerifyRedirectCallback *cb)
{
if ((aFlags &
(nsIChannelEventSink::REDIRECT_TEMPORARY |
nsIChannelEventSink::REDIRECT_PERMANENT)) &&
!(aFlags & nsIChannelEventSink::REDIRECT_DELEGATES_CHECKED)) {
nsCOMPtr<nsIDocShell> docShell =
do_QueryInterface(static_cast<nsIRequestObserver*>(this));
nsCOMPtr<nsILoadURIDelegate> delegate;
docShell->GetLoadURIDelegate(getter_AddRefs(delegate));
nsCOMPtr<nsIURI> newURI;
aNewChannel->GetURI(getter_AddRefs(newURI));
if (newURI && delegate) {
RefPtr<mozilla::dom::Promise> promise;
const int where = nsIBrowserDOMWindow::OPEN_CURRENTWINDOW;
nsresult rv = delegate->LoadURI(newURI, where, /* flags */ 0,
/* triggering principal */ nullptr,
getter_AddRefs(promise));
if (NS_SUCCEEDED(rv) && promise) {
RefPtr<LoadURIDelegateRedirectHandler> handler =
new LoadURIDelegateRedirectHandler(this, aOldChannel, aNewChannel,
aFlags, cb);
promise->AppendNativeHandler(handler);
return NS_OK;
}
}
}
if (aOldChannel)
{
nsLoadFlags loadFlags = 0;