Blob Blame History Raw
diff -up firefox-46.0.1/extensions/auth/nsHttpNegotiateAuth.cpp.890908-async-negotiate firefox-46.0.1/extensions/auth/nsHttpNegotiateAuth.cpp
--- firefox-46.0.1/extensions/auth/nsHttpNegotiateAuth.cpp.890908-async-negotiate	2016-05-03 07:31:11.000000000 +0200
+++ firefox-46.0.1/extensions/auth/nsHttpNegotiateAuth.cpp	2016-05-26 10:58:14.754420347 +0200
@@ -38,6 +38,10 @@
 #include "prnetdb.h"
 #include "mozilla/Likely.h"
 #include "mozilla/Snprintf.h"
+#include "nsThreadUtils.h"
+#include "nsIHttpAuthenticatorCallback.h"
+#include "mozilla/Mutex.h"
+#include "nsICancelable.h"
 
 //-----------------------------------------------------------------------------
 
@@ -49,6 +53,7 @@ static const char kNegotiateAuthAllowNon
 static const char kNegotiateAuthSSPI[] = "network.auth.use-sspi";
 
 #define kNegotiateLen  (sizeof(kNegotiate)-1)
+#define DEFAULT_THREAD_TIMEOUT_MS 30000
 
 //-----------------------------------------------------------------------------
 
@@ -172,7 +177,237 @@ 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,
+                                  nsISupports *aSessionState,
+                                  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()
+    {
+        // Called from worker thread
+        MOZ_ASSERT(!NS_IsMainThread());
+
+        mResult = NS_ERROR_FAILURE;
+        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 mozilla::Runnable
+{
+    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);
+           if (NS_FAILED(rv)) {
+               return mCompleteEvent->DispatchError();
+           }
+
+           return mCompleteEvent->DispatchSuccess(creds, flags,  mSessionState, mContinuationState);
+        }
+
+        NS_IMETHODIMP ObtainCredentialsAndFlags(char **aCreds, uint32_t *aFlags)
+        {
+           // Use negotiate service to call GenerateCredentials outside of main thread
+           nsAutoCString contractId;
+           contractId.Assign(NS_HTTP_AUTHENTICATOR_CONTRACTID_PREFIX);
+           contractId.Append("negotiate");
+           nsresult rv;
+           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.
+           rv = authenticator->GenerateCredentials(mAuthChannel,
+                                                   mChallenge.get(),
+                                                   mIsProxyAuth,
+                                                   mDomain.get(),
+                                                   mUsername.get(),
+                                                   mPassword.get(),
+                                                   &sessionState,
+                                                   &continuationState,
+                                                   aFlags,
+                                                   aCreds);
+           mSessionState = sessionState;
+           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-46.0.1/extensions/auth/nsHttpNegotiateAuth.h.890908-async-negotiate firefox-46.0.1/extensions/auth/nsHttpNegotiateAuth.h
--- firefox-46.0.1/extensions/auth/nsHttpNegotiateAuth.h.890908-async-negotiate	2016-05-03 07:31:11.000000000 +0200
+++ firefox-46.0.1/extensions/auth/nsHttpNegotiateAuth.h	2016-05-26 10:51:14.816550760 +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-46.0.1/netwerk/base/moz.build.rej.890908-async-negotiate firefox-46.0.1/netwerk/base/moz.build.rej
diff -up firefox-46.0.1/netwerk/base/nsIHttpAuthenticatorCallback.idl.890908-async-negotiate firefox-46.0.1/netwerk/base/nsIHttpAuthenticatorCallback.idl
--- firefox-46.0.1/netwerk/base/nsIHttpAuthenticatorCallback.idl.890908-async-negotiate	2016-05-26 10:51:14.816550760 +0200
+++ firefox-46.0.1/netwerk/base/nsIHttpAuthenticatorCallback.idl	2016-05-26 10:51:14.816550760 +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-46.0.1/netwerk/protocol/http/nsHttpBasicAuth.cpp.890908-async-negotiate firefox-46.0.1/netwerk/protocol/http/nsHttpBasicAuth.cpp
--- firefox-46.0.1/netwerk/protocol/http/nsHttpBasicAuth.cpp.890908-async-negotiate	2016-05-03 07:31:08.000000000 +0200
+++ firefox-46.0.1/netwerk/protocol/http/nsHttpBasicAuth.cpp	2016-05-26 10:51:14.816550760 +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-46.0.1/netwerk/protocol/http/nsHttpChannelAuthProvider.cpp.890908-async-negotiate firefox-46.0.1/netwerk/protocol/http/nsHttpChannelAuthProvider.cpp
--- firefox-46.0.1/netwerk/protocol/http/nsHttpChannelAuthProvider.cpp.890908-async-negotiate	2016-05-03 07:31:08.000000000 +0200
+++ firefox-46.0.1/netwerk/protocol/http/nsHttpChannelAuthProvider.cpp	2016-05-26 10:51:14.817550760 +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
@@ -1224,6 +1270,66 @@ NS_IMETHODIMP nsHttpChannelAuthProvider:
 }
 
 nsresult
