LCOV - app.info - netwerk/base/src/nsAsyncRedirectVerifyHelper.cpp

LCOV - code coverage report
| Current view: | directory - netwerk/base/src - nsAsyncRedirectVerifyHelper.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 102 | 85 | 83.3 %
| Date: | 2012-07-07 | Functions: | 19 | 18 | 94.7 %

           1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
           2                 : /* ***** BEGIN LICENSE BLOCK *****
           3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
           4                 :  *
           5                 :  * The contents of this file are subject to the Mozilla Public License Version
           6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
           7                 :  * the License. You may obtain a copy of the License at
           8                 :  * http://www.mozilla.org/MPL/
           9                 :  *
          10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
          11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
          12                 :  * for the specific language governing rights and limitations under the
          13                 :  * License.
          14                 :  *
          15                 :  * The Original Code is mozilla.org networking code.
          16                 :  *
          17                 :  * The Initial Developer of the Original Code is
          18                 :  * Mozilla Corporation
          19                 :  * Portions created by the Initial Developer are Copyright (C) 2009
          20                 :  * the Initial Developer. All Rights Reserved.
          21                 :  *
          22                 :  * Contributor(s):
          23                 :  *    Honza Bambas <honzab@firemni.cz>
          24                 :  *    Bjarne Geir Herland <bjarne@runitsoft.com>
          25                 :  *
          26                 :  * Alternatively, the contents of this file may be used under the terms of
          27                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
          28                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
          29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
          30                 :  * of those above. If you wish to allow use of your version of this file only
          31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
          32                 :  * use your version of this file under the terms of the MPL, indicate your
          33                 :  * decision by deleting the provisions above and replace them with the notice
          34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
          35                 :  * the provisions above, a recipient may use your version of this file under
          36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
          37                 :  *
          38                 :  * ***** END LICENSE BLOCK ***** */
          39                 :
          40                 : #ifdef MOZ_LOGGING
          41                 : #define FORCE_PR_LOG
          42                 : #endif
          43                 :
          44                 : #include "prlog.h"
          45                 : #include "nsAsyncRedirectVerifyHelper.h"
          46                 : #include "nsThreadUtils.h"
          47                 : #include "nsNetUtil.h"
          48                 :
          49                 : #include "nsIOService.h"
          50                 : #include "nsIChannel.h"
          51                 : #include "nsIHttpChannelInternal.h"
          52                 : #include "nsIAsyncVerifyRedirectCallback.h"
          53                 :
          54                 : #ifdef PR_LOGGING
          55            1464 : static PRLogModuleInfo *gLog = PR_NewLogModule("nsRedirect");
          56                 : #define LOG(args) PR_LOG(gLog, PR_LOG_DEBUG, args)
          57                 : #else
          58                 : #define LOG(args)
          59                 : #endif
          60                 :
          61            1703 : NS_IMPL_THREADSAFE_ISUPPORTS2(nsAsyncRedirectVerifyHelper,
          62                 :                               nsIAsyncVerifyRedirectCallback,
          63                 :                               nsIRunnable)
          64                 :
          65             620 : class nsAsyncVerifyRedirectCallbackEvent : public nsRunnable {
          66                 : public:
          67             155 :     nsAsyncVerifyRedirectCallbackEvent(nsIAsyncVerifyRedirectCallback *cb,
          68                 :                                        nsresult result)
          69             155 :         : mCallback(cb), mResult(result) {
          70             155 :     }
          71                 :
          72             155 :     NS_IMETHOD Run()
          73                 :     {
          74             155 :         LOG(("nsAsyncVerifyRedirectCallbackEvent::Run() "
          75                 :              "callback to %p with result %x",
          76                 :              mCallback.get(), mResult));
          77             155 :        (void) mCallback->OnRedirectVerifyCallback(mResult);
          78             155 :        return NS_OK;
          79                 :     }
          80                 : private:
          81                 :     nsCOMPtr<nsIAsyncVerifyRedirectCallback> mCallback;
          82                 :     nsresult mResult;
          83                 : };
          84                 :
          85             155 : nsAsyncRedirectVerifyHelper::nsAsyncRedirectVerifyHelper()
          86                 :     : mCallbackInitiated(false),
          87                 :       mExpectedCallbacks(0),
          88             155 :       mResult(NS_OK)
          89                 : {
          90             155 : }
          91                 :
          92             310 : nsAsyncRedirectVerifyHelper::~nsAsyncRedirectVerifyHelper()
          93                 : {
          94             155 :     NS_ASSERTION(NS_FAILED(mResult) || mExpectedCallbacks == 0,
          95                 :                  "Did not receive all required callbacks!");
          96             155 : }
          97                 :
          98                 : nsresult
          99             155 : nsAsyncRedirectVerifyHelper::Init(nsIChannel* oldChan, nsIChannel* newChan,
         100                 :                                   PRUint32 flags, bool synchronize)
         101                 : {
         102             155 :     LOG(("nsAsyncRedirectVerifyHelper::Init() "
         103                 :          "oldChan=%p newChan=%p", oldChan, newChan));
         104             155 :     mOldChan           = oldChan;
         105             155 :     mNewChan           = newChan;
         106             155 :     mFlags             = flags;
         107             155 :     mCallbackThread    = do_GetCurrentThread();
         108                 :
         109             155 :     if (synchronize)
         110               0 :       mWaitingForRedirectCallback = true;
         111                 :
         112                 :     nsresult rv;
         113             155 :     rv = NS_DispatchToMainThread(this);
         114             155 :     NS_ENSURE_SUCCESS(rv, rv);
         115                 :
         116             155 :     if (synchronize) {
         117               0 :       nsIThread *thread = NS_GetCurrentThread();
         118               0 :       while (mWaitingForRedirectCallback) {
         119               0 :         if (!NS_ProcessNextEvent(thread)) {
         120               0 :           return NS_ERROR_UNEXPECTED;
         121                 :         }
         122                 :       }
         123                 :     }
         124                 :
         125             155 :     return NS_OK;
         126                 : }
         127                 :
         128                 : NS_IMETHODIMP
         129             371 : nsAsyncRedirectVerifyHelper::OnRedirectVerifyCallback(nsresult result)
         130                 : {
         131             371 :     LOG(("nsAsyncRedirectVerifyHelper::OnRedirectVerifyCallback() "
         132                 :          "result=%x expectedCBs=%u mResult=%x",
         133                 :          result, mExpectedCallbacks, mResult));
         134                 :
         135             371 :     --mExpectedCallbacks;
         136                 :
         137                 :     // If response indicates failure we may call back immediately
         138             371 :     if (NS_FAILED(result)) {
         139                 :         // We chose to store the first failure-value (as opposed to the last)
         140              15 :         if (NS_SUCCEEDED(mResult))
         141              15 :             mResult = result;
         142                 :
         143                 :         // If InitCallback() has been called, just invoke the callback and
         144                 :         // return. Otherwise it will be invoked from InitCallback()
         145              15 :         if (mCallbackInitiated) {
         146               0 :             ExplicitCallback(mResult);
         147               0 :             return NS_OK;
         148                 :         }
         149                 :     }
         150                 :
         151                 :     // If the expected-counter is in balance and InitCallback() was called, all
         152                 :     // sinks have agreed that the redirect is ok and we can invoke our callback
         153             371 :     if (mCallbackInitiated && mExpectedCallbacks == 0) {
         154               0 :         ExplicitCallback(mResult);
         155                 :     }
         156                 :
         157             371 :     return NS_OK;
         158                 : }
         159                 :
         160                 : nsresult
         161             371 : nsAsyncRedirectVerifyHelper::DelegateOnChannelRedirect(nsIChannelEventSink *sink,
         162                 :                                                        nsIChannel *oldChannel,
         163                 :                                                        nsIChannel *newChannel,
         164                 :                                                        PRUint32 flags)
         165                 : {
         166             371 :     LOG(("nsAsyncRedirectVerifyHelper::DelegateOnChannelRedirect() "
         167                 :          "sink=%p expectedCBs=%u mResult=%x",
         168                 :          sink, mExpectedCallbacks, mResult));
         169                 :
         170             371 :     ++mExpectedCallbacks;
         171                 :
         172             371 :     if (IsOldChannelCanceled()) {
         173               0 :         LOG(("  old channel has been canceled, cancel the redirect by "
         174                 :              "emulating OnRedirectVerifyCallback..."));
         175               0 :         (void) OnRedirectVerifyCallback(NS_BINDING_ABORTED);
         176               0 :         return NS_BINDING_ABORTED;
         177                 :     }
         178                 :
         179                 :     nsresult rv =
         180             371 :         sink->AsyncOnChannelRedirect(oldChannel, newChannel, flags, this);
         181                 :
         182             371 :     LOG(("  result=%x expectedCBs=%u", rv, mExpectedCallbacks));
         183                 :
         184                 :     // If the sink returns failure from this call the redirect is vetoed. We
         185                 :     // emulate a callback from the sink in this case in order to perform all
         186                 :     // the necessary logic.
         187             371 :     if (NS_FAILED(rv)) {
         188              15 :         LOG(("  emulating OnRedirectVerifyCallback..."));
         189              15 :         (void) OnRedirectVerifyCallback(rv);
         190                 :     }
         191                 :
         192             371 :     return rv;  // Return the actual status since our caller may need it
         193                 : }
         194                 :
         195                 : void
         196             155 : nsAsyncRedirectVerifyHelper::ExplicitCallback(nsresult result)
         197                 : {
         198             155 :     LOG(("nsAsyncRedirectVerifyHelper::ExplicitCallback() "
         199                 :          "result=%x expectedCBs=%u mCallbackInitiated=%u mResult=%x",
         200                 :          result, mExpectedCallbacks, mCallbackInitiated, mResult));
         201                 :
         202                 :     nsCOMPtr<nsIAsyncVerifyRedirectCallback>
         203             310 :         callback(do_QueryInterface(mOldChan));
         204                 :
         205             155 :     if (!callback || !mCallbackThread) {
         206               0 :         LOG(("nsAsyncRedirectVerifyHelper::ExplicitCallback() "
         207                 :              "callback=%p mCallbackThread=%p", callback.get(), mCallbackThread.get()));
         208                 :         return;
         209                 :     }
         210                 :
         211             155 :     mCallbackInitiated = false;  // reset to ensure only one callback
         212             155 :     mWaitingForRedirectCallback = false;
         213                 :
         214                 :     // Now, dispatch the callback on the event-target which called Init()
         215                 :     nsRefPtr<nsIRunnable> event =
         216             465 :         new nsAsyncVerifyRedirectCallbackEvent(callback, result);
         217             155 :     if (!event) {
         218                 :         NS_WARNING("nsAsyncRedirectVerifyHelper::ExplicitCallback() "
         219               0 :                    "failed creating callback event!");
         220                 :         return;
         221                 :     }
         222             155 :     nsresult rv = mCallbackThread->Dispatch(event, NS_DISPATCH_NORMAL);
         223             155 :     if (NS_FAILED(rv)) {
         224                 :         NS_WARNING("nsAsyncRedirectVerifyHelper::ExplicitCallback() "
         225               0 :                    "failed dispatching callback event!");
         226                 :     } else {
         227             155 :         LOG(("nsAsyncRedirectVerifyHelper::ExplicitCallback() "
         228                 :              "dispatched callback event=%p", event.get()));
         229                 :     }
         230                 :
         231                 : }
         232                 :
         233                 : void
         234             152 : nsAsyncRedirectVerifyHelper::InitCallback()
         235                 : {
         236             152 :     LOG(("nsAsyncRedirectVerifyHelper::InitCallback() "
         237                 :          "expectedCBs=%d mResult=%x", mExpectedCallbacks, mResult));
         238                 :
         239             152 :     mCallbackInitiated = true;
         240                 :
         241                 :     // Invoke the callback if we are done
         242             152 :     if (mExpectedCallbacks == 0)
         243             152 :         ExplicitCallback(mResult);
         244             152 : }
         245                 :
         246                 : NS_IMETHODIMP
         247             155 : nsAsyncRedirectVerifyHelper::Run()
         248                 : {
         249                 :     /* If the channel got canceled after it fired AsyncOnChannelRedirect
         250                 :      * and before we got here, mostly because docloader load has been canceled,
         251                 :      * we must completely ignore this notification and prevent any further
         252                 :      * notification.
         253                 :      */
         254             155 :     if (IsOldChannelCanceled()) {
         255               0 :         ExplicitCallback(NS_BINDING_ABORTED);
         256               0 :         return NS_OK;
         257                 :     }
         258                 :
         259                 :     // First, the global observer
         260             155 :     NS_ASSERTION(gIOService, "Must have an IO service at this point");
         261             155 :     LOG(("nsAsyncRedirectVerifyHelper::Run() calling gIOService..."));
         262                 :     nsresult rv = gIOService->AsyncOnChannelRedirect(mOldChan, mNewChan,
         263             155 :                                                      mFlags, this);
         264             155 :     if (NS_FAILED(rv)) {
         265               3 :         ExplicitCallback(rv);
         266               3 :         return NS_OK;
         267                 :     }
         268                 :
         269                 :     // Now, the per-channel observers
         270             304 :     nsCOMPtr<nsIChannelEventSink> sink;
         271             152 :     NS_QueryNotificationCallbacks(mOldChan, sink);
         272             152 :     if (sink) {
         273              62 :         LOG(("nsAsyncRedirectVerifyHelper::Run() calling sink..."));
         274              62 :         rv = DelegateOnChannelRedirect(sink, mOldChan, mNewChan, mFlags);
         275                 :     }
         276                 :
         277                 :     // All invocations to AsyncOnChannelRedirect has been done - call
         278                 :     // InitCallback() to flag this
         279             152 :     InitCallback();
         280             152 :     return NS_OK;
         281                 : }
         282                 :
         283                 : bool
         284             526 : nsAsyncRedirectVerifyHelper::IsOldChannelCanceled()
         285                 : {
         286                 :     bool canceled;
         287                 :     nsCOMPtr<nsIHttpChannelInternal> oldChannelInternal =
         288            1052 :         do_QueryInterface(mOldChan);
         289             526 :     if (oldChannelInternal) {
         290             526 :         oldChannelInternal->GetCanceled(&canceled);
         291             526 :         if (canceled)
         292               0 :             return true;
         293                 :     }
         294                 :
         295             526 :     return false;
         296            4392 : }

Generated by: LCOV version 1.7