michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 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: #ifndef nsAsyncRedirectVerifyHelper_h michael@0: #define nsAsyncRedirectVerifyHelper_h michael@0: michael@0: #include "nsIRunnable.h" michael@0: #include "nsIThread.h" michael@0: #include "nsIChannelEventSink.h" michael@0: #include "nsIInterfaceRequestor.h" michael@0: #include "nsIAsyncVerifyRedirectCallback.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsAutoPtr.h" michael@0: #include "nsCycleCollectionParticipant.h" michael@0: #include "mozilla/Attributes.h" michael@0: michael@0: class nsIChannel; michael@0: michael@0: /** michael@0: * This class simplifies call of OnChannelRedirect of IOService and michael@0: * the sink bound with the channel being redirected while the result of michael@0: * redirect decision is returned through the callback. michael@0: */ michael@0: class nsAsyncRedirectVerifyHelper MOZ_FINAL : public nsIRunnable, michael@0: public nsIAsyncVerifyRedirectCallback michael@0: { michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: NS_DECL_NSIRUNNABLE michael@0: NS_DECL_NSIASYNCVERIFYREDIRECTCALLBACK michael@0: michael@0: public: michael@0: nsAsyncRedirectVerifyHelper(); michael@0: michael@0: /* michael@0: * Calls AsyncOnChannelRedirect() on the given sink with the given michael@0: * channels and flags. Keeps track of number of async callbacks to expect. michael@0: */ michael@0: nsresult DelegateOnChannelRedirect(nsIChannelEventSink *sink, michael@0: nsIChannel *oldChannel, michael@0: nsIChannel *newChannel, michael@0: uint32_t flags); michael@0: michael@0: /** michael@0: * Initialize and run the chain of AsyncOnChannelRedirect calls. OldChannel michael@0: * is QI'ed for nsIAsyncVerifyRedirectCallback. The result of the redirect michael@0: * decision is passed through this interface back to the oldChannel. michael@0: * michael@0: * @param oldChan michael@0: * channel being redirected, MUST implement michael@0: * nsIAsyncVerifyRedirectCallback michael@0: * @param newChan michael@0: * target of the redirect channel michael@0: * @param flags michael@0: * redirect flags michael@0: * @param synchronize michael@0: * set to TRUE if you want the Init method wait synchronously for michael@0: * all redirect callbacks michael@0: */ michael@0: nsresult Init(nsIChannel* oldChan, michael@0: nsIChannel* newChan, michael@0: uint32_t flags, michael@0: bool synchronize = false); michael@0: michael@0: protected: michael@0: nsCOMPtr mOldChan; michael@0: nsCOMPtr mNewChan; michael@0: uint32_t mFlags; michael@0: bool mWaitingForRedirectCallback; michael@0: nsCOMPtr mCallbackThread; michael@0: bool mCallbackInitiated; michael@0: int32_t mExpectedCallbacks; michael@0: nsresult mResult; // value passed to callback michael@0: michael@0: void InitCallback(); michael@0: michael@0: /** michael@0: * Calls back to |oldChan| as described in Init() michael@0: */ michael@0: void ExplicitCallback(nsresult result); michael@0: michael@0: private: michael@0: ~nsAsyncRedirectVerifyHelper(); michael@0: michael@0: bool IsOldChannelCanceled(); michael@0: }; michael@0: michael@0: /* michael@0: * Helper to make the call-stack handle some control-flow for us michael@0: */ michael@0: class nsAsyncRedirectAutoCallback michael@0: { michael@0: public: michael@0: nsAsyncRedirectAutoCallback(nsIAsyncVerifyRedirectCallback* aCallback) michael@0: : mCallback(aCallback) michael@0: { michael@0: mResult = NS_OK; michael@0: } michael@0: ~nsAsyncRedirectAutoCallback() michael@0: { michael@0: if (mCallback) michael@0: mCallback->OnRedirectVerifyCallback(mResult); michael@0: } michael@0: /* michael@0: * Call this is you want it to call back with a different result-code michael@0: */ michael@0: void SetResult(nsresult aRes) michael@0: { michael@0: mResult = aRes; michael@0: } michael@0: /* michael@0: * Call this is you want to avoid the callback michael@0: */ michael@0: void DontCallback() michael@0: { michael@0: mCallback = nullptr; michael@0: } michael@0: private: michael@0: nsIAsyncVerifyRedirectCallback* mCallback; michael@0: nsresult mResult; michael@0: }; michael@0: michael@0: #endif