LCOV - code coverage report
Current view: directory - netwerk/base/src - nsBaseChannel.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 344 219 63.7 %
Date: 2012-06-02 Functions: 54 43 79.6 %

       1                 : /* -*- Mode: C++; tab-width: 2; 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 code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is Google Inc.
      18                 :  * Portions created by the Initial Developer are Copyright (C) 2005
      19                 :  * the Initial Developer. All Rights Reserved.
      20                 :  *
      21                 :  * Contributor(s):
      22                 :  *  Darin Fisher <darin@meer.net>
      23                 :  *
      24                 :  * Alternatively, the contents of this file may be used under the terms of
      25                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      26                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      27                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      28                 :  * of those above. If you wish to allow use of your version of this file only
      29                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      30                 :  * use your version of this file under the terms of the MPL, indicate your
      31                 :  * decision by deleting the provisions above and replace them with the notice
      32                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      33                 :  * the provisions above, a recipient may use your version of this file under
      34                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      35                 :  *
      36                 :  * ***** END LICENSE BLOCK ***** */
      37                 : 
      38                 : #include "nsBaseChannel.h"
      39                 : #include "nsChannelProperties.h"
      40                 : #include "nsURLHelper.h"
      41                 : #include "nsNetUtil.h"
      42                 : #include "nsMimeTypes.h"
      43                 : #include "nsIOService.h"
      44                 : #include "nsIHttpEventSink.h"
      45                 : #include "nsIHttpChannel.h"
      46                 : #include "nsIChannelEventSink.h"
      47                 : #include "nsIStreamConverterService.h"
      48                 : #include "nsIContentSniffer.h"
      49                 : #include "nsChannelClassifier.h"
      50                 : #include "nsAsyncRedirectVerifyHelper.h"
      51                 : 
      52                 : static PLDHashOperator
      53               0 : CopyProperties(const nsAString &key, nsIVariant *data, void *closure)
      54                 : {
      55                 :   nsIWritablePropertyBag *bag =
      56               0 :       static_cast<nsIWritablePropertyBag *>(closure);
      57                 : 
      58               0 :   bag->SetProperty(key, data);
      59               0 :   return PL_DHASH_NEXT;
      60                 : }
      61                 : 
      62                 : // This class is used to suspend a request across a function scope.
      63                 : class ScopedRequestSuspender {
      64                 : public:
      65             617 :   ScopedRequestSuspender(nsIRequest *request)
      66             617 :     : mRequest(request) {
      67             617 :     if (mRequest && NS_FAILED(mRequest->Suspend())) {
      68               0 :       NS_WARNING("Couldn't suspend pump");
      69               0 :       mRequest = nsnull;
      70                 :     }
      71             617 :   }
      72             617 :   ~ScopedRequestSuspender() {
      73             617 :     if (mRequest)
      74             617 :       mRequest->Resume();
      75             617 :   }
      76                 : private:
      77                 :   nsIRequest *mRequest;
      78                 : };
      79                 : 
      80                 : // Used to suspend data events from mPump within a function scope.  This is
      81                 : // usually needed when a function makes callbacks that could process events.
      82                 : #define SUSPEND_PUMP_FOR_SCOPE() \
      83                 :   ScopedRequestSuspender pump_suspender__(mPump)
      84                 : 
      85                 : //-----------------------------------------------------------------------------
      86                 : // nsBaseChannel
      87                 : 
      88           53433 : nsBaseChannel::nsBaseChannel()
      89                 :   : mLoadFlags(LOAD_NORMAL)
      90                 :   , mQueriedProgressSink(true)
      91                 :   , mSynthProgressEvents(false)
      92                 :   , mWasOpened(false)
      93                 :   , mWaitingOnAsyncRedirect(false)
      94           53433 :   , mStatus(NS_OK)
      95                 : {
      96           53433 :   mContentType.AssignLiteral(UNKNOWN_CONTENT_TYPE);
      97           53433 : }
      98                 : 
      99                 : nsresult
     100               0 : nsBaseChannel::Redirect(nsIChannel *newChannel, PRUint32 redirectFlags,
     101                 :                         bool openNewChannel)
     102                 : {
     103               0 :   SUSPEND_PUMP_FOR_SCOPE();
     104                 : 
     105                 :   // Transfer properties
     106                 : 
     107               0 :   newChannel->SetLoadGroup(mLoadGroup);
     108               0 :   newChannel->SetNotificationCallbacks(mCallbacks);
     109               0 :   newChannel->SetLoadFlags(mLoadFlags | LOAD_REPLACE);
     110                 : 
     111               0 :   nsCOMPtr<nsIWritablePropertyBag> bag = ::do_QueryInterface(newChannel);
     112               0 :   if (bag)
     113               0 :     mPropertyHash.EnumerateRead(CopyProperties, bag.get());
     114                 : 
     115                 :   // Notify consumer, giving chance to cancel redirect.  For backwards compat,
     116                 :   // we support nsIHttpEventSink if we are an HTTP channel and if this is not
     117                 :   // an internal redirect.
     118                 : 
     119                 :   nsRefPtr<nsAsyncRedirectVerifyHelper> redirectCallbackHelper =
     120               0 :       new nsAsyncRedirectVerifyHelper();
     121                 : 
     122               0 :   bool checkRedirectSynchronously = !openNewChannel;
     123                 : 
     124               0 :   mRedirectChannel = newChannel;
     125               0 :   mRedirectFlags = redirectFlags;
     126               0 :   mOpenRedirectChannel = openNewChannel;
     127                 :   nsresult rv = redirectCallbackHelper->Init(this, newChannel, redirectFlags,
     128               0 :                                              checkRedirectSynchronously);
     129               0 :   if (NS_FAILED(rv))
     130               0 :     return rv;
     131                 : 
     132               0 :   if (checkRedirectSynchronously && NS_FAILED(mStatus))
     133               0 :     return mStatus;
     134                 : 
     135               0 :   return NS_OK;
     136                 : }
     137                 : 
     138                 : nsresult
     139               0 : nsBaseChannel::ContinueRedirect()
     140                 : {
     141                 :   // Backwards compat for non-internal redirects from a HTTP channel.
     142                 :   // XXX Is our http channel implementation going to derive from nsBaseChannel?
     143                 :   //     If not, this code can be removed.
     144               0 :   if (!(mRedirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL)) {
     145               0 :     nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface();
     146               0 :     if (httpChannel) {
     147               0 :       nsCOMPtr<nsIHttpEventSink> httpEventSink;
     148               0 :       GetCallback(httpEventSink);
     149               0 :       if (httpEventSink) {
     150               0 :         nsresult rv = httpEventSink->OnRedirect(httpChannel, mRedirectChannel);
     151               0 :         if (NS_FAILED(rv)) {
     152               0 :           return rv;
     153                 :         }
     154                 :       }
     155                 :     }
     156                 :   }
     157                 : 
     158                 :   // Make sure to do this _after_ making all the OnChannelRedirect calls
     159               0 :   mRedirectChannel->SetOriginalURI(OriginalURI());
     160                 : 
     161                 :   // If we fail to open the new channel, then we want to leave this channel
     162                 :   // unaffected, so we defer tearing down our channel until we have succeeded
     163                 :   // with the redirect.
     164                 : 
     165               0 :   if (mOpenRedirectChannel) {
     166               0 :     nsresult rv = mRedirectChannel->AsyncOpen(mListener, mListenerContext);
     167               0 :     if (NS_FAILED(rv))
     168               0 :       return rv;
     169                 :   }
     170                 : 
     171               0 :   mRedirectChannel = nsnull;
     172                 : 
     173                 :   // close down this channel
     174               0 :   Cancel(NS_BINDING_REDIRECTED);
     175               0 :   mListener = nsnull;
     176               0 :   mListenerContext = nsnull;
     177                 : 
     178               0 :   return NS_OK;
     179                 : }
     180                 : 
     181                 : bool
     182            2863 : nsBaseChannel::HasContentTypeHint() const
     183                 : {
     184            2863 :   NS_ASSERTION(!IsPending(), "HasContentTypeHint called too late");
     185            2863 :   return !mContentType.EqualsLiteral(UNKNOWN_CONTENT_TYPE);
     186                 : }
     187                 : 
     188                 : void
     189            3284 : nsBaseChannel::SetContentLength64(PRInt64 len)
     190                 : {
     191                 :   // XXX: Storing the content-length as a property may not be what we want.
     192                 :   //      It has the drawback of being copied if we redirect this channel.
     193                 :   //      Maybe it is time for nsIChannel2.
     194            3284 :   SetPropertyAsInt64(NS_CHANNEL_PROP_CONTENT_LENGTH, len);
     195            3284 : }
     196                 : 
     197                 : PRInt64
     198            3394 : nsBaseChannel::ContentLength64()
     199                 : {
     200                 :   PRInt64 len;
     201            3394 :   nsresult rv = GetPropertyAsInt64(NS_CHANNEL_PROP_CONTENT_LENGTH, &len);
     202            3394 :   return NS_SUCCEEDED(rv) ? len : -1;
     203                 : }
     204                 : 
     205                 : nsresult
     206              17 : nsBaseChannel::PushStreamConverter(const char *fromType,
     207                 :                                    const char *toType,
     208                 :                                    bool invalidatesContentLength,
     209                 :                                    nsIStreamListener **result)
     210                 : {
     211              17 :   NS_ASSERTION(mListener, "no listener");
     212                 : 
     213                 :   nsresult rv;
     214                 :   nsCOMPtr<nsIStreamConverterService> scs =
     215              34 :       do_GetService(NS_STREAMCONVERTERSERVICE_CONTRACTID, &rv);
     216              17 :   if (NS_FAILED(rv))
     217               0 :     return rv;
     218                 : 
     219              34 :   nsCOMPtr<nsIStreamListener> converter;
     220              17 :   rv = scs->AsyncConvertData(fromType, toType, mListener, mListenerContext,
     221              17 :                              getter_AddRefs(converter));
     222              17 :   if (NS_SUCCEEDED(rv)) {
     223              17 :     mListener = converter;
     224              17 :     if (invalidatesContentLength)
     225              17 :       SetContentLength64(-1);
     226              17 :     if (result) {
     227               0 :       *result = nsnull;
     228               0 :       converter.swap(*result);
     229                 :     }
     230                 :   }
     231              17 :   return rv;
     232                 : }
     233                 : 
     234                 : nsresult
     235             190 : nsBaseChannel::BeginPumpingData()
     236                 : {
     237             380 :   nsCOMPtr<nsIInputStream> stream;
     238             380 :   nsCOMPtr<nsIChannel> channel;
     239             190 :   nsresult rv = OpenContentStream(true, getter_AddRefs(stream),
     240             380 :                                   getter_AddRefs(channel));
     241             190 :   if (NS_FAILED(rv))
     242               0 :     return rv;
     243                 : 
     244             190 :   NS_ASSERTION(!stream || !channel, "Got both a channel and a stream?");
     245                 : 
     246             190 :   if (channel) {
     247               0 :       rv = NS_DispatchToCurrentThread(new RedirectRunnable(this, channel));
     248               0 :       if (NS_SUCCEEDED(rv))
     249               0 :           mWaitingOnAsyncRedirect = true;
     250               0 :       return rv;
     251                 :   }
     252                 : 
     253                 :   // By assigning mPump, we flag this channel as pending (see IsPending).  It's
     254                 :   // important that the pending flag is set when we call into the stream (the
     255                 :   // call to AsyncRead results in the stream's AsyncWait method being called)
     256                 :   // and especially when we call into the loadgroup.  Our caller takes care to
     257                 :   // release mPump if we return an error.
     258                 :  
     259             190 :   rv = nsInputStreamPump::Create(getter_AddRefs(mPump), stream, -1, -1, 0, 0,
     260             380 :                                  true);
     261             190 :   if (NS_SUCCEEDED(rv))
     262             190 :     rv = mPump->AsyncRead(this, nsnull);
     263                 : 
     264             190 :   return rv;
     265                 : }
     266                 : 
     267                 : void
     268               0 : nsBaseChannel::HandleAsyncRedirect(nsIChannel* newChannel)
     269                 : {
     270               0 :   NS_ASSERTION(!mPump, "Shouldn't have gotten here");
     271                 : 
     272               0 :   nsresult rv = mStatus;
     273               0 :   if (NS_SUCCEEDED(mStatus)) {
     274                 :     rv = Redirect(newChannel,
     275                 :                   nsIChannelEventSink::REDIRECT_TEMPORARY,
     276               0 :                   true);
     277               0 :     if (NS_SUCCEEDED(rv)) {
     278                 :       // OnRedirectVerifyCallback will be called asynchronously
     279               0 :       return;
     280                 :     }
     281                 :   }
     282                 : 
     283               0 :   ContinueHandleAsyncRedirect(rv);
     284                 : }
     285                 : 
     286                 : void
     287               0 : nsBaseChannel::ContinueHandleAsyncRedirect(nsresult result)
     288                 : {
     289               0 :   mWaitingOnAsyncRedirect = false;
     290                 : 
     291               0 :   if (NS_FAILED(result))
     292               0 :     Cancel(result);
     293                 : 
     294               0 :   if (NS_FAILED(result) && mListener) {
     295                 :     // Notify our consumer ourselves
     296               0 :     mListener->OnStartRequest(this, mListenerContext);
     297               0 :     mListener->OnStopRequest(this, mListenerContext, mStatus);
     298               0 :     mListener = nsnull;
     299               0 :     mListenerContext = nsnull;
     300                 :   }
     301                 : 
     302               0 :   if (mLoadGroup)
     303               0 :     mLoadGroup->RemoveRequest(this, nsnull, mStatus);
     304                 : 
     305                 :   // Drop notification callbacks to prevent cycles.
     306               0 :   mCallbacks = nsnull;
     307               0 :   CallbacksChanged();
     308               0 : }
     309                 : 
     310                 : void
     311            3284 : nsBaseChannel::ClassifyURI()
     312                 : {
     313                 :   nsresult rv;
     314                 : 
     315            3284 :   if (mLoadFlags & LOAD_CLASSIFY_URI) {
     316               0 :     nsRefPtr<nsChannelClassifier> classifier = new nsChannelClassifier();
     317               0 :     if (classifier) {
     318               0 :       rv = classifier->Start(this);
     319               0 :       if (NS_FAILED(rv)) {
     320               0 :         Cancel(rv);
     321                 :       }
     322                 :     } else {
     323               0 :       Cancel(NS_ERROR_OUT_OF_MEMORY);
     324                 :     }
     325                 :   }
     326            3284 : }
     327                 : 
     328                 : //-----------------------------------------------------------------------------
     329                 : // nsBaseChannel::nsISupports
     330                 : 
     331          395619 : NS_IMPL_ISUPPORTS_INHERITED7(nsBaseChannel,
     332                 :                              nsHashPropertyBag,
     333                 :                              nsIRequest,
     334                 :                              nsIChannel,
     335                 :                              nsIInterfaceRequestor,
     336                 :                              nsITransportEventSink,
     337                 :                              nsIRequestObserver,
     338                 :                              nsIStreamListener,
     339                 :                              nsIAsyncVerifyRedirectCallback)
     340                 : 
     341                 : //-----------------------------------------------------------------------------
     342                 : // nsBaseChannel::nsIRequest
     343                 : 
     344                 : NS_IMETHODIMP
     345               4 : nsBaseChannel::GetName(nsACString &result)
     346                 : {
     347               4 :   if (!mURI) {
     348               0 :     result.Truncate();
     349               0 :     return NS_OK;
     350                 :   }
     351               4 :   return mURI->GetSpec(result);
     352                 : }
     353                 : 
     354                 : NS_IMETHODIMP
     355              24 : nsBaseChannel::IsPending(bool *result)
     356                 : {
     357              24 :   *result = IsPending();
     358              24 :   return NS_OK;
     359                 : }
     360                 : 
     361                 : NS_IMETHODIMP
     362            2233 : nsBaseChannel::GetStatus(nsresult *status)
     363                 : {
     364            2233 :   if (mPump && NS_SUCCEEDED(mStatus)) {
     365               2 :     mPump->GetStatus(status);
     366                 :   } else {
     367            2231 :     *status = mStatus;
     368                 :   }
     369            2233 :   return NS_OK;
     370                 : }
     371                 : 
     372                 : NS_IMETHODIMP
     373               5 : nsBaseChannel::Cancel(nsresult status)
     374                 : {
     375                 :   // Ignore redundant cancelation
     376               5 :   if (NS_FAILED(mStatus))
     377               0 :     return NS_OK;
     378                 : 
     379               5 :   mStatus = status;
     380                 : 
     381               5 :   if (mPump)
     382               5 :     mPump->Cancel(status);
     383                 : 
     384               5 :   return NS_OK;
     385                 : }
     386                 : 
     387                 : NS_IMETHODIMP
     388               0 : nsBaseChannel::Suspend()
     389                 : {
     390               0 :   NS_ENSURE_TRUE(mPump, NS_ERROR_NOT_INITIALIZED);
     391               0 :   return mPump->Suspend();
     392                 : }
     393                 : 
     394                 : NS_IMETHODIMP
     395               0 : nsBaseChannel::Resume()
     396                 : {
     397               0 :   NS_ENSURE_TRUE(mPump, NS_ERROR_NOT_INITIALIZED);
     398               0 :   return mPump->Resume();
     399                 : }
     400                 : 
     401                 : NS_IMETHODIMP
     402           49796 : nsBaseChannel::GetLoadFlags(nsLoadFlags *aLoadFlags)
     403                 : {
     404           49796 :   *aLoadFlags = mLoadFlags;
     405           49796 :   return NS_OK;
     406                 : }
     407                 : 
     408                 : NS_IMETHODIMP
     409           49790 : nsBaseChannel::SetLoadFlags(nsLoadFlags aLoadFlags)
     410                 : {
     411           49790 :   mLoadFlags = aLoadFlags;
     412           49790 :   return NS_OK;
     413                 : }
     414                 : 
     415                 : NS_IMETHODIMP
     416               6 : nsBaseChannel::GetLoadGroup(nsILoadGroup **aLoadGroup)
     417                 : {
     418               6 :   NS_IF_ADDREF(*aLoadGroup = mLoadGroup);
     419               6 :   return NS_OK;
     420                 : }
     421                 : 
     422                 : NS_IMETHODIMP
     423               4 : nsBaseChannel::SetLoadGroup(nsILoadGroup *aLoadGroup)
     424                 : {
     425               4 :   mLoadGroup = aLoadGroup;
     426               4 :   CallbacksChanged();
     427               4 :   return NS_OK;
     428                 : }
     429                 : 
     430                 : //-----------------------------------------------------------------------------
     431                 : // nsBaseChannel::nsIChannel
     432                 : 
     433                 : NS_IMETHODIMP
     434              11 : nsBaseChannel::GetOriginalURI(nsIURI **aURI)
     435                 : {
     436              11 :   *aURI = OriginalURI();
     437              11 :   NS_ADDREF(*aURI);
     438              11 :   return NS_OK;
     439                 : }
     440                 : 
     441                 : NS_IMETHODIMP
     442           49682 : nsBaseChannel::SetOriginalURI(nsIURI *aURI)
     443                 : {
     444           49682 :   NS_ENSURE_ARG_POINTER(aURI);
     445           49682 :   mOriginalURI = aURI;
     446           49682 :   return NS_OK;
     447                 : }
     448                 : 
     449                 : NS_IMETHODIMP
     450           47568 : nsBaseChannel::GetURI(nsIURI **aURI)
     451                 : {
     452           47568 :   NS_IF_ADDREF(*aURI = mURI);
     453           47568 :   return NS_OK;
     454                 : }
     455                 : 
     456                 : NS_IMETHODIMP
     457               6 : nsBaseChannel::GetOwner(nsISupports **aOwner)
     458                 : {
     459               6 :   NS_IF_ADDREF(*aOwner = mOwner);
     460               6 :   return NS_OK;
     461                 : }
     462                 : 
     463                 : NS_IMETHODIMP
     464             737 : nsBaseChannel::SetOwner(nsISupports *aOwner)
     465                 : {
     466             737 :   mOwner = aOwner;
     467             737 :   return NS_OK;
     468                 : }
     469                 : 
     470                 : NS_IMETHODIMP
     471              23 : nsBaseChannel::GetNotificationCallbacks(nsIInterfaceRequestor **aCallbacks)
     472                 : {
     473              23 :   NS_IF_ADDREF(*aCallbacks = mCallbacks);
     474              23 :   return NS_OK;
     475                 : }
     476                 : 
     477                 : NS_IMETHODIMP
     478             152 : nsBaseChannel::SetNotificationCallbacks(nsIInterfaceRequestor *aCallbacks)
     479                 : {
     480             152 :   mCallbacks = aCallbacks;
     481             152 :   CallbacksChanged();
     482             152 :   return NS_OK;
     483                 : }
     484                 : 
     485                 : NS_IMETHODIMP 
     486               4 : nsBaseChannel::GetSecurityInfo(nsISupports **aSecurityInfo)
     487                 : {
     488               4 :   NS_IF_ADDREF(*aSecurityInfo = mSecurityInfo);
     489               4 :   return NS_OK;
     490                 : }
     491                 : 
     492                 : NS_IMETHODIMP
     493            3573 : nsBaseChannel::GetContentType(nsACString &aContentType)
     494                 : {
     495            3573 :   aContentType = mContentType;
     496            3573 :   return NS_OK;
     497                 : }
     498                 : 
     499                 : NS_IMETHODIMP
     500            6586 : nsBaseChannel::SetContentType(const nsACString &aContentType)
     501                 : {
     502                 :   // mContentCharset is unchanged if not parsed
     503                 :   bool dummy;
     504            6586 :   net_ParseContentType(aContentType, mContentType, mContentCharset, &dummy);
     505            6586 :   return NS_OK;
     506                 : }
     507                 : 
     508                 : NS_IMETHODIMP
     509             778 : nsBaseChannel::GetContentCharset(nsACString &aContentCharset)
     510                 : {
     511             778 :   aContentCharset = mContentCharset;
     512             778 :   return NS_OK;
     513                 : }
     514                 : 
     515                 : NS_IMETHODIMP
     516             973 : nsBaseChannel::SetContentCharset(const nsACString &aContentCharset)
     517                 : {
     518             973 :   mContentCharset = aContentCharset;
     519             973 :   return NS_OK;
     520                 : }
     521                 : 
     522                 : NS_IMETHODIMP
     523               0 : nsBaseChannel::GetContentDisposition(PRUint32 *aContentDisposition)
     524                 : {
     525               0 :   return NS_ERROR_NOT_AVAILABLE;
     526                 : }
     527                 : 
     528                 : NS_IMETHODIMP
     529               0 : nsBaseChannel::GetContentDispositionFilename(nsAString &aContentDispositionFilename)
     530                 : {
     531               0 :   return NS_ERROR_NOT_AVAILABLE;
     532                 : }
     533                 : 
     534                 : NS_IMETHODIMP
     535             575 : nsBaseChannel::GetContentDispositionHeader(nsACString &aContentDispositionHeader)
     536                 : {
     537             575 :   return NS_ERROR_NOT_AVAILABLE;
     538                 : }
     539                 : 
     540                 : NS_IMETHODIMP
     541             487 : nsBaseChannel::GetContentLength(PRInt32 *aContentLength)
     542                 : {
     543             487 :   PRInt64 len = ContentLength64();
     544             487 :   if (len > PR_INT32_MAX || len < 0)
     545               0 :     *aContentLength = -1;
     546                 :   else
     547             487 :     *aContentLength = (PRInt32) len;
     548             487 :   return NS_OK;
     549                 : }
     550                 : 
     551                 : NS_IMETHODIMP
     552               0 : nsBaseChannel::SetContentLength(PRInt32 aContentLength)
     553                 : {
     554               0 :   SetContentLength64(aContentLength);
     555               0 :   return NS_OK;
     556                 : }
     557                 : 
     558                 : NS_IMETHODIMP
     559            3166 : nsBaseChannel::Open(nsIInputStream **result)
     560                 : {
     561            3166 :   NS_ENSURE_TRUE(mURI, NS_ERROR_NOT_INITIALIZED);
     562            3166 :   NS_ENSURE_TRUE(!mPump, NS_ERROR_IN_PROGRESS);
     563            3164 :   NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_IN_PROGRESS);
     564                 : 
     565            6324 :   nsCOMPtr<nsIChannel> chan;
     566            3162 :   nsresult rv = OpenContentStream(false, result, getter_AddRefs(chan));
     567            3162 :   NS_ASSERTION(!chan || !*result, "Got both a channel and a stream?");
     568            3162 :   if (NS_SUCCEEDED(rv) && chan) {
     569               0 :       rv = Redirect(chan, nsIChannelEventSink::REDIRECT_INTERNAL, false);
     570               0 :       if (NS_FAILED(rv))
     571               0 :           return rv;
     572               0 :       rv = chan->Open(result);
     573            3162 :   } else if (rv == NS_ERROR_NOT_IMPLEMENTED)
     574              17 :     return NS_ImplementChannelOpen(this, result);
     575                 : 
     576            3145 :   if (NS_SUCCEEDED(rv)) {
     577            3094 :     mWasOpened = true;
     578            3094 :     ClassifyURI();
     579                 :   }
     580                 : 
     581            3145 :   return rv;
     582                 : }
     583                 : 
     584                 : NS_IMETHODIMP
     585             201 : nsBaseChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt)
     586                 : {
     587             201 :   NS_ENSURE_TRUE(mURI, NS_ERROR_NOT_INITIALIZED);
     588             201 :   NS_ENSURE_TRUE(!mPump, NS_ERROR_IN_PROGRESS);
     589             196 :   NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
     590             190 :   NS_ENSURE_ARG(listener);
     591                 : 
     592                 :   // Ensure that this is an allowed port before proceeding.
     593             190 :   nsresult rv = NS_CheckPortSafety(mURI);
     594             190 :   if (NS_FAILED(rv)) {
     595               0 :     mCallbacks = nsnull;
     596               0 :     return rv;
     597                 :   }
     598                 : 
     599                 :   // Store the listener and context early so that OpenContentStream and the
     600                 :   // stream's AsyncWait method (called by AsyncRead) can have access to them
     601                 :   // via PushStreamConverter and the StreamListener methods.  However, since
     602                 :   // this typically introduces a reference cycle between this and the listener,
     603                 :   // we need to be sure to break the reference if this method does not succeed.
     604             190 :   mListener = listener;
     605             190 :   mListenerContext = ctxt;
     606                 : 
     607                 :   // This method assigns mPump as a side-effect.  We need to clear mPump if
     608                 :   // this method fails.
     609             190 :   rv = BeginPumpingData();
     610             190 :   if (NS_FAILED(rv)) {
     611               0 :     mPump = nsnull;
     612               0 :     mListener = nsnull;
     613               0 :     mListenerContext = nsnull;
     614               0 :     mCallbacks = nsnull;
     615               0 :     return rv;
     616                 :   }
     617                 : 
     618                 :   // At this point, we are going to return success no matter what.
     619                 : 
     620             190 :   mWasOpened = true;
     621                 : 
     622             380 :   SUSPEND_PUMP_FOR_SCOPE();
     623                 : 
     624             190 :   if (mLoadGroup)
     625               2 :     mLoadGroup->AddRequest(this, nsnull);
     626                 : 
     627             190 :   ClassifyURI();
     628                 : 
     629             190 :   return NS_OK;
     630                 : }
     631                 : 
     632                 : //-----------------------------------------------------------------------------
     633                 : // nsBaseChannel::nsITransportEventSink
     634                 : 
     635                 : NS_IMETHODIMP
     636              61 : nsBaseChannel::OnTransportStatus(nsITransport *transport, nsresult status,
     637                 :                                  PRUint64 progress, PRUint64 progressMax)
     638                 : {
     639                 :   // In some cases, we may wish to suppress transport-layer status events.
     640                 : 
     641              61 :   if (!mPump || NS_FAILED(mStatus) || HasLoadFlag(LOAD_BACKGROUND))
     642               3 :     return NS_OK;
     643                 : 
     644             116 :   SUSPEND_PUMP_FOR_SCOPE();
     645                 : 
     646                 :   // Lazily fetch mProgressSink
     647              58 :   if (!mProgressSink) {
     648              58 :     if (mQueriedProgressSink)
     649              29 :       return NS_OK;
     650              29 :     GetCallback(mProgressSink);
     651              29 :     mQueriedProgressSink = true;
     652              29 :     if (!mProgressSink)
     653              29 :       return NS_OK;
     654                 :   }
     655                 : 
     656               0 :   nsAutoString statusArg;
     657               0 :   if (GetStatusArg(status, statusArg))
     658               0 :     mProgressSink->OnStatus(this, mListenerContext, status, statusArg.get());
     659                 : 
     660               0 :   if (progress)
     661               0 :     mProgressSink->OnProgress(this, mListenerContext, progress, progressMax);
     662                 : 
     663               0 :   return NS_OK;
     664                 : }
     665                 : 
     666                 : //-----------------------------------------------------------------------------
     667                 : // nsBaseChannel::nsIInterfaceRequestor
     668                 : 
     669                 : NS_IMETHODIMP
     670              29 : nsBaseChannel::GetInterface(const nsIID &iid, void **result)
     671                 : {
     672              29 :   NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup, iid, result);
     673              29 :   return *result ? NS_OK : NS_ERROR_NO_INTERFACE; 
     674                 : }
     675                 : 
     676                 : //-----------------------------------------------------------------------------
     677                 : // nsBaseChannel::nsIRequestObserver
     678                 : 
     679                 : static void
     680               3 : CallTypeSniffers(void *aClosure, const PRUint8 *aData, PRUint32 aCount)
     681                 : {
     682               3 :   nsIChannel *chan = static_cast<nsIChannel*>(aClosure);
     683                 : 
     684                 :   const nsCOMArray<nsIContentSniffer>& sniffers =
     685               3 :     gIOService->GetContentSniffers();
     686               3 :   PRUint32 length = sniffers.Count();
     687               9 :   for (PRUint32 i = 0; i < length; ++i) {
     688              16 :     nsCAutoString newType;
     689                 :     nsresult rv =
     690               8 :       sniffers[i]->GetMIMETypeFromContent(chan, aData, aCount, newType);
     691               8 :     if (NS_SUCCEEDED(rv) && !newType.IsEmpty()) {
     692               2 :       chan->SetContentType(newType);
     693                 :       break;
     694                 :     }
     695                 :   }
     696               3 : }
     697                 : 
     698                 : static void
     699               8 : CallUnknownTypeSniffer(void *aClosure, const PRUint8 *aData, PRUint32 aCount)
     700                 : {
     701               8 :   nsIChannel *chan = static_cast<nsIChannel*>(aClosure);
     702                 : 
     703                 :   nsCOMPtr<nsIContentSniffer> sniffer =
     704              16 :     do_CreateInstance(NS_GENERIC_CONTENT_SNIFFER);
     705               8 :   if (!sniffer)
     706                 :     return;
     707                 : 
     708              16 :   nsCAutoString detected;
     709               8 :   nsresult rv = sniffer->GetMIMETypeFromContent(chan, aData, aCount, detected);
     710               8 :   if (NS_SUCCEEDED(rv))
     711               8 :     chan->SetContentType(detected);
     712                 : }
     713                 : 
     714                 : NS_IMETHODIMP
     715             190 : nsBaseChannel::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
     716                 : {
     717                 :   // If our content type is unknown, then use the content type sniffer.  If the
     718                 :   // sniffer is not available for some reason, then we just keep going as-is.
     719             190 :   if (NS_SUCCEEDED(mStatus) && mContentType.EqualsLiteral(UNKNOWN_CONTENT_TYPE)) {
     720               8 :     mPump->PeekStream(CallUnknownTypeSniffer, static_cast<nsIChannel*>(this));
     721                 :   }
     722                 : 
     723                 :   // Now, the general type sniffers. Skip this if we have none.
     724             193 :   if ((mLoadFlags & LOAD_CALL_CONTENT_SNIFFERS) &&
     725               3 :       gIOService->GetContentSniffers().Count() != 0)
     726               3 :     mPump->PeekStream(CallTypeSniffers, static_cast<nsIChannel*>(this));
     727                 : 
     728             380 :   SUSPEND_PUMP_FOR_SCOPE();
     729                 : 
     730             190 :   return mListener->OnStartRequest(this, mListenerContext);
     731                 : }
     732                 : 
     733                 : NS_IMETHODIMP
     734             190 : nsBaseChannel::OnStopRequest(nsIRequest *request, nsISupports *ctxt,
     735                 :                              nsresult status)
     736                 : {
     737                 :   // If both mStatus and status are failure codes, we keep mStatus as-is since
     738                 :   // that is consistent with our GetStatus and Cancel methods.
     739             190 :   if (NS_SUCCEEDED(mStatus))
     740             185 :     mStatus = status;
     741                 : 
     742                 :   // Cause IsPending to return false.
     743             190 :   mPump = nsnull;
     744                 : 
     745             190 :   mListener->OnStopRequest(this, mListenerContext, mStatus);
     746             190 :   mListener = nsnull;
     747             190 :   mListenerContext = nsnull;
     748                 : 
     749                 :   // No need to suspend pump in this scope since we will not be receiving
     750                 :   // any more events from it.
     751                 : 
     752             190 :   if (mLoadGroup)
     753               2 :     mLoadGroup->RemoveRequest(this, nsnull, mStatus);
     754                 : 
     755                 :   // Drop notification callbacks to prevent cycles.
     756             190 :   mCallbacks = nsnull;
     757             190 :   CallbacksChanged();
     758                 : 
     759             190 :   return NS_OK;
     760                 : }
     761                 : 
     762                 : //-----------------------------------------------------------------------------
     763                 : // nsBaseChannel::nsIStreamListener
     764                 : 
     765                 : NS_IMETHODIMP
     766             179 : nsBaseChannel::OnDataAvailable(nsIRequest *request, nsISupports *ctxt,
     767                 :                                nsIInputStream *stream, PRUint32 offset,
     768                 :                                PRUint32 count)
     769                 : {
     770             358 :   SUSPEND_PUMP_FOR_SCOPE();
     771                 : 
     772             179 :   nsresult rv = mListener->OnDataAvailable(this, mListenerContext, stream,
     773             179 :                                            offset, count);
     774             179 :   if (mSynthProgressEvents && NS_SUCCEEDED(rv)) {
     775              41 :     PRUint64 prog = PRUint64(offset) + count;
     776              41 :     PRUint64 progMax = ContentLength64();
     777              41 :     OnTransportStatus(nsnull, nsITransport::STATUS_READING, prog, progMax);
     778                 :   }
     779                 : 
     780             179 :   return rv;
     781                 : }
     782                 : 
     783                 : NS_IMETHODIMP
     784               0 : nsBaseChannel::OnRedirectVerifyCallback(nsresult result)
     785                 : {
     786               0 :   if (NS_SUCCEEDED(result))
     787               0 :     result = ContinueRedirect();
     788                 : 
     789               0 :   if (NS_FAILED(result) && !mWaitingOnAsyncRedirect) {
     790               0 :     if (NS_SUCCEEDED(mStatus))
     791               0 :       mStatus = result;
     792               0 :     return NS_OK;
     793                 :   }
     794                 : 
     795               0 :   if (mWaitingOnAsyncRedirect)
     796               0 :     ContinueHandleAsyncRedirect(result);
     797                 : 
     798               0 :   return NS_OK;
     799                 : }

Generated by: LCOV version 1.7