+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);
+        NS_IF_ADDREF(mProxyAuthContinuationState);
+    } else {
+        contState.swap(mAuthContinuationState);
+        NS_IF_ADDREF(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)
 {
     nsresult rv;
@@ -1457,7 +1563,7 @@ nsHttpChannelAuthProvider::GetCurrentPat
 }
 
 NS_IMPL_ISUPPORTS(nsHttpChannelAuthProvider, nsICancelable,
-                  nsIHttpChannelAuthProvider, nsIAuthPromptCallback)
+                  nsIHttpChannelAuthProvider, nsIAuthPromptCallback, nsIHttpAuthenticatorCallback)
 
 } // namespace net
 } // namespace mozilla
diff -up firefox-46.0.1/netwerk/protocol/http/nsHttpChannelAuthProvider.h.890908-async-negotiate firefox-46.0.1/netwerk/protocol/http/nsHttpChannelAuthProvider.h
--- firefox-46.0.1/netwerk/protocol/http/nsHttpChannelAuthProvider.h.890908-async-negotiate	2016-05-03 07:31:08.000000000 +0200
+++ firefox-46.0.1/netwerk/protocol/http/nsHttpChannelAuthProvider.h	2016-05-26 10:51:14.817550760 +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-46.0.1/netwerk/protocol/http/nsHttpDigestAuth.cpp.890908-async-negotiate firefox-46.0.1/netwerk/protocol/http/nsHttpDigestAuth.cpp
--- firefox-46.0.1/netwerk/protocol/http/nsHttpDigestAuth.cpp.890908-async-negotiate	2016-05-03 07:31:08.000000000 +0200
+++ firefox-46.0.1/netwerk/protocol/http/nsHttpDigestAuth.cpp	2016-05-26 10:51:14.817550760 +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-46.0.1/netwerk/protocol/http/nsHttpNTLMAuth.cpp.890908-async-negotiate firefox-46.0.1/netwerk/protocol/http/nsHttpNTLMAuth.cpp
--- firefox-46.0.1/netwerk/protocol/http/nsHttpNTLMAuth.cpp.890908-async-negotiate	2016-05-03 07:31:08.000000000 +0200
+++ firefox-46.0.1/netwerk/protocol/http/nsHttpNTLMAuth.cpp	2016-05-26 10:51:14.817550760 +0200
@@ -323,6 +323,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-46.0.1/netwerk/protocol/http/nsIHttpAuthenticator.idl.890908-async-negotiate firefox-46.0.1/netwerk/protocol/http/nsIHttpAuthenticator.idl
--- firefox-46.0.1/netwerk/protocol/http/nsIHttpAuthenticator.idl.890908-async-negotiate	2016-05-03 07:31:08.000000000 +0200
+++ firefox-46.0.1/netwerk/protocol/http/nsIHttpAuthenticator.idl	2016-05-26 10:51:14.817550760 +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.
      *