LCOV - code coverage report
Current view: top level - modules/libjar - nsJARChannel.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 508 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 71 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /* vim: set sw=4 ts=8 et tw=80 : */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "nsJAR.h"
       8             : #include "nsJARChannel.h"
       9             : #include "nsJARProtocolHandler.h"
      10             : #include "nsMimeTypes.h"
      11             : #include "nsNetUtil.h"
      12             : #include "nsEscape.h"
      13             : #include "nsIPrefService.h"
      14             : #include "nsIPrefBranch.h"
      15             : #include "nsIViewSourceChannel.h"
      16             : #include "nsContentUtils.h"
      17             : #include "nsProxyRelease.h"
      18             : #include "nsContentSecurityManager.h"
      19             : 
      20             : #include "nsIScriptSecurityManager.h"
      21             : #include "nsIPrincipal.h"
      22             : #include "nsIFileURL.h"
      23             : 
      24             : #include "mozilla/IntegerPrintfMacros.h"
      25             : #include "mozilla/Preferences.h"
      26             : #include "nsITabChild.h"
      27             : #include "private/pprio.h"
      28             : #include "nsInputStreamPump.h"
      29             : 
      30             : using namespace mozilla;
      31             : using namespace mozilla::net;
      32             : 
      33             : static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID);
      34             : 
      35             : // the entry for a directory will either be empty (in the case of the
      36             : // top-level directory) or will end with a slash
      37             : #define ENTRY_IS_DIRECTORY(_entry) \
      38             :   ((_entry).IsEmpty() || '/' == (_entry).Last())
      39             : 
      40             : //-----------------------------------------------------------------------------
      41             : 
      42             : // Ignore any LOG macro that we inherit from arbitrary headers. (We define our
      43             : // own LOG macro below.)
      44             : #ifdef LOG
      45             : #undef LOG
      46             : #endif
      47             : 
      48             : //
      49             : // set NSPR_LOG_MODULES=nsJarProtocol:5
      50             : //
      51             : static LazyLogModule gJarProtocolLog("nsJarProtocol");
      52             : 
      53             : #define LOG(args)     MOZ_LOG(gJarProtocolLog, mozilla::LogLevel::Debug, args)
      54             : #define LOG_ENABLED() MOZ_LOG_TEST(gJarProtocolLog, mozilla::LogLevel::Debug)
      55             : 
      56             : //-----------------------------------------------------------------------------
      57             : // nsJARInputThunk
      58             : //
      59             : // this class allows us to do some extra work on the stream transport thread.
      60             : //-----------------------------------------------------------------------------
      61             : 
      62             : class nsJARInputThunk : public nsIInputStream
      63             : {
      64             : public:
      65             :     NS_DECL_THREADSAFE_ISUPPORTS
      66             :     NS_DECL_NSIINPUTSTREAM
      67             : 
      68           0 :     nsJARInputThunk(nsIZipReader *zipReader,
      69             :                     nsIURI* fullJarURI,
      70             :                     const nsACString &jarEntry,
      71             :                     bool usingJarCache)
      72           0 :         : mUsingJarCache(usingJarCache)
      73             :         , mJarReader(zipReader)
      74             :         , mJarEntry(jarEntry)
      75           0 :         , mContentLength(-1)
      76             :     {
      77           0 :         if (fullJarURI) {
      78             : #ifdef DEBUG
      79             :             nsresult rv =
      80             : #endif
      81           0 :                 fullJarURI->GetAsciiSpec(mJarDirSpec);
      82           0 :             NS_ASSERTION(NS_SUCCEEDED(rv), "this shouldn't fail");
      83             :         }
      84           0 :     }
      85             : 
      86           0 :     int64_t GetContentLength()
      87             :     {
      88           0 :         return mContentLength;
      89             :     }
      90             : 
      91             :     nsresult Init();
      92             : 
      93             : private:
      94             : 
      95           0 :     virtual ~nsJARInputThunk()
      96           0 :     {
      97           0 :         Close();
      98           0 :     }
      99             : 
     100             :     bool                        mUsingJarCache;
     101             :     nsCOMPtr<nsIZipReader>      mJarReader;
     102             :     nsCString                   mJarDirSpec;
     103             :     nsCOMPtr<nsIInputStream>    mJarStream;
     104             :     nsCString                   mJarEntry;
     105             :     int64_t                     mContentLength;
     106             : };
     107             : 
     108           0 : NS_IMPL_ISUPPORTS(nsJARInputThunk, nsIInputStream)
     109             : 
     110             : nsresult
     111           0 : nsJARInputThunk::Init()
     112             : {
     113             :     nsresult rv;
     114           0 :     if (ENTRY_IS_DIRECTORY(mJarEntry)) {
     115             :         // A directory stream also needs the Spec of the FullJarURI
     116             :         // because is included in the stream data itself.
     117             : 
     118           0 :         NS_ENSURE_STATE(!mJarDirSpec.IsEmpty());
     119             : 
     120           0 :         rv = mJarReader->GetInputStreamWithSpec(mJarDirSpec,
     121             :                                                 mJarEntry,
     122           0 :                                                 getter_AddRefs(mJarStream));
     123             :     }
     124             :     else {
     125           0 :         rv = mJarReader->GetInputStream(mJarEntry,
     126           0 :                                         getter_AddRefs(mJarStream));
     127             :     }
     128           0 :     if (NS_FAILED(rv)) {
     129             :         // convert to the proper result if the entry wasn't found
     130             :         // so that error pages work
     131           0 :         if (rv == NS_ERROR_FILE_TARGET_DOES_NOT_EXIST)
     132           0 :             rv = NS_ERROR_FILE_NOT_FOUND;
     133           0 :         return rv;
     134             :     }
     135             : 
     136             :     // ask the JarStream for the content length
     137             :     uint64_t avail;
     138           0 :     rv = mJarStream->Available((uint64_t *) &avail);
     139           0 :     if (NS_FAILED(rv)) return rv;
     140             : 
     141           0 :     mContentLength = avail < INT64_MAX ? (int64_t) avail : -1;
     142             : 
     143           0 :     return NS_OK;
     144             : }
     145             : 
     146             : NS_IMETHODIMP
     147           0 : nsJARInputThunk::Close()
     148             : {
     149           0 :     nsresult rv = NS_OK;
     150             : 
     151           0 :     if (mJarStream)
     152           0 :         rv = mJarStream->Close();
     153             : 
     154           0 :     if (!mUsingJarCache && mJarReader)
     155           0 :         mJarReader->Close();
     156             : 
     157           0 :     mJarReader = nullptr;
     158             : 
     159           0 :     return rv;
     160             : }
     161             : 
     162             : NS_IMETHODIMP
     163           0 : nsJARInputThunk::Available(uint64_t *avail)
     164             : {
     165           0 :     return mJarStream->Available(avail);
     166             : }
     167             : 
     168             : NS_IMETHODIMP
     169           0 : nsJARInputThunk::Read(char *buf, uint32_t count, uint32_t *countRead)
     170             : {
     171           0 :     return mJarStream->Read(buf, count, countRead);
     172             : }
     173             : 
     174             : NS_IMETHODIMP
     175           0 : nsJARInputThunk::ReadSegments(nsWriteSegmentFun writer, void *closure,
     176             :                               uint32_t count, uint32_t *countRead)
     177             : {
     178             :     // stream transport does only calls Read()
     179           0 :     return NS_ERROR_NOT_IMPLEMENTED;
     180             : }
     181             : 
     182             : NS_IMETHODIMP
     183           0 : nsJARInputThunk::IsNonBlocking(bool *nonBlocking)
     184             : {
     185           0 :     *nonBlocking = false;
     186           0 :     return NS_OK;
     187             : }
     188             : 
     189             : //-----------------------------------------------------------------------------
     190             : // nsJARChannel
     191             : //-----------------------------------------------------------------------------
     192             : 
     193             : 
     194           0 : nsJARChannel::nsJARChannel()
     195             :     : mOpened(false)
     196             :     , mContentDisposition(0)
     197             :     , mContentLength(-1)
     198             :     , mLoadFlags(LOAD_NORMAL)
     199             :     , mStatus(NS_OK)
     200             :     , mIsPending(false)
     201             :     , mIsUnsafe(true)
     202           0 :     , mBlockRemoteFiles(false)
     203             : {
     204           0 :     mBlockRemoteFiles = Preferences::GetBool("network.jar.block-remote-files", false);
     205             : 
     206             :     // hold an owning reference to the jar handler
     207           0 :     NS_ADDREF(gJarHandler);
     208           0 : }
     209             : 
     210           0 : nsJARChannel::~nsJARChannel()
     211             : {
     212           0 :     NS_ReleaseOnMainThread("nsJARChannel::mLoadInfo", mLoadInfo.forget());
     213             : 
     214             :     // release owning reference to the jar handler
     215           0 :     nsJARProtocolHandler *handler = gJarHandler;
     216           0 :     NS_RELEASE(handler); // nullptr parameter
     217           0 : }
     218             : 
     219           0 : NS_IMPL_ISUPPORTS_INHERITED(nsJARChannel,
     220             :                             nsHashPropertyBag,
     221             :                             nsIRequest,
     222             :                             nsIChannel,
     223             :                             nsIStreamListener,
     224             :                             nsIRequestObserver,
     225             :                             nsIThreadRetargetableRequest,
     226             :                             nsIThreadRetargetableStreamListener,
     227             :                             nsIJARChannel)
     228             : 
     229             : nsresult
     230           0 : nsJARChannel::Init(nsIURI *uri)
     231             : {
     232             :     nsresult rv;
     233           0 :     mJarURI = do_QueryInterface(uri, &rv);
     234           0 :     if (NS_FAILED(rv))
     235           0 :         return rv;
     236             : 
     237           0 :     mOriginalURI = mJarURI;
     238             : 
     239             :     // Prevent loading jar:javascript URIs (see bug 290982).
     240           0 :     nsCOMPtr<nsIURI> innerURI;
     241           0 :     rv = mJarURI->GetJARFile(getter_AddRefs(innerURI));
     242           0 :     if (NS_FAILED(rv))
     243           0 :         return rv;
     244             :     bool isJS;
     245           0 :     rv = innerURI->SchemeIs("javascript", &isJS);
     246           0 :     if (NS_FAILED(rv))
     247           0 :         return rv;
     248           0 :     if (isJS) {
     249           0 :         NS_WARNING("blocking jar:javascript:");
     250           0 :         return NS_ERROR_INVALID_ARG;
     251             :     }
     252             : 
     253           0 :     mJarURI->GetSpec(mSpec);
     254           0 :     return rv;
     255             : }
     256             : 
     257             : nsresult
     258           0 : nsJARChannel::CreateJarInput(nsIZipReaderCache *jarCache, nsJARInputThunk **resultInput)
     259             : {
     260           0 :     MOZ_ASSERT(resultInput);
     261           0 :     MOZ_ASSERT(mJarFile || mTempMem);
     262             : 
     263             :     // important to pass a clone of the file since the nsIFile impl is not
     264             :     // necessarily MT-safe
     265           0 :     nsCOMPtr<nsIFile> clonedFile;
     266           0 :     nsresult rv = NS_OK;
     267           0 :     if (mJarFile) {
     268           0 :         rv = mJarFile->Clone(getter_AddRefs(clonedFile));
     269           0 :         if (NS_FAILED(rv))
     270           0 :             return rv;
     271             :     }
     272             : 
     273           0 :     nsCOMPtr<nsIZipReader> reader;
     274           0 :     if (jarCache) {
     275           0 :         MOZ_ASSERT(mJarFile);
     276           0 :         if (mInnerJarEntry.IsEmpty())
     277           0 :             rv = jarCache->GetZip(clonedFile, getter_AddRefs(reader));
     278             :         else
     279           0 :             rv = jarCache->GetInnerZip(clonedFile, mInnerJarEntry,
     280           0 :                                        getter_AddRefs(reader));
     281             :     } else {
     282             :         // create an uncached jar reader
     283           0 :         nsCOMPtr<nsIZipReader> outerReader = do_CreateInstance(kZipReaderCID, &rv);
     284           0 :         if (NS_FAILED(rv))
     285           0 :             return rv;
     286             : 
     287           0 :         if (mJarFile) {
     288           0 :             rv = outerReader->Open(clonedFile);
     289             :         } else {
     290           0 :             rv = outerReader->OpenMemory(mTempMem->Elements(),
     291           0 :                                          mTempMem->Length());
     292             :         }
     293           0 :         if (NS_FAILED(rv))
     294           0 :             return rv;
     295             : 
     296           0 :         if (mInnerJarEntry.IsEmpty())
     297           0 :             reader = outerReader;
     298             :         else {
     299           0 :             reader = do_CreateInstance(kZipReaderCID, &rv);
     300           0 :             if (NS_FAILED(rv))
     301           0 :                 return rv;
     302             : 
     303           0 :             rv = reader->OpenInner(outerReader, mInnerJarEntry);
     304             :         }
     305             :     }
     306           0 :     if (NS_FAILED(rv))
     307           0 :         return rv;
     308             : 
     309             :     RefPtr<nsJARInputThunk> input = new nsJARInputThunk(reader,
     310             :                                                           mJarURI,
     311             :                                                           mJarEntry,
     312             :                                                           jarCache != nullptr
     313           0 :                                                           );
     314           0 :     rv = input->Init();
     315           0 :     if (NS_FAILED(rv))
     316           0 :         return rv;
     317             : 
     318             :     // Make GetContentLength meaningful
     319           0 :     mContentLength = input->GetContentLength();
     320             : 
     321           0 :     input.forget(resultInput);
     322           0 :     return NS_OK;
     323             : }
     324             : 
     325             : nsresult
     326           0 : nsJARChannel::LookupFile(bool aAllowAsync)
     327             : {
     328           0 :     LOG(("nsJARChannel::LookupFile [this=%p %s]\n", this, mSpec.get()));
     329             : 
     330           0 :     if (mJarFile)
     331           0 :         return NS_OK;
     332             : 
     333             :     nsresult rv;
     334             : 
     335           0 :     rv = mJarURI->GetJARFile(getter_AddRefs(mJarBaseURI));
     336           0 :     if (NS_FAILED(rv))
     337           0 :         return rv;
     338             : 
     339           0 :     rv = mJarURI->GetJAREntry(mJarEntry);
     340           0 :     if (NS_FAILED(rv))
     341           0 :         return rv;
     342             : 
     343             :     // The name of the JAR entry must not contain URL-escaped characters:
     344             :     // we're moving from URL domain to a filename domain here. nsStandardURL
     345             :     // does basic escaping by default, which breaks reading zipped files which
     346             :     // have e.g. spaces in their filenames.
     347           0 :     NS_UnescapeURL(mJarEntry);
     348             : 
     349           0 :     if (mJarFileOverride) {
     350           0 :         mJarFile = mJarFileOverride;
     351           0 :         LOG(("nsJARChannel::LookupFile [this=%p] Overriding mJarFile\n", this));
     352           0 :         return NS_OK;
     353             :     }
     354             : 
     355             :     // try to get a nsIFile directly from the url, which will often succeed.
     356             :     {
     357           0 :         nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(mJarBaseURI);
     358           0 :         if (fileURL)
     359           0 :             fileURL->GetFile(getter_AddRefs(mJarFile));
     360             :     }
     361             : 
     362             :     // try to handle a nested jar
     363           0 :     if (!mJarFile) {
     364           0 :         nsCOMPtr<nsIJARURI> jarURI = do_QueryInterface(mJarBaseURI);
     365           0 :         if (jarURI) {
     366           0 :             nsCOMPtr<nsIFileURL> fileURL;
     367           0 :             nsCOMPtr<nsIURI> innerJarURI;
     368           0 :             rv = jarURI->GetJARFile(getter_AddRefs(innerJarURI));
     369           0 :             if (NS_SUCCEEDED(rv))
     370           0 :                 fileURL = do_QueryInterface(innerJarURI);
     371           0 :             if (fileURL) {
     372           0 :                 fileURL->GetFile(getter_AddRefs(mJarFile));
     373           0 :                 jarURI->GetJAREntry(mInnerJarEntry);
     374             :             }
     375             :         }
     376             :     }
     377             : 
     378           0 :     return rv;
     379             : }
     380             : 
     381             : nsresult
     382           0 : nsJARChannel::OpenLocalFile()
     383             : {
     384           0 :     MOZ_ASSERT(mIsPending);
     385             : 
     386             :     // Local files are always considered safe.
     387           0 :     mIsUnsafe = false;
     388             : 
     389           0 :     RefPtr<nsJARInputThunk> input;
     390           0 :     nsresult rv = CreateJarInput(gJarHandler->JarCache(),
     391           0 :                                  getter_AddRefs(input));
     392           0 :     if (NS_SUCCEEDED(rv)) {
     393             :         // Create input stream pump and call AsyncRead as a block.
     394           0 :         rv = NS_NewInputStreamPump(getter_AddRefs(mPump), input);
     395           0 :         if (NS_SUCCEEDED(rv))
     396           0 :             rv = mPump->AsyncRead(this, nullptr);
     397             :     }
     398             : 
     399           0 :     return rv;
     400             : }
     401             : 
     402             : void
     403           0 : nsJARChannel::NotifyError(nsresult aError)
     404             : {
     405           0 :     MOZ_ASSERT(NS_FAILED(aError));
     406             : 
     407           0 :     mStatus = aError;
     408             : 
     409           0 :     OnStartRequest(nullptr, nullptr);
     410           0 :     OnStopRequest(nullptr, nullptr, aError);
     411           0 : }
     412             : 
     413             : void
     414           0 : nsJARChannel::FireOnProgress(uint64_t aProgress)
     415             : {
     416           0 :   MOZ_ASSERT(NS_IsMainThread());
     417           0 :   MOZ_ASSERT(mProgressSink);
     418             : 
     419           0 :   mProgressSink->OnProgress(this, nullptr, aProgress, mContentLength);
     420           0 : }
     421             : 
     422             : //-----------------------------------------------------------------------------
     423             : // nsIRequest
     424             : //-----------------------------------------------------------------------------
     425             : 
     426             : NS_IMETHODIMP
     427           0 : nsJARChannel::GetName(nsACString &result)
     428             : {
     429           0 :     return mJarURI->GetSpec(result);
     430             : }
     431             : 
     432             : NS_IMETHODIMP
     433           0 : nsJARChannel::IsPending(bool *result)
     434             : {
     435           0 :     *result = mIsPending;
     436           0 :     return NS_OK;
     437             : }
     438             : 
     439             : NS_IMETHODIMP
     440           0 : nsJARChannel::GetStatus(nsresult *status)
     441             : {
     442           0 :     if (mPump && NS_SUCCEEDED(mStatus))
     443           0 :         mPump->GetStatus(status);
     444             :     else
     445           0 :         *status = mStatus;
     446           0 :     return NS_OK;
     447             : }
     448             : 
     449             : NS_IMETHODIMP
     450           0 : nsJARChannel::Cancel(nsresult status)
     451             : {
     452           0 :     mStatus = status;
     453           0 :     if (mPump)
     454           0 :         return mPump->Cancel(status);
     455             : 
     456           0 :     NS_ASSERTION(!mIsPending, "need to implement cancel when downloading");
     457           0 :     return NS_OK;
     458             : }
     459             : 
     460             : NS_IMETHODIMP
     461           0 : nsJARChannel::Suspend()
     462             : {
     463           0 :     if (mPump)
     464           0 :         return mPump->Suspend();
     465             : 
     466           0 :     NS_ASSERTION(!mIsPending, "need to implement suspend when downloading");
     467           0 :     return NS_OK;
     468             : }
     469             : 
     470             : NS_IMETHODIMP
     471           0 : nsJARChannel::Resume()
     472             : {
     473           0 :     if (mPump)
     474           0 :         return mPump->Resume();
     475             : 
     476           0 :     NS_ASSERTION(!mIsPending, "need to implement resume when downloading");
     477           0 :     return NS_OK;
     478             : }
     479             : 
     480             : NS_IMETHODIMP
     481           0 : nsJARChannel::GetLoadFlags(nsLoadFlags *aLoadFlags)
     482             : {
     483           0 :     *aLoadFlags = mLoadFlags;
     484           0 :     return NS_OK;
     485             : }
     486             : 
     487             : NS_IMETHODIMP
     488           0 : nsJARChannel::SetLoadFlags(nsLoadFlags aLoadFlags)
     489             : {
     490           0 :     mLoadFlags = aLoadFlags;
     491           0 :     return NS_OK;
     492             : }
     493             : 
     494             : NS_IMETHODIMP
     495           0 : nsJARChannel::GetIsDocument(bool *aIsDocument)
     496             : {
     497           0 :     return NS_GetIsDocumentChannel(this, aIsDocument);
     498             : }
     499             : 
     500             : NS_IMETHODIMP
     501           0 : nsJARChannel::GetLoadGroup(nsILoadGroup **aLoadGroup)
     502             : {
     503           0 :     NS_IF_ADDREF(*aLoadGroup = mLoadGroup);
     504           0 :     return NS_OK;
     505             : }
     506             : 
     507             : NS_IMETHODIMP
     508           0 : nsJARChannel::SetLoadGroup(nsILoadGroup *aLoadGroup)
     509             : {
     510           0 :     mLoadGroup = aLoadGroup;
     511           0 :     return NS_OK;
     512             : }
     513             : 
     514             : //-----------------------------------------------------------------------------
     515             : // nsIChannel
     516             : //-----------------------------------------------------------------------------
     517             : 
     518             : NS_IMETHODIMP
     519           0 : nsJARChannel::GetOriginalURI(nsIURI **aURI)
     520             : {
     521           0 :     *aURI = mOriginalURI;
     522           0 :     NS_ADDREF(*aURI);
     523           0 :     return NS_OK;
     524             : }
     525             : 
     526             : NS_IMETHODIMP
     527           0 : nsJARChannel::SetOriginalURI(nsIURI *aURI)
     528             : {
     529           0 :     NS_ENSURE_ARG_POINTER(aURI);
     530           0 :     mOriginalURI = aURI;
     531           0 :     return NS_OK;
     532             : }
     533             : 
     534             : NS_IMETHODIMP
     535           0 : nsJARChannel::GetURI(nsIURI **aURI)
     536             : {
     537           0 :     NS_IF_ADDREF(*aURI = mJarURI);
     538             : 
     539           0 :     return NS_OK;
     540             : }
     541             : 
     542             : NS_IMETHODIMP
     543           0 : nsJARChannel::GetOwner(nsISupports **aOwner)
     544             : {
     545             :     // JAR signatures are not processed to avoid main-thread network I/O (bug 726125)
     546           0 :     *aOwner = mOwner;
     547           0 :     NS_IF_ADDREF(*aOwner);
     548           0 :     return NS_OK;
     549             : }
     550             : 
     551             : NS_IMETHODIMP
     552           0 : nsJARChannel::SetOwner(nsISupports *aOwner)
     553             : {
     554           0 :     mOwner = aOwner;
     555           0 :     return NS_OK;
     556             : }
     557             : 
     558             : NS_IMETHODIMP
     559           0 : nsJARChannel::GetLoadInfo(nsILoadInfo **aLoadInfo)
     560             : {
     561           0 :   NS_IF_ADDREF(*aLoadInfo = mLoadInfo);
     562           0 :   return NS_OK;
     563             : }
     564             : 
     565             : NS_IMETHODIMP
     566           0 : nsJARChannel::SetLoadInfo(nsILoadInfo* aLoadInfo)
     567             : {
     568           0 :   mLoadInfo = aLoadInfo;
     569           0 :   return NS_OK;
     570             : }
     571             : 
     572             : NS_IMETHODIMP
     573           0 : nsJARChannel::GetNotificationCallbacks(nsIInterfaceRequestor **aCallbacks)
     574             : {
     575           0 :     NS_IF_ADDREF(*aCallbacks = mCallbacks);
     576           0 :     return NS_OK;
     577             : }
     578             : 
     579             : NS_IMETHODIMP
     580           0 : nsJARChannel::SetNotificationCallbacks(nsIInterfaceRequestor *aCallbacks)
     581             : {
     582           0 :     mCallbacks = aCallbacks;
     583           0 :     return NS_OK;
     584             : }
     585             : 
     586             : NS_IMETHODIMP
     587           0 : nsJARChannel::GetSecurityInfo(nsISupports **aSecurityInfo)
     588             : {
     589           0 :     NS_PRECONDITION(aSecurityInfo, "Null out param");
     590           0 :     NS_IF_ADDREF(*aSecurityInfo = mSecurityInfo);
     591           0 :     return NS_OK;
     592             : }
     593             : 
     594             : NS_IMETHODIMP
     595           0 : nsJARChannel::GetContentType(nsACString &result)
     596             : {
     597             :     // If the Jar file has not been open yet,
     598             :     // We return application/x-unknown-content-type
     599           0 :     if (!mOpened) {
     600           0 :       result.Assign(UNKNOWN_CONTENT_TYPE);
     601           0 :       return NS_OK;
     602             :     }
     603             : 
     604           0 :     if (mContentType.IsEmpty()) {
     605             : 
     606             :         //
     607             :         // generate content type and set it
     608             :         //
     609           0 :         const char *ext = nullptr, *fileName = mJarEntry.get();
     610           0 :         int32_t len = mJarEntry.Length();
     611             : 
     612             :         // check if we're displaying a directory
     613             :         // mJarEntry will be empty if we're trying to display
     614             :         // the topmost directory in a zip, e.g. jar:foo.zip!/
     615           0 :         if (ENTRY_IS_DIRECTORY(mJarEntry)) {
     616           0 :             mContentType.AssignLiteral(APPLICATION_HTTP_INDEX_FORMAT);
     617             :         }
     618             :         else {
     619             :             // not a directory, take a guess by its extension
     620           0 :             for (int32_t i = len-1; i >= 0; i--) {
     621           0 :                 if (fileName[i] == '.') {
     622           0 :                     ext = &fileName[i + 1];
     623           0 :                     break;
     624             :                 }
     625             :             }
     626           0 :             if (ext) {
     627           0 :                 nsIMIMEService *mimeServ = gJarHandler->MimeService();
     628           0 :                 if (mimeServ)
     629           0 :                     mimeServ->GetTypeFromExtension(nsDependentCString(ext), mContentType);
     630             :             }
     631           0 :             if (mContentType.IsEmpty())
     632           0 :                 mContentType.AssignLiteral(UNKNOWN_CONTENT_TYPE);
     633             :         }
     634             :     }
     635           0 :     result = mContentType;
     636           0 :     return NS_OK;
     637             : }
     638             : 
     639             : NS_IMETHODIMP
     640           0 : nsJARChannel::SetContentType(const nsACString &aContentType)
     641             : {
     642             :     // If someone gives us a type hint we should just use that type instead of
     643             :     // doing our guessing.  So we don't care when this is being called.
     644             : 
     645             :     // mContentCharset is unchanged if not parsed
     646           0 :     NS_ParseResponseContentType(aContentType, mContentType, mContentCharset);
     647           0 :     return NS_OK;
     648             : }
     649             : 
     650             : NS_IMETHODIMP
     651           0 : nsJARChannel::GetContentCharset(nsACString &aContentCharset)
     652             : {
     653             :     // If someone gives us a charset hint we should just use that charset.
     654             :     // So we don't care when this is being called.
     655           0 :     aContentCharset = mContentCharset;
     656           0 :     return NS_OK;
     657             : }
     658             : 
     659             : NS_IMETHODIMP
     660           0 : nsJARChannel::SetContentCharset(const nsACString &aContentCharset)
     661             : {
     662           0 :     mContentCharset = aContentCharset;
     663           0 :     return NS_OK;
     664             : }
     665             : 
     666             : NS_IMETHODIMP
     667           0 : nsJARChannel::GetContentDisposition(uint32_t *aContentDisposition)
     668             : {
     669           0 :     if (mContentDispositionHeader.IsEmpty())
     670           0 :         return NS_ERROR_NOT_AVAILABLE;
     671             : 
     672           0 :     *aContentDisposition = mContentDisposition;
     673           0 :     return NS_OK;
     674             : }
     675             : 
     676             : NS_IMETHODIMP
     677           0 : nsJARChannel::SetContentDisposition(uint32_t aContentDisposition)
     678             : {
     679           0 :     return NS_ERROR_NOT_AVAILABLE;
     680             : }
     681             : 
     682             : NS_IMETHODIMP
     683           0 : nsJARChannel::GetContentDispositionFilename(nsAString &aContentDispositionFilename)
     684             : {
     685           0 :     return NS_ERROR_NOT_AVAILABLE;
     686             : }
     687             : 
     688             : NS_IMETHODIMP
     689           0 : nsJARChannel::SetContentDispositionFilename(const nsAString &aContentDispositionFilename)
     690             : {
     691           0 :     return NS_ERROR_NOT_AVAILABLE;
     692             : }
     693             : 
     694             : NS_IMETHODIMP
     695           0 : nsJARChannel::GetContentDispositionHeader(nsACString &aContentDispositionHeader)
     696             : {
     697           0 :     if (mContentDispositionHeader.IsEmpty())
     698           0 :         return NS_ERROR_NOT_AVAILABLE;
     699             : 
     700           0 :     aContentDispositionHeader = mContentDispositionHeader;
     701           0 :     return NS_OK;
     702             : }
     703             : 
     704             : NS_IMETHODIMP
     705           0 : nsJARChannel::GetContentLength(int64_t *result)
     706             : {
     707           0 :     *result = mContentLength;
     708           0 :     return NS_OK;
     709             : }
     710             : 
     711             : NS_IMETHODIMP
     712           0 : nsJARChannel::SetContentLength(int64_t aContentLength)
     713             : {
     714             :     // XXX does this really make any sense at all?
     715           0 :     mContentLength = aContentLength;
     716           0 :     return NS_OK;
     717             : }
     718             : 
     719             : NS_IMETHODIMP
     720           0 : nsJARChannel::Open(nsIInputStream **stream)
     721             : {
     722           0 :     LOG(("nsJARChannel::Open [this=%p]\n", this));
     723             : 
     724           0 :     NS_ENSURE_TRUE(!mOpened, NS_ERROR_IN_PROGRESS);
     725           0 :     NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
     726             : 
     727           0 :     mJarFile = nullptr;
     728           0 :     mIsUnsafe = true;
     729             : 
     730           0 :     nsresult rv = LookupFile(false);
     731           0 :     if (NS_FAILED(rv))
     732           0 :         return rv;
     733             : 
     734             :     // If mJarInput was not set by LookupFile, the JAR is a remote jar.
     735           0 :     if (!mJarFile) {
     736           0 :         NS_NOTREACHED("need sync downloader");
     737           0 :         return NS_ERROR_NOT_IMPLEMENTED;
     738             :     }
     739             : 
     740           0 :     RefPtr<nsJARInputThunk> input;
     741           0 :     rv = CreateJarInput(gJarHandler->JarCache(), getter_AddRefs(input));
     742           0 :     if (NS_FAILED(rv))
     743           0 :         return rv;
     744             : 
     745           0 :     input.forget(stream);
     746           0 :     mOpened = true;
     747             :     // local files are always considered safe
     748           0 :     mIsUnsafe = false;
     749           0 :     return NS_OK;
     750             : }
     751             : 
     752             : NS_IMETHODIMP
     753           0 : nsJARChannel::Open2(nsIInputStream** aStream)
     754             : {
     755           0 :     nsCOMPtr<nsIStreamListener> listener;
     756           0 :     nsresult rv = nsContentSecurityManager::doContentSecurityCheck(this, listener);
     757           0 :     NS_ENSURE_SUCCESS(rv, rv);
     758           0 :     return Open(aStream);
     759             : }
     760             : 
     761             : NS_IMETHODIMP
     762           0 : nsJARChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctx)
     763             : {
     764           0 :     MOZ_ASSERT(!mLoadInfo ||
     765             :                mLoadInfo->GetSecurityMode() == 0 ||
     766             :                mLoadInfo->GetInitialSecurityCheckDone() ||
     767             :                (mLoadInfo->GetSecurityMode() == nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL &&
     768             :                 nsContentUtils::IsSystemPrincipal(mLoadInfo->LoadingPrincipal())),
     769             :                "security flags in loadInfo but asyncOpen2() not called");
     770             : 
     771           0 :     LOG(("nsJARChannel::AsyncOpen [this=%p]\n", this));
     772             : 
     773           0 :     NS_ENSURE_ARG_POINTER(listener);
     774           0 :     NS_ENSURE_TRUE(!mOpened, NS_ERROR_IN_PROGRESS);
     775           0 :     NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
     776             : 
     777           0 :     mJarFile = nullptr;
     778           0 :     mIsUnsafe = true;
     779             : 
     780             :     // Initialize mProgressSink
     781           0 :     NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup, mProgressSink);
     782             : 
     783           0 :     mListener = listener;
     784           0 :     mListenerContext = ctx;
     785           0 :     mIsPending = true;
     786             : 
     787           0 :     nsresult rv = LookupFile(true);
     788           0 :     if (NS_FAILED(rv)) {
     789           0 :         mIsPending = false;
     790           0 :         mListenerContext = nullptr;
     791           0 :         mListener = nullptr;
     792           0 :         mCallbacks = nullptr;
     793           0 :         mProgressSink = nullptr;
     794           0 :         return rv;
     795             :     }
     796             : 
     797           0 :     nsCOMPtr<nsIChannel> channel;
     798             : 
     799           0 :     if (!mJarFile) {
     800             :         // Not a local file...
     801             : 
     802             :         // Check preferences to see if all remote jar support should be disabled
     803           0 :         if (mBlockRemoteFiles) {
     804           0 :             mIsUnsafe = true;
     805           0 :             mIsPending = false;
     806           0 :             mListenerContext = nullptr;
     807           0 :             mListener = nullptr;
     808           0 :             mCallbacks = nullptr;
     809           0 :             mProgressSink = nullptr;
     810           0 :             return NS_ERROR_UNSAFE_CONTENT_TYPE;
     811             :         }
     812             : 
     813             :         // kick off an async download of the base URI...
     814           0 :         nsCOMPtr<nsIStreamListener> downloader = new MemoryDownloader(this);
     815             :         uint32_t loadFlags =
     816           0 :             mLoadFlags & ~(LOAD_DOCUMENT_URI | LOAD_CALL_CONTENT_SNIFFERS);
     817           0 :         rv = NS_NewChannelInternal(getter_AddRefs(channel),
     818             :                                    mJarBaseURI,
     819             :                                    mLoadInfo,
     820             :                                    mLoadGroup,
     821             :                                    mCallbacks,
     822           0 :                                    loadFlags);
     823           0 :         if (NS_FAILED(rv)) {
     824           0 :             mIsPending = false;
     825           0 :             mListenerContext = nullptr;
     826           0 :             mListener = nullptr;
     827           0 :             mCallbacks = nullptr;
     828           0 :             mProgressSink = nullptr;
     829           0 :             return rv;
     830             :         }
     831           0 :         if (mLoadInfo && mLoadInfo->GetEnforceSecurity()) {
     832           0 :             rv = channel->AsyncOpen2(downloader);
     833             :         }
     834             :         else {
     835           0 :             rv = channel->AsyncOpen(downloader, nullptr);
     836             :         }
     837             :     }
     838             :     else {
     839           0 :         rv = OpenLocalFile();
     840             :     }
     841             : 
     842           0 :     if (NS_FAILED(rv)) {
     843           0 :         mIsPending = false;
     844           0 :         mListenerContext = nullptr;
     845           0 :         mListener = nullptr;
     846           0 :         mCallbacks = nullptr;
     847           0 :         mProgressSink = nullptr;
     848           0 :         return rv;
     849             :     }
     850             : 
     851           0 :     if (mLoadGroup)
     852           0 :         mLoadGroup->AddRequest(this, nullptr);
     853             : 
     854           0 :     mOpened = true;
     855             : 
     856           0 :     return NS_OK;
     857             : }
     858             : 
     859             : NS_IMETHODIMP
     860           0 : nsJARChannel::AsyncOpen2(nsIStreamListener *aListener)
     861             : {
     862           0 :   nsCOMPtr<nsIStreamListener> listener = aListener;
     863           0 :   nsresult rv = nsContentSecurityManager::doContentSecurityCheck(this, listener);
     864           0 :   if (NS_FAILED(rv)) {
     865           0 :       mIsPending = false;
     866           0 :       mListenerContext = nullptr;
     867           0 :       mListener = nullptr;
     868           0 :       mCallbacks = nullptr;
     869           0 :       mProgressSink = nullptr;
     870           0 :       return rv;
     871             :   }
     872             : 
     873           0 :   return AsyncOpen(listener, nullptr);
     874             : }
     875             : 
     876             : //-----------------------------------------------------------------------------
     877             : // nsIJARChannel
     878             : //-----------------------------------------------------------------------------
     879             : NS_IMETHODIMP
     880           0 : nsJARChannel::GetIsUnsafe(bool *isUnsafe)
     881             : {
     882           0 :     *isUnsafe = mIsUnsafe;
     883           0 :     return NS_OK;
     884             : }
     885             : 
     886             : NS_IMETHODIMP
     887           0 : nsJARChannel::GetJarFile(nsIFile **aFile)
     888             : {
     889           0 :     NS_IF_ADDREF(*aFile = mJarFile);
     890           0 :     return NS_OK;
     891             : }
     892             : 
     893             : NS_IMETHODIMP
     894           0 : nsJARChannel::SetJarFile(nsIFile *aFile)
     895             : {
     896           0 :     if (mOpened) {
     897           0 :         return NS_ERROR_IN_PROGRESS;
     898             :     }
     899           0 :     mJarFileOverride = aFile;
     900           0 :     return NS_OK;
     901             : }
     902             : 
     903             : 
     904             : NS_IMETHODIMP
     905           0 : nsJARChannel::GetZipEntry(nsIZipEntry **aZipEntry)
     906             : {
     907           0 :     nsresult rv = LookupFile(false);
     908           0 :     if (NS_FAILED(rv))
     909           0 :         return rv;
     910             : 
     911           0 :     if (!mJarFile)
     912           0 :         return NS_ERROR_NOT_AVAILABLE;
     913             : 
     914           0 :     nsCOMPtr<nsIZipReader> reader;
     915           0 :     rv = gJarHandler->JarCache()->GetZip(mJarFile, getter_AddRefs(reader));
     916           0 :     if (NS_FAILED(rv))
     917           0 :         return rv;
     918             : 
     919           0 :     return reader->GetEntry(mJarEntry, aZipEntry);
     920             : }
     921             : 
     922             : //-----------------------------------------------------------------------------
     923             : // mozilla::net::MemoryDownloader::IObserver
     924             : //-----------------------------------------------------------------------------
     925             : 
     926             : void
     927           0 : nsJARChannel::OnDownloadComplete(MemoryDownloader* aDownloader,
     928             :                                  nsIRequest    *request,
     929             :                                  nsISupports   *context,
     930             :                                  nsresult       status,
     931             :                                  MemoryDownloader::Data aData)
     932             : {
     933             :     nsresult rv;
     934             : 
     935           0 :     nsCOMPtr<nsIChannel> channel(do_QueryInterface(request));
     936           0 :     if (channel) {
     937             :         uint32_t loadFlags;
     938           0 :         channel->GetLoadFlags(&loadFlags);
     939           0 :         if (loadFlags & LOAD_REPLACE) {
     940             :             // Update our URI to reflect any redirects that happen during
     941             :             // the HTTP request.
     942           0 :             if (!mOriginalURI) {
     943           0 :                 SetOriginalURI(mJarURI);
     944             :             }
     945             : 
     946           0 :             nsCOMPtr<nsIURI> innerURI;
     947           0 :             rv = channel->GetURI(getter_AddRefs(innerURI));
     948           0 :             if (NS_SUCCEEDED(rv)) {
     949           0 :                 nsCOMPtr<nsIJARURI> newURI;
     950           0 :                 rv = mJarURI->CloneWithJARFile(innerURI,
     951           0 :                                                getter_AddRefs(newURI));
     952           0 :                 if (NS_SUCCEEDED(rv)) {
     953           0 :                     mJarURI = newURI;
     954             :                 }
     955             :             }
     956           0 :             if (NS_SUCCEEDED(status)) {
     957           0 :                 status = rv;
     958             :             }
     959             :         }
     960             :     }
     961             : 
     962           0 :     if (NS_SUCCEEDED(status) && channel) {
     963             :         // In case the load info object has changed during a redirect,
     964             :         // grab it from the target channel.
     965           0 :         channel->GetLoadInfo(getter_AddRefs(mLoadInfo));
     966             :         // Grab the security info from our base channel
     967           0 :         channel->GetSecurityInfo(getter_AddRefs(mSecurityInfo));
     968             : 
     969           0 :         nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
     970           0 :         if (httpChannel) {
     971             :             // We only want to run scripts if the server really intended to
     972             :             // send us a JAR file.  Check the server-supplied content type for
     973             :             // a JAR type.
     974           0 :             nsAutoCString header;
     975           0 :             Unused << httpChannel->GetResponseHeader(
     976           0 :               NS_LITERAL_CSTRING("Content-Type"), header);
     977           0 :             nsAutoCString contentType;
     978           0 :             nsAutoCString charset;
     979           0 :             NS_ParseResponseContentType(header, contentType, charset);
     980           0 :             nsAutoCString channelContentType;
     981           0 :             channel->GetContentType(channelContentType);
     982           0 :             mIsUnsafe = !(contentType.Equals(channelContentType) &&
     983           0 :                           (contentType.EqualsLiteral("application/java-archive") ||
     984           0 :                            contentType.EqualsLiteral("application/x-jar")));
     985             :         } else {
     986           0 :             nsCOMPtr<nsIJARChannel> innerJARChannel(do_QueryInterface(channel));
     987           0 :             if (innerJARChannel) {
     988           0 :                 mIsUnsafe = innerJARChannel->GetIsUnsafe();
     989             :             }
     990             :         }
     991             : 
     992           0 :         channel->GetContentDispositionHeader(mContentDispositionHeader);
     993           0 :         mContentDisposition = NS_GetContentDispositionFromHeader(mContentDispositionHeader, this);
     994             :     }
     995             : 
     996             :     // This is a defense-in-depth check for the preferences to see if all remote jar
     997             :     // support should be disabled. This check may not be needed.
     998           0 :     MOZ_RELEASE_ASSERT(!mBlockRemoteFiles);
     999             : 
    1000           0 :     if (NS_SUCCEEDED(status) && mIsUnsafe &&
    1001           0 :         !Preferences::GetBool("network.jar.open-unsafe-types", false)) {
    1002           0 :         status = NS_ERROR_UNSAFE_CONTENT_TYPE;
    1003             :     }
    1004             : 
    1005           0 :     if (NS_SUCCEEDED(status)) {
    1006             :         // Refuse to unpack view-source: jars even if open-unsafe-types is set.
    1007           0 :         nsCOMPtr<nsIViewSourceChannel> viewSource = do_QueryInterface(channel);
    1008           0 :         if (viewSource) {
    1009           0 :             status = NS_ERROR_UNSAFE_CONTENT_TYPE;
    1010             :         }
    1011             :     }
    1012             : 
    1013           0 :     if (NS_SUCCEEDED(status)) {
    1014           0 :         mTempMem = Move(aData);
    1015             : 
    1016           0 :         RefPtr<nsJARInputThunk> input;
    1017           0 :         rv = CreateJarInput(nullptr, getter_AddRefs(input));
    1018           0 :         if (NS_SUCCEEDED(rv)) {
    1019             :             // create input stream pump
    1020           0 :             rv = NS_NewInputStreamPump(getter_AddRefs(mPump), input);
    1021           0 :             if (NS_SUCCEEDED(rv))
    1022           0 :                 rv = mPump->AsyncRead(this, nullptr);
    1023             :         }
    1024           0 :         status = rv;
    1025             :     }
    1026             : 
    1027           0 :     if (NS_FAILED(status)) {
    1028           0 :         NotifyError(status);
    1029             :     }
    1030           0 : }
    1031             : 
    1032             : //-----------------------------------------------------------------------------
    1033             : // nsIStreamListener
    1034             : //-----------------------------------------------------------------------------
    1035             : 
    1036             : NS_IMETHODIMP
    1037           0 : nsJARChannel::OnStartRequest(nsIRequest *req, nsISupports *ctx)
    1038             : {
    1039           0 :     LOG(("nsJARChannel::OnStartRequest [this=%p %s]\n", this, mSpec.get()));
    1040             : 
    1041           0 :     mRequest = req;
    1042           0 :     nsresult rv = mListener->OnStartRequest(this, mListenerContext);
    1043           0 :     mRequest = nullptr;
    1044             : 
    1045           0 :     return rv;
    1046             : }
    1047             : 
    1048             : NS_IMETHODIMP
    1049           0 : nsJARChannel::OnStopRequest(nsIRequest *req, nsISupports *ctx, nsresult status)
    1050             : {
    1051           0 :     LOG(("nsJARChannel::OnStopRequest [this=%p %s status=%" PRIx32 "]\n",
    1052             :          this, mSpec.get(), static_cast<uint32_t>(status)));
    1053             : 
    1054           0 :     if (NS_SUCCEEDED(mStatus))
    1055           0 :         mStatus = status;
    1056             : 
    1057           0 :     if (mListener) {
    1058           0 :         mListener->OnStopRequest(this, mListenerContext, status);
    1059           0 :         mListener = nullptr;
    1060           0 :         mListenerContext = nullptr;
    1061             :     }
    1062             : 
    1063           0 :     if (mLoadGroup)
    1064           0 :         mLoadGroup->RemoveRequest(this, nullptr, status);
    1065             : 
    1066           0 :     mPump = nullptr;
    1067           0 :     mIsPending = false;
    1068             : 
    1069             :     // Drop notification callbacks to prevent cycles.
    1070           0 :     mCallbacks = nullptr;
    1071           0 :     mProgressSink = nullptr;
    1072             : 
    1073             :     #if defined(XP_WIN) || defined(MOZ_WIDGET_COCOA)
    1074             :     #else
    1075             :     // To deallocate file descriptor by RemoteOpenFileChild destructor.
    1076           0 :     mJarFile = nullptr;
    1077             :     #endif
    1078             : 
    1079           0 :     return NS_OK;
    1080             : }
    1081             : 
    1082             : NS_IMETHODIMP
    1083           0 : nsJARChannel::OnDataAvailable(nsIRequest *req, nsISupports *ctx,
    1084             :                                nsIInputStream *stream,
    1085             :                                uint64_t offset, uint32_t count)
    1086             : {
    1087           0 :     LOG(("nsJARChannel::OnDataAvailable [this=%p %s]\n", this, mSpec.get()));
    1088             : 
    1089             :     nsresult rv;
    1090             : 
    1091           0 :     rv = mListener->OnDataAvailable(this, mListenerContext, stream, offset, count);
    1092             : 
    1093             :     // simply report progress here instead of hooking ourselves up as a
    1094             :     // nsITransportEventSink implementation.
    1095             :     // XXX do the 64-bit stuff for real
    1096           0 :     if (mProgressSink && NS_SUCCEEDED(rv)) {
    1097           0 :         if (NS_IsMainThread()) {
    1098           0 :             FireOnProgress(offset + count);
    1099             :         } else {
    1100           0 :             NS_DispatchToMainThread(NewRunnableMethod
    1101           0 :                                     <uint64_t>("nsJARChannel::FireOnProgress",
    1102             :                                                this,
    1103             :                                                &nsJARChannel::FireOnProgress,
    1104           0 :                                                offset + count));
    1105             :         }
    1106             :     }
    1107             : 
    1108           0 :     return rv; // let the pump cancel on failure
    1109             : }
    1110             : 
    1111             : NS_IMETHODIMP
    1112           0 : nsJARChannel::RetargetDeliveryTo(nsIEventTarget* aEventTarget)
    1113             : {
    1114           0 :   MOZ_ASSERT(NS_IsMainThread());
    1115             : 
    1116           0 :   nsCOMPtr<nsIThreadRetargetableRequest> request = do_QueryInterface(mRequest);
    1117           0 :   if (!request) {
    1118           0 :     return NS_ERROR_NO_INTERFACE;
    1119             :   }
    1120             : 
    1121           0 :   return request->RetargetDeliveryTo(aEventTarget);
    1122             : }
    1123             : 
    1124             : NS_IMETHODIMP
    1125           0 : nsJARChannel::CheckListenerChain()
    1126             : {
    1127           0 :   MOZ_ASSERT(NS_IsMainThread());
    1128             : 
    1129             :   nsCOMPtr<nsIThreadRetargetableStreamListener> listener =
    1130           0 :     do_QueryInterface(mListener);
    1131           0 :   if (!listener) {
    1132           0 :     return NS_ERROR_NO_INTERFACE;
    1133             :   }
    1134             : 
    1135           0 :   return listener->CheckListenerChain();
    1136             : }

Generated by: LCOV version 1.13