LCOV - code coverage report
Current view: directory - netwerk/base/src - nsInputStreamPump.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 224 189 84.4 %
Date: 2012-06-02 Functions: 26 20 76.9 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2                 : /* vim:set ts=4 sts=4 sw=4 et cin: */
       3                 : /* ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is mozilla.org code.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is
      19                 :  * Netscape Communications Corporation.
      20                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      21                 :  * the Initial Developer. All Rights Reserved.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      27                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : 
      39                 : #include "nsIOService.h"
      40                 : #include "nsInputStreamPump.h"
      41                 : #include "nsIServiceManager.h"
      42                 : #include "nsIStreamTransportService.h"
      43                 : #include "nsIInterfaceRequestorUtils.h"
      44                 : #include "nsISeekableStream.h"
      45                 : #include "nsITransport.h"
      46                 : #include "nsNetUtil.h"
      47                 : #include "nsThreadUtils.h"
      48                 : #include "nsCOMPtr.h"
      49                 : #include "prlog.h"
      50                 : #include "sampler.h"
      51                 : 
      52                 : static NS_DEFINE_CID(kStreamTransportServiceCID, NS_STREAMTRANSPORTSERVICE_CID);
      53                 : 
      54                 : #if defined(PR_LOGGING)
      55                 : //
      56                 : // NSPR_LOG_MODULES=nsStreamPump:5
      57                 : //
      58                 : static PRLogModuleInfo *gStreamPumpLog = nsnull;
      59                 : #endif
      60                 : #define LOG(args) PR_LOG(gStreamPumpLog, PR_LOG_DEBUG, args)
      61                 : 
      62                 : //-----------------------------------------------------------------------------
      63                 : // nsInputStreamPump methods
      64                 : //-----------------------------------------------------------------------------
      65                 : 
      66            3499 : nsInputStreamPump::nsInputStreamPump()
      67                 :     : mState(STATE_IDLE)
      68                 :     , mStreamOffset(0)
      69            3499 :     , mStreamLength(LL_MaxUint())
      70                 :     , mStatus(NS_OK)
      71                 :     , mSuspendCount(0)
      72                 :     , mLoadFlags(LOAD_NORMAL)
      73                 :     , mWaiting(false)
      74            6998 :     , mCloseWhenDone(false)
      75                 : {
      76                 : #if defined(PR_LOGGING)
      77            3499 :     if (!gStreamPumpLog)
      78             341 :         gStreamPumpLog = PR_NewLogModule("nsStreamPump");
      79                 : #endif
      80            3499 : }
      81                 : 
      82            3487 : nsInputStreamPump::~nsInputStreamPump()
      83                 : {
      84            3487 : }
      85                 : 
      86                 : nsresult
      87            3396 : nsInputStreamPump::Create(nsInputStreamPump  **result,
      88                 :                           nsIInputStream      *stream,
      89                 :                           PRInt64              streamPos,
      90                 :                           PRInt64              streamLen,
      91                 :                           PRUint32             segsize,
      92                 :                           PRUint32             segcount,
      93                 :                           bool                 closeWhenDone)
      94                 : {
      95            3396 :     nsresult rv = NS_ERROR_OUT_OF_MEMORY;
      96            6792 :     nsRefPtr<nsInputStreamPump> pump = new nsInputStreamPump();
      97            3396 :     if (pump) {
      98            3396 :         rv = pump->Init(stream, streamPos, streamLen,
      99            3396 :                         segsize, segcount, closeWhenDone);
     100            3396 :         if (NS_SUCCEEDED(rv)) {
     101            3396 :             *result = nsnull;
     102            3396 :             pump.swap(*result);
     103                 :         }
     104                 :     }
     105            3396 :     return rv;
     106                 : }
     107                 : 
     108                 : struct PeekData {
     109              12 :   PeekData(nsInputStreamPump::PeekSegmentFun fun, void* closure)
     110              12 :     : mFunc(fun), mClosure(closure) {}
     111                 : 
     112                 :   nsInputStreamPump::PeekSegmentFun mFunc;
     113                 :   void* mClosure;
     114                 : };
     115                 : 
     116                 : static NS_METHOD
     117              12 : CallPeekFunc(nsIInputStream *aInStream, void *aClosure,
     118                 :              const char *aFromSegment, PRUint32 aToOffset, PRUint32 aCount,
     119                 :              PRUint32 *aWriteCount)
     120                 : {
     121              12 :   NS_ASSERTION(aToOffset == 0, "Called more than once?");
     122              12 :   NS_ASSERTION(aCount > 0, "Called without data?");
     123                 : 
     124              12 :   PeekData* data = static_cast<PeekData*>(aClosure);
     125                 :   data->mFunc(data->mClosure,
     126              12 :               reinterpret_cast<const PRUint8*>(aFromSegment), aCount);
     127              12 :   return NS_BINDING_ABORTED;
     128                 : }
     129                 : 
     130                 : nsresult
     131              12 : nsInputStreamPump::PeekStream(PeekSegmentFun callback, void* closure)
     132                 : {
     133              12 :   NS_ASSERTION(mAsyncStream, "PeekStream called without stream");
     134                 : 
     135                 :   // See if the pipe is closed by checking the return of Available.
     136                 :   PRUint32 dummy;
     137              12 :   nsresult rv = mAsyncStream->Available(&dummy);
     138              12 :   if (NS_FAILED(rv))
     139               0 :     return rv;
     140                 : 
     141              12 :   PeekData data(callback, closure);
     142              12 :   return mAsyncStream->ReadSegments(CallPeekFunc,
     143                 :                                     &data,
     144                 :                                     nsIOService::gDefaultSegmentSize,
     145              12 :                                     &dummy);
     146                 : }
     147                 : 
     148                 : nsresult
     149            5378 : nsInputStreamPump::EnsureWaiting()
     150                 : {
     151                 :     // no need to worry about multiple threads... an input stream pump lives
     152                 :     // on only one thread.
     153                 : 
     154            5378 :     if (!mWaiting) {
     155            4753 :         nsresult rv = mAsyncStream->AsyncWait(this, 0, 0, mTargetThread);
     156            4753 :         if (NS_FAILED(rv)) {
     157               0 :             NS_ERROR("AsyncWait failed");
     158               0 :             return rv;
     159                 :         }
     160            4753 :         mWaiting = true;
     161                 :     }
     162            5378 :     return NS_OK;
     163                 : }
     164                 : 
     165                 : //-----------------------------------------------------------------------------
     166                 : // nsInputStreamPump::nsISupports
     167                 : //-----------------------------------------------------------------------------
     168                 : 
     169                 : // although this class can only be accessed from one thread at a time, we do
     170                 : // allow its ownership to move from thread to thread, assuming the consumer
     171                 : // understands the limitations of this.
     172           39718 : NS_IMPL_THREADSAFE_ISUPPORTS3(nsInputStreamPump,
     173                 :                               nsIRequest,
     174                 :                               nsIInputStreamCallback,
     175                 :                               nsIInputStreamPump)
     176                 : 
     177                 : //-----------------------------------------------------------------------------
     178                 : // nsInputStreamPump::nsIRequest
     179                 : //-----------------------------------------------------------------------------
     180                 : 
     181                 : NS_IMETHODIMP
     182               0 : nsInputStreamPump::GetName(nsACString &result)
     183                 : {
     184               0 :     result.Truncate();
     185               0 :     return NS_OK;
     186                 : }
     187                 : 
     188                 : NS_IMETHODIMP
     189               0 : nsInputStreamPump::IsPending(bool *result)
     190                 : {
     191               0 :     *result = (mState != STATE_IDLE);
     192               0 :     return NS_OK;
     193                 : }
     194                 : 
     195                 : NS_IMETHODIMP
     196            3191 : nsInputStreamPump::GetStatus(nsresult *status)
     197                 : {
     198            3191 :     *status = mStatus;
     199            3191 :     return NS_OK;
     200                 : }
     201                 : 
     202                 : NS_IMETHODIMP
     203             171 : nsInputStreamPump::Cancel(nsresult status)
     204                 : {
     205             171 :     LOG(("nsInputStreamPump::Cancel [this=%x status=%x]\n",
     206                 :         this, status));
     207                 : 
     208             171 :     if (NS_FAILED(mStatus)) {
     209               1 :         LOG(("  already canceled\n"));
     210               1 :         return NS_OK;
     211                 :     }
     212                 : 
     213             170 :     NS_ASSERTION(NS_FAILED(status), "cancel with non-failure status code");
     214             170 :     mStatus = status;
     215                 : 
     216                 :     // close input stream
     217             170 :     if (mAsyncStream) {
     218             170 :         mAsyncStream->CloseWithStatus(status);
     219             170 :         if (mSuspendCount == 0)
     220              43 :             EnsureWaiting();
     221                 :         // Otherwise, EnsureWaiting will be called by Resume().
     222                 :         // Note that while suspended, OnInputStreamReady will
     223                 :         // not do anything, and also note that calling asyncWait
     224                 :         // on a closed stream works and will dispatch an event immediately.
     225                 :     }
     226             170 :     return NS_OK;
     227                 : }
     228                 : 
     229                 : NS_IMETHODIMP
     230             778 : nsInputStreamPump::Suspend()
     231                 : {
     232             778 :     LOG(("nsInputStreamPump::Suspend [this=%x]\n", this));
     233             778 :     NS_ENSURE_TRUE(mState != STATE_IDLE, NS_ERROR_UNEXPECTED);
     234             778 :     ++mSuspendCount;
     235             778 :     return NS_OK;
     236                 : }
     237                 : 
     238                 : NS_IMETHODIMP
     239             778 : nsInputStreamPump::Resume()
     240                 : {
     241             778 :     LOG(("nsInputStreamPump::Resume [this=%x]\n", this));
     242             778 :     NS_ENSURE_TRUE(mSuspendCount > 0, NS_ERROR_UNEXPECTED);
     243             778 :     NS_ENSURE_TRUE(mState != STATE_IDLE, NS_ERROR_UNEXPECTED);
     244                 : 
     245             778 :     if (--mSuspendCount == 0)
     246             736 :         EnsureWaiting();
     247             778 :     return NS_OK;
     248                 : }
     249                 : 
     250                 : NS_IMETHODIMP
     251               0 : nsInputStreamPump::GetLoadFlags(nsLoadFlags *aLoadFlags)
     252                 : {
     253               0 :     *aLoadFlags = mLoadFlags;
     254               0 :     return NS_OK;
     255                 : }
     256                 : 
     257                 : NS_IMETHODIMP
     258               0 : nsInputStreamPump::SetLoadFlags(nsLoadFlags aLoadFlags)
     259                 : {
     260               0 :     mLoadFlags = aLoadFlags;
     261               0 :     return NS_OK;
     262                 : }
     263                 : 
     264                 : NS_IMETHODIMP
     265               0 : nsInputStreamPump::GetLoadGroup(nsILoadGroup **aLoadGroup)
     266                 : {
     267               0 :     NS_IF_ADDREF(*aLoadGroup = mLoadGroup);
     268               0 :     return NS_OK;
     269                 : }
     270                 : 
     271                 : NS_IMETHODIMP
     272               0 : nsInputStreamPump::SetLoadGroup(nsILoadGroup *aLoadGroup)
     273                 : {
     274               0 :     mLoadGroup = aLoadGroup;
     275               0 :     return NS_OK;
     276                 : }
     277                 : 
     278                 : //-----------------------------------------------------------------------------
     279                 : // nsInputStreamPump::nsIInputStreamPump implementation
     280                 : //-----------------------------------------------------------------------------
     281                 : 
     282                 : NS_IMETHODIMP
     283            3499 : nsInputStreamPump::Init(nsIInputStream *stream,
     284                 :                         PRInt64 streamPos, PRInt64 streamLen,
     285                 :                         PRUint32 segsize, PRUint32 segcount,
     286                 :                         bool closeWhenDone)
     287                 : {
     288            3499 :     NS_ENSURE_TRUE(mState == STATE_IDLE, NS_ERROR_IN_PROGRESS);
     289                 : 
     290            3499 :     mStreamOffset = PRUint64(streamPos);
     291            3499 :     if (PRInt64(streamLen) >= PRInt64(0))
     292               0 :         mStreamLength = PRUint64(streamLen);
     293            3499 :     mStream = stream;
     294            3499 :     mSegSize = segsize;
     295            3499 :     mSegCount = segcount;
     296            3499 :     mCloseWhenDone = closeWhenDone;
     297                 : 
     298            3499 :     return NS_OK;
     299                 : }
     300                 : 
     301                 : NS_IMETHODIMP
     302            3487 : nsInputStreamPump::AsyncRead(nsIStreamListener *listener, nsISupports *ctxt)
     303                 : {
     304            3487 :     NS_ENSURE_TRUE(mState == STATE_IDLE, NS_ERROR_IN_PROGRESS);
     305            3487 :     NS_ENSURE_ARG_POINTER(listener);
     306                 : 
     307                 :     //
     308                 :     // OK, we need to use the stream transport service if
     309                 :     //
     310                 :     // (1) the stream is blocking
     311                 :     // (2) the stream does not support nsIAsyncInputStream
     312                 :     //
     313                 : 
     314                 :     bool nonBlocking;
     315            3486 :     nsresult rv = mStream->IsNonBlocking(&nonBlocking);
     316            3486 :     if (NS_FAILED(rv)) return rv;
     317                 : 
     318            3486 :     if (nonBlocking) {
     319            3223 :         mAsyncStream = do_QueryInterface(mStream);
     320                 :         //
     321                 :         // if the stream supports nsIAsyncInputStream, and if we need to seek
     322                 :         // to a starting offset, then we must do so here.  in the non-async
     323                 :         // stream case, the stream transport service will take care of seeking
     324                 :         // for us.
     325                 :         // 
     326            3223 :         if (mAsyncStream && (mStreamOffset != LL_MAXUINT)) {
     327               0 :             nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mStream);
     328               0 :             if (seekable)
     329               0 :                 seekable->Seek(nsISeekableStream::NS_SEEK_SET, mStreamOffset);
     330                 :         }
     331                 :     }
     332                 : 
     333            3486 :     if (!mAsyncStream) {
     334                 :         // ok, let's use the stream transport service to read this stream.
     335                 :         nsCOMPtr<nsIStreamTransportService> sts =
     336             528 :             do_GetService(kStreamTransportServiceCID, &rv);
     337             264 :         if (NS_FAILED(rv)) return rv;
     338                 : 
     339             528 :         nsCOMPtr<nsITransport> transport;
     340             264 :         rv = sts->CreateInputTransport(mStream, mStreamOffset, mStreamLength,
     341             264 :                                        mCloseWhenDone, getter_AddRefs(transport));
     342             264 :         if (NS_FAILED(rv)) return rv;
     343                 : 
     344             528 :         nsCOMPtr<nsIInputStream> wrapper;
     345             264 :         rv = transport->OpenInputStream(0, mSegSize, mSegCount, getter_AddRefs(wrapper));
     346             264 :         if (NS_FAILED(rv)) return rv;
     347                 : 
     348             264 :         mAsyncStream = do_QueryInterface(wrapper, &rv);
     349             264 :         if (NS_FAILED(rv)) return rv;
     350                 :     }
     351                 : 
     352                 :     // release our reference to the original stream.  from this point forward,
     353                 :     // we only reference the "stream" via mAsyncStream.
     354            3486 :     mStream = 0;
     355                 : 
     356                 :     // mStreamOffset now holds the number of bytes currently read.  we use this
     357                 :     // to enforce the mStreamLength restriction.
     358            3486 :     mStreamOffset = 0;
     359                 : 
     360                 :     // grab event queue (we must do this here by contract, since all notifications
     361                 :     // must go to the thread which called AsyncRead)
     362            3486 :     mTargetThread = do_GetCurrentThread();
     363            3486 :     NS_ENSURE_STATE(mTargetThread);
     364                 : 
     365            3486 :     rv = EnsureWaiting();
     366            3486 :     if (NS_FAILED(rv)) return rv;
     367                 : 
     368            3486 :     if (mLoadGroup)
     369               0 :         mLoadGroup->AddRequest(this, nsnull);
     370                 : 
     371            3486 :     mState = STATE_START;
     372            3486 :     mListener = listener;
     373            3486 :     mListenerContext = ctxt;
     374            3486 :     return NS_OK;
     375                 : }
     376                 : 
     377                 : //-----------------------------------------------------------------------------
     378                 : // nsInputStreamPump::nsIInputStreamCallback implementation
     379                 : //-----------------------------------------------------------------------------
     380                 : 
     381                 : NS_IMETHODIMP
     382            4753 : nsInputStreamPump::OnInputStreamReady(nsIAsyncInputStream *stream)
     383                 : {
     384            4753 :     LOG(("nsInputStreamPump::OnInputStreamReady [this=%x]\n", this));
     385                 : 
     386            9506 :     SAMPLE_LABEL("Input", "nsInputStreamPump::OnInputStreamReady");
     387                 :     // this function has been called from a PLEvent, so we can safely call
     388                 :     // any listener or progress sink methods directly from here.
     389                 : 
     390           10265 :     for (;;) {
     391           15018 :         if (mSuspendCount || mState == STATE_IDLE) {
     392            3640 :             mWaiting = false;
     393            3640 :             break;
     394                 :         }
     395                 : 
     396                 :         PRUint32 nextState;
     397           11378 :         switch (mState) {
     398                 :         case STATE_START:
     399            3486 :             nextState = OnStateStart();
     400            3486 :             break;
     401                 :         case STATE_TRANSFER:
     402            4406 :             nextState = OnStateTransfer();
     403            4406 :             break;
     404                 :         case STATE_STOP:
     405            3486 :             nextState = OnStateStop();
     406            3486 :             break;
     407                 :         }
     408                 : 
     409           11378 :         if (mState == nextState && !mSuspendCount) {
     410            1113 :             NS_ASSERTION(mState == STATE_TRANSFER, "unexpected state");
     411            1113 :             NS_ASSERTION(NS_SUCCEEDED(mStatus), "unexpected status");
     412                 : 
     413            1113 :             mWaiting = false;
     414            1113 :             mStatus = EnsureWaiting();
     415            1113 :             if (NS_SUCCEEDED(mStatus))
     416            1113 :                 break;
     417                 :             
     418               0 :             nextState = STATE_STOP;
     419                 :         }
     420                 : 
     421           10265 :         mState = nextState;
     422                 :     }
     423            4753 :     return NS_OK;
     424                 : }
     425                 : 
     426                 : PRUint32
     427            3486 : nsInputStreamPump::OnStateStart()
     428                 : {
     429            6972 :     SAMPLE_LABEL("nsInputStreamPump", "OnStateStart");
     430            3486 :     LOG(("  OnStateStart [this=%x]\n", this));
     431                 : 
     432                 :     nsresult rv;
     433                 : 
     434                 :     // need to check the reason why the stream is ready.  this is required
     435                 :     // so our listener can check our status from OnStartRequest.
     436                 :     // XXX async streams should have a GetStatus method!
     437            3486 :     if (NS_SUCCEEDED(mStatus)) {
     438                 :         PRUint32 avail;
     439            3479 :         rv = mAsyncStream->Available(&avail);
     440            3479 :         if (NS_FAILED(rv) && rv != NS_BASE_STREAM_CLOSED)
     441             155 :             mStatus = rv;
     442                 :     }
     443                 : 
     444            3486 :     rv = mListener->OnStartRequest(this, mListenerContext);
     445                 : 
     446                 :     // an error returned from OnStartRequest should cause us to abort; however,
     447                 :     // we must not stomp on mStatus if already canceled.
     448            3486 :     if (NS_FAILED(rv) && NS_SUCCEEDED(mStatus))
     449              16 :         mStatus = rv;
     450                 : 
     451            3486 :     return NS_SUCCEEDED(mStatus) ? STATE_TRANSFER : STATE_STOP;
     452                 : }
     453                 : 
     454                 : PRUint32
     455            4406 : nsInputStreamPump::OnStateTransfer()
     456                 : {
     457            8812 :     SAMPLE_LABEL("Input", "nsInputStreamPump::OnStateTransfer");
     458            4406 :     LOG(("  OnStateTransfer [this=%x]\n", this));
     459                 : 
     460                 :     // if canceled, go directly to STATE_STOP...
     461            4406 :     if (NS_FAILED(mStatus))
     462             124 :         return STATE_STOP;
     463                 : 
     464                 :     nsresult rv;
     465                 : 
     466                 :     PRUint32 avail;
     467            4282 :     rv = mAsyncStream->Available(&avail);
     468            4282 :     LOG(("  Available returned [stream=%x rv=%x avail=%u]\n", mAsyncStream.get(), rv, avail));
     469                 : 
     470            4282 :     if (rv == NS_BASE_STREAM_CLOSED) {
     471             340 :         rv = NS_OK;
     472             340 :         avail = 0;
     473                 :     }
     474            3942 :     else if (NS_SUCCEEDED(rv) && avail) {
     475                 :         // figure out how much data to report (XXX detect overflow??)
     476            3942 :         if (PRUint64(avail) + mStreamOffset > mStreamLength)
     477               0 :             avail = PRUint32(mStreamLength - mStreamOffset);
     478                 : 
     479            3942 :         if (avail) {
     480                 :             // we used to limit avail to 16K - we were afraid some ODA handlers
     481                 :             // might assume they wouldn't get more than 16K at once
     482                 :             // we're removing that limit since it speeds up local file access.
     483                 :             // Now there's an implicit 64K limit of 4 16K segments
     484                 :             // NOTE: ok, so the story is as follows.  OnDataAvailable impls
     485                 :             //       are by contract supposed to consume exactly |avail| bytes.
     486                 :             //       however, many do not... mailnews... stream converters...
     487                 :             //       cough, cough.  the input stream pump is fairly tolerant
     488                 :             //       in this regard; however, if an ODA does not consume any
     489                 :             //       data from the stream, then we could potentially end up in
     490                 :             //       an infinite loop.  we do our best here to try to catch
     491                 :             //       such an error.  (see bug 189672)
     492                 : 
     493                 :             // in most cases this QI will succeed (mAsyncStream is almost always
     494                 :             // a nsPipeInputStream, which implements nsISeekableStream::Tell).
     495                 :             PRInt64 offsetBefore;
     496            7884 :             nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mAsyncStream);
     497            3942 :             if (seekable && NS_FAILED(seekable->Tell(&offsetBefore))) {
     498               0 :                 NS_NOTREACHED("Tell failed on readable stream");
     499               0 :                 offsetBefore = 0;
     500                 :             }
     501                 : 
     502                 :             // report the current stream offset to our listener... if we've
     503                 :             // streamed more than PR_UINT32_MAX, then avoid overflowing the
     504                 :             // stream offset.  it's the best we can do without a 64-bit stream
     505                 :             // listener API.
     506                 :             PRUint32 odaOffset =
     507                 :                 mStreamOffset > PR_UINT32_MAX ?
     508            3942 :                 PR_UINT32_MAX : PRUint32(mStreamOffset);
     509                 : 
     510            3942 :             LOG(("  calling OnDataAvailable [offset=%lld(%u) count=%u]\n",
     511                 :                 mStreamOffset, odaOffset, avail));
     512                 : 
     513            3942 :             rv = mListener->OnDataAvailable(this, mListenerContext, mAsyncStream,
     514            3942 :                                             odaOffset, avail);
     515                 : 
     516                 :             // don't enter this code if ODA failed or called Cancel
     517            3942 :             if (NS_SUCCEEDED(rv) && NS_SUCCEEDED(mStatus)) {
     518                 :                 // test to see if this ODA failed to consume data
     519            3918 :                 if (seekable) {
     520                 :                     // NOTE: if Tell fails, which can happen if the stream is
     521                 :                     // now closed, then we assume that everything was read.
     522                 :                     PRInt64 offsetAfter;
     523            3901 :                     if (NS_FAILED(seekable->Tell(&offsetAfter)))
     524            2790 :                         offsetAfter = offsetBefore + avail;
     525            3901 :                     if (offsetAfter > offsetBefore)
     526            3901 :                         mStreamOffset += (offsetAfter - offsetBefore);
     527               0 :                     else if (mSuspendCount == 0) {
     528                 :                         //
     529                 :                         // possible infinite loop if we continue pumping data!
     530                 :                         //
     531                 :                         // NOTE: although not allowed by nsIStreamListener, we
     532                 :                         // will allow the ODA impl to Suspend the pump.  IMAP
     533                 :                         // does this :-(
     534                 :                         //
     535               0 :                         NS_ERROR("OnDataAvailable implementation consumed no data");
     536               0 :                         mStatus = NS_ERROR_UNEXPECTED;
     537                 :                     }
     538                 :                 }
     539                 :                 else
     540              17 :                     mStreamOffset += avail; // assume ODA behaved well
     541                 :             }
     542                 :         }
     543                 :     }
     544                 : 
     545                 :     // an error returned from Available or OnDataAvailable should cause us to
     546                 :     // abort; however, we must not stomp on mStatus if already canceled.
     547                 : 
     548            4282 :     if (NS_SUCCEEDED(mStatus)) {
     549            4258 :         if (NS_FAILED(rv))
     550               0 :             mStatus = rv;
     551            4258 :         else if (avail) {
     552                 :             // if stream is now closed, advance to STATE_STOP right away.
     553                 :             // Available may return 0 bytes available at the moment; that
     554                 :             // would not mean that we are done.
     555                 :             // XXX async streams should have a GetStatus method!
     556            3918 :             rv = mAsyncStream->Available(&avail);
     557            3918 :             if (NS_SUCCEEDED(rv))
     558            1113 :                 return STATE_TRANSFER;
     559                 :         }
     560                 :     }
     561            3169 :     return STATE_STOP;
     562                 : }
     563                 : 
     564                 : PRUint32
     565            3486 : nsInputStreamPump::OnStateStop()
     566                 : {
     567            6972 :     SAMPLE_LABEL("Input", "nsInputStreamPump::OnStateTransfer");
     568            3486 :     LOG(("  OnStateStop [this=%x status=%x]\n", this, mStatus));
     569                 : 
     570                 :     // if an error occurred, we must be sure to pass the error onto the async
     571                 :     // stream.  in some cases, this is redundant, but since close is idempotent,
     572                 :     // this is OK.  otherwise, be sure to honor the "close-when-done" option.
     573                 : 
     574            3486 :     if (NS_FAILED(mStatus))
     575             341 :         mAsyncStream->CloseWithStatus(mStatus);
     576            3145 :     else if (mCloseWhenDone)
     577             400 :         mAsyncStream->Close();
     578                 : 
     579            3486 :     mAsyncStream = 0;
     580            3486 :     mTargetThread = 0;
     581            3486 :     mIsPending = false;
     582                 : 
     583            3486 :     mListener->OnStopRequest(this, mListenerContext, mStatus);
     584            3486 :     mListener = 0;
     585            3486 :     mListenerContext = 0;
     586                 : 
     587            3486 :     if (mLoadGroup)
     588               0 :         mLoadGroup->RemoveRequest(this, nsnull, mStatus);
     589                 : 
     590            3486 :     return STATE_IDLE;
     591                 : }

Generated by: LCOV version 1.7