summaryrefslogtreecommitdiff
path: root/mozilla-890908-async-nego.patch
diff options
context:
space:
mode:
Diffstat (limited to 'mozilla-890908-async-nego.patch')
-rw-r--r--mozilla-890908-async-nego.patch757
1 files changed, 757 insertions, 0 deletions
diff --git a/mozilla-890908-async-nego.patch b/mozilla-890908-async-nego.patch
new file mode 100644
index 0000000..9a8ec77
--- /dev/null
+++ b/mozilla-890908-async-nego.patch
@@ -0,0 +1,757 @@
+diff -up firefox-48.0/extensions/auth/nsHttpNegotiateAuth.cpp.890908-async-nego firefox-48.0/extensions/auth/nsHttpNegotiateAuth.cpp
+--- firefox-48.0/extensions/auth/nsHttpNegotiateAuth.cpp.890908-async-nego 2016-07-25 22:22:05.000000000 +0200
++++ firefox-48.0/extensions/auth/nsHttpNegotiateAuth.cpp 2016-07-27 09:56:55.652261702 +0200
+@@ -40,6 +40,10 @@
+ #include "mozilla/Snprintf.h"
+ #include "nsIChannel.h"
+ #include "nsNetUtil.h"
++#include "nsThreadUtils.h"
++#include "nsIHttpAuthenticatorCallback.h"
++#include "mozilla/Mutex.h"
++#include "nsICancelable.h"
+
+ //-----------------------------------------------------------------------------
+
+@@ -51,6 +55,7 @@ static const char kNegotiateAuthAllowNon
+ static const char kNegotiateAuthSSPI[] = "network.auth.use-sspi";
+
+ #define kNegotiateLen (sizeof(kNegotiate)-1)
++#define DEFAULT_THREAD_TIMEOUT_MS 30000
+
+ //-----------------------------------------------------------------------------
+
+@@ -184,7 +189,260 @@ nsHttpNegotiateAuth::ChallengeReceived(n
+ }
+
+ NS_IMPL_ISUPPORTS(nsHttpNegotiateAuth, nsIHttpAuthenticator)
+-
++
++namespace {
++
++//
++// GetNextTokenCompleteEvent
++//
++// This event is fired on main thread when async call of
++// nsHttpNegotiateAuth::GenerateCredentials is finished. During the Run()
++// method the nsIHttpAuthenticatorCallback::OnCredsAvailable is called with
++// obtained credentials, flags and NS_OK when successful, otherwise
++// NS_ERROR_FAILURE is returned as a result of failed operation.
++//
++class GetNextTokenCompleteEvent final : public nsIRunnable,
++ public nsICancelable
++{
++ virtual ~GetNextTokenCompleteEvent()
++ {
++ if (mCreds) {
++ free(mCreds);
++ }
++ };
++
++public:
++ NS_DECL_THREADSAFE_ISUPPORTS
++
++ explicit GetNextTokenCompleteEvent(nsIHttpAuthenticatorCallback* aCallback)
++ : mCallback(aCallback)
++ , mCreds(nullptr)
++ , mCancelled(false)
++ {
++ }
++
++ NS_IMETHODIMP DispatchSuccess(char *aCreds,
++ uint32_t aFlags,
++ already_AddRefed<nsISupports> aSessionState,
++ already_AddRefed<nsISupports> aContinuationState)
++ {
++ // Called from worker thread
++ MOZ_ASSERT(!NS_IsMainThread());
++
++ mCreds = aCreds;
++ mFlags = aFlags;
++ mResult = NS_OK;
++ mSessionState = aSessionState;
++ mContinuationState = aContinuationState;
++ return NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL);
++ }
++
++ NS_IMETHODIMP DispatchError(already_AddRefed<nsISupports> aSessionState,
++ already_AddRefed<nsISupports> aContinuationState)
++ {
++ // Called from worker thread
++ MOZ_ASSERT(!NS_IsMainThread());
++
++ mResult = NS_ERROR_FAILURE;
++ mSessionState = aSessionState;
++ mContinuationState = aContinuationState;
++ return NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL);
++ }
++
++ NS_IMETHODIMP Run() override
++ {
++ // Runs on main thread
++ MOZ_ASSERT(NS_IsMainThread());
++
++ if (!mCancelled) {
++ nsCOMPtr<nsIHttpAuthenticatorCallback> callback;
++ callback.swap(mCallback);
++ callback->OnCredsGenerated(mCreds, mFlags, mResult, mSessionState, mContinuationState);
++ }
++ return NS_OK;
++ }
++
++ NS_IMETHODIMP Cancel(nsresult aReason) override
++ {
++ // Supposed to be called from main thread
++ MOZ_ASSERT(NS_IsMainThread());
++
++ mCancelled = true;
++ return NS_OK;
++ }
++
++private:
++ nsCOMPtr<nsIHttpAuthenticatorCallback> mCallback;
++ char *mCreds; // This class owns it, freed in destructor
++ uint32_t mFlags;
++ nsresult mResult;
++ bool mCancelled;
++ nsCOMPtr<nsISupports> mSessionState;
++ nsCOMPtr<nsISupports> mContinuationState;
++};
++
++NS_IMPL_ISUPPORTS(GetNextTokenCompleteEvent, nsIRunnable, nsICancelable)
++
++//
++// GetNextTokenRunnable
++//
++// This runnable is created by GenerateCredentialsAsync and it runs
++// in nsHttpNegotiateAuth::mNegotiateThread and calling GenerateCredentials.
++//
++class GetNextTokenRunnable final : public nsRunnable
++{
++ virtual ~GetNextTokenRunnable() {}
++ public:
++ GetNextTokenRunnable(nsIHttpAuthenticableChannel *authChannel,
++ const char *challenge,
++ bool isProxyAuth,
++ const char16_t *domain,
++ const char16_t *username,
++ const char16_t *password,
++ nsISupports *sessionState,
++ nsISupports *continuationState,
++ GetNextTokenCompleteEvent *aCompleteEvent
++ )
++ : mAuthChannel(authChannel)
++ , mChallenge(challenge)
++ , mIsProxyAuth(isProxyAuth)
++ , mDomain(domain)
++ , mUsername(username)
++ , mPassword(password)
++ , mSessionState(sessionState)
++ , mContinuationState(continuationState)
++ , mCompleteEvent(aCompleteEvent)
++ {
++ }
++
++ NS_IMETHODIMP Run() override
++ {
++ // Runs on worker thread
++ MOZ_ASSERT(!NS_IsMainThread());
++
++ char *creds;
++ uint32_t flags;
++ nsresult rv = ObtainCredentialsAndFlags(&creds, &flags);
++
++ // Passing session and continuation state this way to not touch
++ // referencing of the object that may not be thread safe.
++ // Not having a thread safe referencing doesn't mean the object
++ // cannot be used on multiple threads (one example is nsAuthSSPI.)
++ // This ensures state objects will be destroyed on the main thread
++ // when not changed by GenerateCredentials.
++ if (NS_FAILED(rv)) {
++ return mCompleteEvent->DispatchError(mSessionState.forget(),
++ mContinuationState.forget());
++ }
++
++ return mCompleteEvent->DispatchSuccess(creds, flags,
++ mSessionState.forget(),
++ mContinuationState.forget());
++ }
++
++ NS_IMETHODIMP ObtainCredentialsAndFlags(char **aCreds, uint32_t *aFlags)
++ {
++ nsresult rv;
++
++ // Use negotiate service to call GenerateCredentials outside of main thread
++ nsAutoCString contractId;
++ contractId.Assign(NS_HTTP_AUTHENTICATOR_CONTRACTID_PREFIX);
++ contractId.Append("negotiate");
++ nsCOMPtr<nsIHttpAuthenticator> authenticator =
++ do_GetService(contractId.get(), &rv);
++ NS_ENSURE_SUCCESS(rv, rv);
++
++ nsISupports *sessionState = mSessionState;
++ nsISupports *continuationState = mContinuationState;
++ // The continuationState is for the sake of completeness propagated
++ // to the caller (despite it is not changed in any GenerateCredentials
++ // implementation).
++ //
++ // The only implementation that use sessionState is the
++ // nsHttpDigestAuth::GenerateCredentials. Since there's no reason
++ // to implement nsHttpDigestAuth::GenerateCredentialsAsync
++ // because digest auth does not block the main thread, we won't
++ // propagate changes to sessionState to the caller because of
++ // the change is too complicated on the caller side.
++ //
++ // Should any of the session or continuation states change inside
++ // this method, they must be threadsafe.
++ rv = authenticator->GenerateCredentials(mAuthChannel,
++ mChallenge.get(),
++ mIsProxyAuth,
++ mDomain.get(),
++ mUsername.get(),
++ mPassword.get(),
++ &sessionState,
++ &continuationState,
++ aFlags,
++ aCreds);
++ if (mSessionState != sessionState) {
++ mSessionState = sessionState;
++ }
++ if (mContinuationState != continuationState) {
++ mContinuationState = continuationState;
++ }
++ return rv;
++ }
++ private:
++ nsCOMPtr<nsIHttpAuthenticableChannel> mAuthChannel;
++ nsCString mChallenge;
++ bool mIsProxyAuth;
++ nsString mDomain;
++ nsString mUsername;
++ nsString mPassword;
++ nsCOMPtr<nsISupports> mSessionState;
++ nsCOMPtr<nsISupports> mContinuationState;
++ RefPtr<GetNextTokenCompleteEvent> mCompleteEvent;
++};
++
++} // anonymous namespace
++
++NS_IMETHODIMP
++nsHttpNegotiateAuth::GenerateCredentialsAsync(nsIHttpAuthenticableChannel *authChannel,
++ nsIHttpAuthenticatorCallback* aCallback,
++ const char *challenge,
++ bool isProxyAuth,
++ const char16_t *domain,
++ const char16_t *username,
++ const char16_t *password,
++ nsISupports *sessionState,
++ nsISupports *continuationState,
++ nsICancelable **aCancelable)
++{
++ NS_ENSURE_ARG(aCallback);
++ NS_ENSURE_ARG_POINTER(aCancelable);
++
++ RefPtr<GetNextTokenCompleteEvent> cancelEvent =
++ new GetNextTokenCompleteEvent(aCallback);
++
++
++ nsCOMPtr<nsIRunnable> getNextTokenRunnable =
++ new GetNextTokenRunnable(authChannel,
++ challenge,
++ isProxyAuth,
++ domain,
++ username,
++ password,
++ sessionState,
++ continuationState,
++ cancelEvent);
++ cancelEvent.forget(aCancelable);
++
++ nsresult rv;
++ if (!mNegotiateThread) {
++ mNegotiateThread =
++ new mozilla::LazyIdleThread(DEFAULT_THREAD_TIMEOUT_MS,
++ NS_LITERAL_CSTRING("NegotiateAuth"));
++ NS_ENSURE_TRUE(mNegotiateThread, NS_ERROR_OUT_OF_MEMORY);
++ }
++ rv = mNegotiateThread->Dispatch(getNextTokenRunnable, NS_DISPATCH_NORMAL);
++ NS_ENSURE_SUCCESS(rv, rv);
++
++ return NS_OK;
++}
++
+ //
+ // GenerateCredentials
+ //
+diff -up firefox-48.0/extensions/auth/nsHttpNegotiateAuth.h.890908-async-nego firefox-48.0/extensions/auth/nsHttpNegotiateAuth.h
+--- firefox-48.0/extensions/auth/nsHttpNegotiateAuth.h.890908-async-nego 2016-05-12 19:13:34.000000000 +0200
++++ firefox-48.0/extensions/auth/nsHttpNegotiateAuth.h 2016-07-27 09:56:55.652261702 +0200
+@@ -10,6 +10,7 @@
+ #include "nsIURI.h"
+ #include "nsSubstring.h"
+ #include "mozilla/Attributes.h"
++#include "mozilla/LazyIdleThread.h"
+
+ // The nsHttpNegotiateAuth class provides responses for the GSS-API Negotiate method
+ // as specified by Microsoft in draft-brezak-spnego-http-04.txt
+@@ -17,7 +18,7 @@
+ class nsHttpNegotiateAuth final : public nsIHttpAuthenticator
+ {
+ public:
+- NS_DECL_ISUPPORTS
++ NS_DECL_THREADSAFE_ISUPPORTS
+ NS_DECL_NSIHTTPAUTHENTICATOR
+
+ private:
+@@ -37,5 +38,7 @@ private:
+ int32_t port,
+ const char *baseStart,
+ const char *baseEnd);
++ // Thread for GenerateCredentialsAsync
++ RefPtr<mozilla::LazyIdleThread> mNegotiateThread;
+ };
+ #endif /* nsHttpNegotiateAuth_h__ */
+diff -up firefox-48.0/netwerk/base/moz.build.890908-async-nego firefox-48.0/netwerk/base/moz.build
+--- firefox-48.0/netwerk/base/moz.build.890908-async-nego 2016-07-25 22:22:05.000000000 +0200
++++ firefox-48.0/netwerk/base/moz.build 2016-07-27 09:56:55.653261702 +0200
+@@ -48,6 +48,7 @@ XPIDL_SOURCES += [
+ 'nsIFileURL.idl',
+ 'nsIForcePendingChannel.idl',
+ 'nsIFormPOSTActionChannel.idl',
++ 'nsIHttpAuthenticatorCallback.idl',
+ 'nsIHttpPushListener.idl',
+ 'nsIIncrementalDownload.idl',
+ 'nsIIncrementalStreamLoader.idl',
+diff -up firefox-48.0/netwerk/base/nsIHttpAuthenticatorCallback.idl.890908-async-nego firefox-48.0/netwerk/base/nsIHttpAuthenticatorCallback.idl
+--- firefox-48.0/netwerk/base/nsIHttpAuthenticatorCallback.idl.890908-async-nego 2016-07-27 09:56:55.653261702 +0200
++++ firefox-48.0/netwerk/base/nsIHttpAuthenticatorCallback.idl 2016-07-27 09:56:55.653261702 +0200
+@@ -0,0 +1,31 @@
++/* 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 "nsISupports.idl"
++
++[scriptable, uuid(d989cb03-e446-4086-b9e6-46842cb97bd5)]
++interface nsIHttpAuthenticatorCallback : nsISupports
++{
++ /**
++ * Authentication data for a header is available.
++ *
++ * @param aCreds
++ * Credentials which were obtained asynchonously.
++ * @param aFlags
++ * Flags set by asynchronous call.
++ * @param aResult
++ * Result status of credentials generation
++ * @param aSessionState
++ * Modified session state to be passed to caller
++ * @param aContinuationState
++ * Modified continuation state to be passed to caller
++ */
++ void onCredsGenerated(in string aCreds,
++ in unsigned long aFlags,
++ in nsresult aResult,
++ in nsISupports aSessionsState,
++ in nsISupports aContinuationState);
++
++};
++
+diff -up firefox-48.0/netwerk/protocol/http/nsHttpBasicAuth.cpp.890908-async-nego firefox-48.0/netwerk/protocol/http/nsHttpBasicAuth.cpp
+--- firefox-48.0/netwerk/protocol/http/nsHttpBasicAuth.cpp.890908-async-nego 2016-05-12 19:13:28.000000000 +0200
++++ firefox-48.0/netwerk/protocol/http/nsHttpBasicAuth.cpp 2016-07-27 09:56:55.653261702 +0200
+@@ -49,6 +49,20 @@ nsHttpBasicAuth::ChallengeReceived(nsIHt
+ *identityInvalid = true;
+ return NS_OK;
+ }
++NS_IMETHODIMP
++nsHttpBasicAuth::GenerateCredentialsAsync(nsIHttpAuthenticableChannel *authChannel,
++ nsIHttpAuthenticatorCallback* aCallback,
++ const char *challenge,
++ bool isProxyAuth,
++ const char16_t *domain,
++ const char16_t *username,
++ const char16_t *password,
++ nsISupports *sessionState,
++ nsISupports *continuationState,
++ nsICancelable **aCancellable)
++{
++ return NS_ERROR_NOT_IMPLEMENTED;
++}
+
+ NS_IMETHODIMP
+ nsHttpBasicAuth::GenerateCredentials(nsIHttpAuthenticableChannel *authChannel,
+diff -up firefox-48.0/netwerk/protocol/http/nsHttpChannelAuthProvider.cpp.890908-async-nego firefox-48.0/netwerk/protocol/http/nsHttpChannelAuthProvider.cpp
+--- firefox-48.0/netwerk/protocol/http/nsHttpChannelAuthProvider.cpp.890908-async-nego 2016-05-12 19:13:28.000000000 +0200
++++ firefox-48.0/netwerk/protocol/http/nsHttpChannelAuthProvider.cpp 2016-07-27 09:56:55.653261702 +0200
+@@ -267,6 +267,11 @@ nsHttpChannelAuthProvider::Cancel(nsresu
+ mAsyncPromptAuthCancelable->Cancel(status);
+ mAsyncPromptAuthCancelable = nullptr;
+ }
++
++ if (mGenerateCredentialsCancelable) {
++ mGenerateCredentialsCancelable->Cancel(status);
++ mGenerateCredentialsCancelable = nullptr;
++ }
+ return NS_OK;
+ }
+
+@@ -280,6 +285,11 @@ nsHttpChannelAuthProvider::Disconnect(ns
+ mAsyncPromptAuthCancelable = nullptr;
+ }
+
++ if (mGenerateCredentialsCancelable) {
++ mGenerateCredentialsCancelable->Cancel(status);
++ mGenerateCredentialsCancelable = nullptr;
++ }
++
+ NS_IF_RELEASE(mProxyAuthContinuationState);
+ NS_IF_RELEASE(mAuthContinuationState);
+
+@@ -355,11 +365,6 @@ nsHttpChannelAuthProvider::GenCredsAndSe
+ char **result)
+ {
+ nsresult rv;
+- uint32_t authFlags;
+-
+- rv = auth->GetAuthFlags(&authFlags);
+- if (NS_FAILED(rv)) return rv;
+-
+ nsISupports *ss = sessionState;
+
+ // set informations that depend on whether
+@@ -373,6 +378,22 @@ nsHttpChannelAuthProvider::GenCredsAndSe
+ continuationState = &mAuthContinuationState;
+ }
+
++ rv = auth->GenerateCredentialsAsync(mAuthChannel,
++ this,
++ challenge,
++ proxyAuth,
++ ident.Domain(),
++ ident.User(),
++ ident.Password(),
++ ss,
++ *continuationState,
++ getter_AddRefs(mGenerateCredentialsCancelable));
++ if (NS_SUCCEEDED(rv)) {
++ // Calling generate credentials async, results will be dispatched to the
++ // main thread by calling OnCredsGenerated method
++ return NS_ERROR_IN_PROGRESS;
++ }
++
+ uint32_t generateFlags;
+ rv = auth->GenerateCredentials(mAuthChannel,
+ challenge,
+@@ -393,6 +414,29 @@ nsHttpChannelAuthProvider::GenCredsAndSe
+ LOG(("generated creds: %s\n", *result));
+ #endif
+
++ return UpdateCache(auth, scheme, host, port, directory, realm,
++ challenge, ident, *result, generateFlags, sessionState);
++}
++
++nsresult
++nsHttpChannelAuthProvider::UpdateCache(nsIHttpAuthenticator *auth,
++ const char *scheme,
++ const char *host,
++ int32_t port,
++ const char *directory,
++ const char *realm,
++ const char *challenge,
++ const nsHttpAuthIdentity &ident,
++ const char *creds,
++ uint32_t generateFlags,
++ nsISupports *sessionState)
++{
++ nsresult rv;
++
++ uint32_t authFlags;
++ rv = auth->GetAuthFlags(&authFlags);
++ if (NS_FAILED(rv)) return rv;
++
+ // find out if this authenticator allows reuse of credentials and/or
+ // challenge.
+ bool saveCreds =
+@@ -410,6 +454,7 @@ nsHttpChannelAuthProvider::GenCredsAndSe
+ nsAutoCString suffix;
+ GetOriginAttributesSuffix(chan, suffix);
+
++
+ // create a cache entry. we do this even though we don't yet know that
+ // these credentials are valid b/c we need to avoid prompting the user
+ // more than once in case the credentials are valid.
+@@ -417,12 +462,13 @@ nsHttpChannelAuthProvider::GenCredsAndSe
+ // if the credentials are not reusable, then we don't bother sticking
+ // them in the auth cache.
+ rv = authCache->SetAuthEntry(scheme, host, port, directory, realm,
+- saveCreds ? *result : nullptr,
++ saveCreds ? creds : nullptr,
+ saveChallenge ? challenge : nullptr,
+ suffix,
+ saveIdentity ? &ident : nullptr,
+ sessionState);
+ return rv;
++
+ }
+
+ nsresult
+@@ -1223,6 +1269,63 @@ NS_IMETHODIMP nsHttpChannelAuthProvider:
+ return NS_OK;
+ }
+
++NS_IMETHODIMP nsHttpChannelAuthProvider::OnCredsGenerated(const char *aGeneratedCreds,
++ uint32_t aFlags,
++ nsresult aResult,
++ nsISupports* aSessionState,
++ nsISupports* aContinuationState)
++{
++ nsresult rv;
++
++ MOZ_ASSERT(NS_IsMainThread());
++
++ // When channel is closed, do not proceed
++ if (!mAuthChannel) {
++ return NS_OK;
++ }
++
++ mGenerateCredentialsCancelable = nullptr;
++
++ if (NS_FAILED(aResult)) {
++ return OnAuthCancelled(nullptr, true);
++ }
++
++ // We want to update m(Proxy)AuthContinuationState in case it was changed by
++ // nsHttpNegotiateAuth::GenerateCredentials
++ nsCOMPtr<nsISupports> contState(aContinuationState);
++ if (mProxyAuth) {
++ contState.swap(mProxyAuthContinuationState);
++ } else {
++ contState.swap(mAuthContinuationState);
++ }
++
++ nsCOMPtr<nsIHttpAuthenticator> auth;
++ nsAutoCString unused;
++ rv = GetAuthenticator(mCurrentChallenge.get(), unused, getter_AddRefs(auth));
++ NS_ENSURE_SUCCESS(rv, rv);
++
++ const char *host;
++ int32_t port;
++ nsHttpAuthIdentity *ident;
++ nsAutoCString directory, scheme;
++ nsISupports **unusedContinuationState;
++
++ // Get realm from challenge
++ nsAutoCString realm;
++ ParseRealm(mCurrentChallenge.get(), realm);
++
++ rv = GetAuthorizationMembers(mProxyAuth, scheme, host, port,
++ directory, ident, unusedContinuationState);
++ if (NS_FAILED(rv)) return rv;
++
++ UpdateCache(auth, scheme.get(), host, port, directory.get(), realm.get(),
++ mCurrentChallenge.get(), *ident, aGeneratedCreds, aFlags, aSessionState);
++ mCurrentChallenge.Truncate();
++
++ ContinueOnAuthAvailable(nsDependentCString(aGeneratedCreds));
++ return NS_OK;
++}
++
+ nsresult
+ nsHttpChannelAuthProvider::ContinueOnAuthAvailable(const nsCSubstring& creds)
+ {
+@@ -1457,7 +1560,7 @@ nsHttpChannelAuthProvider::GetCurrentPat
+ }
+
+ NS_IMPL_ISUPPORTS(nsHttpChannelAuthProvider, nsICancelable,
+- nsIHttpChannelAuthProvider, nsIAuthPromptCallback)
++ nsIHttpChannelAuthProvider, nsIAuthPromptCallback, nsIHttpAuthenticatorCallback)
+
+ } // namespace net
+ } // namespace mozilla
+diff -up firefox-48.0/netwerk/protocol/http/nsHttpChannelAuthProvider.h.890908-async-nego firefox-48.0/netwerk/protocol/http/nsHttpChannelAuthProvider.h
+--- firefox-48.0/netwerk/protocol/http/nsHttpChannelAuthProvider.h.890908-async-nego 2016-05-12 19:13:28.000000000 +0200
++++ firefox-48.0/netwerk/protocol/http/nsHttpChannelAuthProvider.h 2016-07-27 09:57:34.084262023 +0200
+@@ -9,11 +9,13 @@
+
+ #include "nsIHttpChannelAuthProvider.h"
+ #include "nsIAuthPromptCallback.h"
++#include "nsIHttpAuthenticatorCallback.h"
+ #include "nsString.h"
+ #include "nsCOMPtr.h"
+ #include "nsHttpAuthCache.h"
+ #include "nsProxyInfo.h"
+ #include "nsCRT.h"
++#include "nsICancelableRunnable.h"
+
+ class nsIHttpAuthenticableChannel;
+ class nsIHttpAuthenticator;
+@@ -25,12 +27,14 @@ class nsHttpHandler;
+
+ class nsHttpChannelAuthProvider : public nsIHttpChannelAuthProvider
+ , public nsIAuthPromptCallback
++ , public nsIHttpAuthenticatorCallback
+ {
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSICANCELABLE
+ NS_DECL_NSIHTTPCHANNELAUTHPROVIDER
+ NS_DECL_NSIAUTHPROMPTCALLBACK
++ NS_DECL_NSIHTTPAUTHENTICATORCALLBACK
+
+ nsHttpChannelAuthProvider();
+ static void InitializePrefs();
+@@ -117,6 +121,19 @@ private:
+ // For more details look at the bug 647010.
+ bool BlockPrompt();
+
++ // Store credentials to the cache when appropriate aFlags are set.
++ nsresult UpdateCache(nsIHttpAuthenticator *aAuth,
++ const char *aScheme,
++ const char *aHost,
++ int32_t aPort,
++ const char *aDirectory,
++ const char *aRealm,
++ const char *aChallenge,
++ const nsHttpAuthIdentity &aIdent,
++ const char *aCreds,
++ uint32_t aGenerateFlags,
++ nsISupports *aSessionState);
++
+ private:
+ nsIHttpAuthenticableChannel *mAuthChannel; // weak ref
+
+@@ -160,6 +177,7 @@ private:
+ // authentication credentials dialogs for sub-resources and cross-origin
+ // sub-resources.
+ static uint32_t sAuthAllowPref;
++ nsCOMPtr<nsICancelable> mGenerateCredentialsCancelable;
+ };
+
+ } // namespace net
+diff -up firefox-48.0/netwerk/protocol/http/nsHttpDigestAuth.cpp.890908-async-nego firefox-48.0/netwerk/protocol/http/nsHttpDigestAuth.cpp
+--- firefox-48.0/netwerk/protocol/http/nsHttpDigestAuth.cpp.890908-async-nego 2016-05-12 19:13:28.000000000 +0200
++++ firefox-48.0/netwerk/protocol/http/nsHttpDigestAuth.cpp 2016-07-27 09:56:55.654261702 +0200
+@@ -158,6 +158,22 @@ nsHttpDigestAuth::ChallengeReceived(nsIH
+ return NS_OK;
+ }
+
++
++NS_IMETHODIMP
++nsHttpDigestAuth::GenerateCredentialsAsync(nsIHttpAuthenticableChannel *authChannel,
++ nsIHttpAuthenticatorCallback* aCallback,
++ const char *challenge,
++ bool isProxyAuth,
++ const char16_t *domain,
++ const char16_t *username,
++ const char16_t *password,
++ nsISupports *sessionState,
++ nsISupports *continuationState,
++ nsICancelable **aCancellable)
++{
++ return NS_ERROR_NOT_IMPLEMENTED;
++}
++
+ NS_IMETHODIMP
+ nsHttpDigestAuth::GenerateCredentials(nsIHttpAuthenticableChannel *authChannel,
+ const char *challenge,
+diff -up firefox-48.0/netwerk/protocol/http/nsHttpNTLMAuth.cpp.890908-async-nego firefox-48.0/netwerk/protocol/http/nsHttpNTLMAuth.cpp
+--- firefox-48.0/netwerk/protocol/http/nsHttpNTLMAuth.cpp.890908-async-nego 2016-07-25 22:22:06.000000000 +0200
++++ firefox-48.0/netwerk/protocol/http/nsHttpNTLMAuth.cpp 2016-07-27 09:56:55.654261702 +0200
+@@ -333,6 +333,21 @@ nsHttpNTLMAuth::ChallengeReceived(nsIHtt
+ }
+
+ NS_IMETHODIMP
++nsHttpNTLMAuth::GenerateCredentialsAsync(nsIHttpAuthenticableChannel *authChannel,
++ nsIHttpAuthenticatorCallback* aCallback,
++ const char *challenge,
++ bool isProxyAuth,
++ const char16_t *domain,
++ const char16_t *username,
++ const char16_t *password,
++ nsISupports *sessionState,
++ nsISupports *continuationState,
++ nsICancelable **aCancellable)
++{
++ return NS_ERROR_NOT_IMPLEMENTED;
++}
++
++NS_IMETHODIMP
+ nsHttpNTLMAuth::GenerateCredentials(nsIHttpAuthenticableChannel *authChannel,
+ const char *challenge,
+ bool isProxyAuth,
+diff -up firefox-48.0/netwerk/protocol/http/nsIHttpAuthenticator.idl.890908-async-nego firefox-48.0/netwerk/protocol/http/nsIHttpAuthenticator.idl
+--- firefox-48.0/netwerk/protocol/http/nsIHttpAuthenticator.idl.890908-async-nego 2016-05-12 19:13:28.000000000 +0200
++++ firefox-48.0/netwerk/protocol/http/nsIHttpAuthenticator.idl 2016-07-27 09:56:55.654261702 +0200
+@@ -6,6 +6,8 @@
+ #include "nsISupports.idl"
+
+ interface nsIHttpAuthenticableChannel;
++interface nsIHttpAuthenticatorCallback;
++interface nsICancelable;
+
+ /**
+ * nsIHttpAuthenticator
+@@ -18,7 +20,7 @@ interface nsIHttpAuthenticableChannel;
+ * where <auth-scheme> is the lower-cased value of the authentication scheme
+ * found in the server challenge per the rules of RFC 2617.
+ */
+-[scriptable, uuid(16784db0-fcb1-4352-b0c9-6a3a67e3cf79)]
++[scriptable, uuid(fef7db8a-a4e2-49d1-9685-19ed7e309b7d)]
+ interface nsIHttpAuthenticator : nsISupports
+ {
+ /**
+@@ -54,6 +56,54 @@ interface nsIHttpAuthenticator : nsISupp
+
+ /**
+ * Called to generate the authentication credentials for a particular
++ * server/proxy challenge asynchronously. Credentials will be sent back
++ * to the server via an Authorization/Proxy-Authorization header.
++ *
++ * @param aChannel
++ * the http channel requesting credentials
++ * @param aCallback
++ * callback function to be called when credentials are available
++ * @param aChallenge
++ * the challenge from the WWW-Authenticate/Proxy-Authenticate
++ * server response header. (possibly from the auth cache.)
++ * @param aProxyAuth
++ * flag indicating whether or not aChallenge is from a proxy.
++ * @param aDomain
++ * string containing the domain name (if appropriate)
++ * @param aUser
++ * string containing the user name
++ * @param aPassword
++ * string containing the password
++ * @param aSessionState
++ * state stored along side the user's identity in the auth cache
++ * for the lifetime of the browser session. if a new auth cache
++ * entry is created for this challenge, then this parameter will
++ * be null. on return, the result will be stored in the new auth
++ * cache entry. this parameter is non-null when an auth cache entry
++ * is being reused. currently modification of session state is not
++ * communicated to caller, thus caching credentials obtained by
++ * asynchronous way is not supported.
++ * @param aContinuationState
++ * state held by the channel between consecutive calls to
++ * generateCredentials, assuming multiple calls are required
++ * to authenticate. this state is held for at most the lifetime of
++ * the channel.
++ * @pram aCancel
++ * returns cancellable runnable object which caller can use to cancel
++ * calling aCallback when finished.
++ */
++ void generateCredentialsAsync(in nsIHttpAuthenticableChannel aChannel,
++ in nsIHttpAuthenticatorCallback aCallback,
++ in string aChallenge,
++ in boolean aProxyAuth,
++ in wstring aDomain,
++ in wstring aUser,
++ in wstring aPassword,
++ in nsISupports aSessionState,
++ in nsISupports aContinuationState,
++ out nsICancelable aCancel);
++ /**
++ * Called to generate the authentication credentials for a particular
+ * server/proxy challenge. This is the value that will be sent back
+ * to the server via an Authorization/Proxy-Authorization header.
+ *
bgstack15