LCOV - code coverage report
Current view: top level - netwerk/base - nsIncrementalStreamLoader.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 68 101 67.3 %
Date: 2017-07-14 16:53:18 Functions: 13 15 86.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "nsIncrementalStreamLoader.h"
       7             : #include "nsIInputStream.h"
       8             : #include "nsIChannel.h"
       9             : #include "nsError.h"
      10             : #include "GeckoProfiler.h"
      11             : 
      12             : #include <limits>
      13             : 
      14           4 : nsIncrementalStreamLoader::nsIncrementalStreamLoader()
      15           4 :   : mData(), mBytesConsumed(0)
      16             : {
      17           4 : }
      18             : 
      19           4 : nsIncrementalStreamLoader::~nsIncrementalStreamLoader()
      20             : {
      21           4 : }
      22             : 
      23             : NS_IMETHODIMP
      24           4 : nsIncrementalStreamLoader::Init(nsIIncrementalStreamLoaderObserver* observer)
      25             : {
      26           4 :   NS_ENSURE_ARG_POINTER(observer);
      27           4 :   mObserver = observer;
      28           4 :   return NS_OK;
      29             : }
      30             : 
      31             : nsresult
      32           4 : nsIncrementalStreamLoader::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
      33             : {
      34           4 :   if (aOuter) return NS_ERROR_NO_AGGREGATION;
      35             : 
      36           4 :   nsIncrementalStreamLoader* it = new nsIncrementalStreamLoader();
      37           4 :   if (it == nullptr)
      38           0 :     return NS_ERROR_OUT_OF_MEMORY;
      39           4 :   NS_ADDREF(it);
      40           4 :   nsresult rv = it->QueryInterface(aIID, aResult);
      41           4 :   NS_RELEASE(it);
      42           4 :   return rv;
      43             : }
      44             : 
      45          88 : NS_IMPL_ISUPPORTS(nsIncrementalStreamLoader, nsIIncrementalStreamLoader,
      46             :                   nsIRequestObserver, nsIStreamListener,
      47             :                   nsIThreadRetargetableStreamListener)
      48             : 
      49             : NS_IMETHODIMP
      50           0 : nsIncrementalStreamLoader::GetNumBytesRead(uint32_t* aNumBytes)
      51             : {
      52           0 :   *aNumBytes = mBytesConsumed + mData.length();
      53           0 :   return NS_OK;
      54             : }
      55             : 
      56             : /* readonly attribute nsIRequest request; */
      57             : NS_IMETHODIMP
      58          20 : nsIncrementalStreamLoader::GetRequest(nsIRequest **aRequest)
      59             : {
      60          20 :   NS_IF_ADDREF(*aRequest = mRequest);
      61          20 :   return NS_OK;
      62             : }
      63             : 
      64             : NS_IMETHODIMP
      65           4 : nsIncrementalStreamLoader::OnStartRequest(nsIRequest* request, nsISupports *ctxt)
      66             : {
      67           8 :   nsCOMPtr<nsIChannel> chan( do_QueryInterface(request) );
      68           4 :   if (chan) {
      69           4 :     int64_t contentLength = -1;
      70           4 :     chan->GetContentLength(&contentLength);
      71           4 :     if (contentLength >= 0) {
      72           4 :       if (uint64_t(contentLength) > std::numeric_limits<size_t>::max()) {
      73             :         // Too big to fit into size_t, so let's bail.
      74           0 :         return NS_ERROR_OUT_OF_MEMORY;
      75             :       }
      76             :       // preallocate buffer
      77           4 :       if (!mData.initCapacity(contentLength)) {
      78           0 :         return NS_ERROR_OUT_OF_MEMORY;
      79             :       }
      80             :     }
      81             :   }
      82           4 :   mContext = ctxt;
      83           4 :   return NS_OK;
      84             : }
      85             : 
      86             : NS_IMETHODIMP
      87           4 : nsIncrementalStreamLoader::OnStopRequest(nsIRequest* request, nsISupports *ctxt,
      88             :                                          nsresult aStatus)
      89             : {
      90           8 :   AUTO_PROFILER_LABEL("nsIncrementalStreamLoader::OnStopRequest", NETWORK);
      91             : 
      92           4 :   if (mObserver) {
      93             :     // provide nsIIncrementalStreamLoader::request during call to OnStreamComplete
      94           4 :     mRequest = request;
      95           4 :     size_t length = mData.length();
      96           4 :     uint8_t* elems = mData.extractOrCopyRawBuffer();
      97           8 :     nsresult rv = mObserver->OnStreamComplete(this, mContext, aStatus,
      98           8 :                                               length, elems);
      99           4 :     if (rv != NS_SUCCESS_ADOPTED_DATA) {
     100             :       // The observer didn't take ownership of the extracted data buffer, so
     101             :       // put it back into mData.
     102           4 :       mData.replaceRawBuffer(elems, length);
     103             :     }
     104             :     // done.. cleanup
     105           4 :     ReleaseData();
     106           4 :     mRequest = nullptr;
     107           4 :     mObserver = nullptr;
     108           4 :     mContext = nullptr;
     109             :   }
     110           8 :   return NS_OK;
     111             : }
     112             : 
     113             : nsresult
     114           4 : nsIncrementalStreamLoader::WriteSegmentFun(nsIInputStream *inStr,
     115             :                                            void *closure,
     116             :                                            const char *fromSegment,
     117             :                                            uint32_t toOffset,
     118             :                                            uint32_t count,
     119             :                                            uint32_t *writeCount)
     120             : {
     121           4 :   nsIncrementalStreamLoader *self = (nsIncrementalStreamLoader *) closure;
     122             : 
     123           4 :   const uint8_t *data = reinterpret_cast<const uint8_t *>(fromSegment);
     124           4 :   uint32_t consumedCount = 0;
     125             :   nsresult rv;
     126           4 :   if (self->mData.empty()) {
     127             :     // Shortcut when observer wants to keep the listener's buffer empty.
     128           8 :     rv = self->mObserver->OnIncrementalData(self, self->mContext,
     129           8 :                                             count, data, &consumedCount);
     130             : 
     131           4 :     if (rv != NS_OK) {
     132           0 :       return rv;
     133             :     }
     134             : 
     135           4 :     if (consumedCount > count) {
     136           0 :       return NS_ERROR_INVALID_ARG;
     137             :     }
     138             : 
     139           4 :     if (consumedCount < count) {
     140           0 :       if (!self->mData.append(fromSegment + consumedCount,
     141           0 :                               count - consumedCount)) {
     142           0 :         self->mData.clearAndFree();
     143           0 :         return NS_ERROR_OUT_OF_MEMORY;
     144             :       }
     145             :     }
     146             :   } else {
     147             :     // We have some non-consumed data from previous OnIncrementalData call,
     148             :     // appending new data and reporting combined data.
     149           0 :     if (!self->mData.append(fromSegment, count)) {
     150           0 :       self->mData.clearAndFree();
     151           0 :       return NS_ERROR_OUT_OF_MEMORY;
     152             :     }
     153           0 :     size_t length = self->mData.length();
     154           0 :     uint32_t reportCount = length > UINT32_MAX ? UINT32_MAX : (uint32_t)length;
     155           0 :     uint8_t* elems = self->mData.extractOrCopyRawBuffer();
     156             : 
     157           0 :     rv = self->mObserver->OnIncrementalData(self, self->mContext,
     158           0 :                                             reportCount, elems, &consumedCount);
     159             : 
     160             :     // We still own elems, freeing its memory when exiting scope.
     161           0 :     if (rv != NS_OK) {
     162           0 :       free(elems);
     163           0 :       return rv;
     164             :     }
     165             : 
     166           0 :     if (consumedCount > reportCount) {
     167           0 :       free(elems);
     168           0 :       return NS_ERROR_INVALID_ARG;
     169             :     }
     170             : 
     171           0 :     if (consumedCount == length) {
     172           0 :       free(elems); // good case -- fully consumed data
     173             :     } else {
     174             :       // Adopting elems back (at least its portion).
     175           0 :       self->mData.replaceRawBuffer(elems, length);
     176           0 :       if (consumedCount > 0) {
     177           0 :         self->mData.erase(self->mData.begin() + consumedCount);
     178             :       }
     179             :     }
     180             :   }
     181             : 
     182           4 :   self->mBytesConsumed += consumedCount;
     183           4 :   *writeCount = count;
     184             : 
     185           4 :   return NS_OK;
     186             : }
     187             : 
     188             : NS_IMETHODIMP
     189           4 : nsIncrementalStreamLoader::OnDataAvailable(nsIRequest* request, nsISupports *ctxt,
     190             :                                 nsIInputStream *inStr,
     191             :                                 uint64_t sourceOffset, uint32_t count)
     192             : {
     193           4 :   if (mObserver) {
     194             :     // provide nsIIncrementalStreamLoader::request during call to OnStreamComplete
     195           4 :     mRequest = request;
     196             :   }
     197             :   uint32_t countRead;
     198           4 :   nsresult rv = inStr->ReadSegments(WriteSegmentFun, this, count, &countRead);
     199           4 :   mRequest = nullptr;
     200           4 :   return rv;
     201             : }
     202             : 
     203             : void
     204           4 : nsIncrementalStreamLoader::ReleaseData()
     205             : {
     206           4 :   mData.clearAndFree();
     207           4 : }
     208             : 
     209             : NS_IMETHODIMP
     210           0 : nsIncrementalStreamLoader::CheckListenerChain()
     211             : {
     212           0 :   return NS_OK;
     213             : }

Generated by: LCOV version 1.13