LCOV - code coverage report
Current view: directory - modules/libjar - nsJARChannel.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 415 194 46.7 %
Date: 2012-06-02 Functions: 57 33 57.9 %

       1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2                 :  *
       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                 :  *   Jeff Walden <jwalden+code@mit.edu>
      25                 :  *
      26                 :  * Alternatively, the contents of this file may be used under the terms of
      27                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      28                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      30                 :  * of those above. If you wish to allow use of your version of this file only
      31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      32                 :  * use your version of this file under the terms of the MPL, indicate your
      33                 :  * decision by deleting the provisions above and replace them with the notice
      34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      35                 :  * the provisions above, a recipient may use your version of this file under
      36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      37                 :  *
      38                 :  * ***** END LICENSE BLOCK ***** */
      39                 : 
      40                 : #include "nsJAR.h"
      41                 : #include "nsJARChannel.h"
      42                 : #include "nsJARProtocolHandler.h"
      43                 : #include "nsMimeTypes.h"
      44                 : #include "nsNetUtil.h"
      45                 : #include "nsEscape.h"
      46                 : #include "nsIPrefService.h"
      47                 : #include "nsIPrefBranch.h"
      48                 : #include "nsIViewSourceChannel.h"
      49                 : #include "nsChannelProperties.h"
      50                 : 
      51                 : #include "nsIScriptSecurityManager.h"
      52                 : #include "nsIPrincipal.h"
      53                 : #include "nsIFileURL.h"
      54                 : 
      55                 : #include "mozilla/Preferences.h"
      56                 : 
      57                 : using namespace mozilla;
      58                 : 
      59                 : static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID);
      60                 : 
      61                 : // the entry for a directory will either be empty (in the case of the
      62                 : // top-level directory) or will end with a slash
      63                 : #define ENTRY_IS_DIRECTORY(_entry) \
      64                 :   ((_entry).IsEmpty() || '/' == (_entry).Last())
      65                 : 
      66                 : //-----------------------------------------------------------------------------
      67                 : 
      68                 : #if defined(PR_LOGGING)
      69                 : //
      70                 : // set NSPR_LOG_MODULES=nsJarProtocol:5
      71                 : //
      72                 : static PRLogModuleInfo *gJarProtocolLog = nsnull;
      73                 : #endif
      74                 : 
      75                 : #define LOG(args)     PR_LOG(gJarProtocolLog, PR_LOG_DEBUG, args)
      76                 : #define LOG_ENABLED() PR_LOG_TEST(gJarProtocolLog, 4)
      77                 : 
      78                 : //-----------------------------------------------------------------------------
      79                 : // nsJARInputThunk
      80                 : //
      81                 : // this class allows us to do some extra work on the stream transport thread.
      82                 : //-----------------------------------------------------------------------------
      83                 : 
      84                 : class nsJARInputThunk : public nsIInputStream
      85                 : {
      86                 : public:
      87                 :     NS_DECL_ISUPPORTS
      88                 :     NS_DECL_NSIINPUTSTREAM
      89                 : 
      90             193 :     nsJARInputThunk(nsIZipReader *zipReader,
      91                 :                     nsIURI* fullJarURI,
      92                 :                     const nsACString &jarEntry,
      93                 :                     nsIZipReaderCache *jarCache)
      94                 :         : mJarCache(jarCache)
      95                 :         , mJarReader(zipReader)
      96                 :         , mJarEntry(jarEntry)
      97             193 :         , mContentLength(-1)
      98                 :     {
      99             193 :         if (fullJarURI) {
     100                 : #ifdef DEBUG
     101                 :             nsresult rv =
     102                 : #endif
     103             193 :                 fullJarURI->GetAsciiSpec(mJarDirSpec);
     104             193 :             NS_ASSERTION(NS_SUCCEEDED(rv), "this shouldn't fail");
     105                 :         }
     106             193 :     }
     107                 : 
     108             386 :     virtual ~nsJARInputThunk()
     109             386 :     {
     110             193 :         if (!mJarCache && mJarReader)
     111               0 :             mJarReader->Close();
     112             772 :     }
     113                 : 
     114               0 :     void GetJarReader(nsIZipReader **result)
     115                 :     {
     116               0 :         NS_IF_ADDREF(*result = mJarReader);
     117               0 :     }
     118                 : 
     119              57 :     PRInt32 GetContentLength()
     120                 :     {
     121              57 :         return mContentLength;
     122                 :     }
     123                 : 
     124                 :     nsresult EnsureJarStream();
     125                 : 
     126                 : private:
     127                 : 
     128                 :     nsCOMPtr<nsIZipReaderCache> mJarCache;
     129                 :     nsCOMPtr<nsIZipReader>      mJarReader;
     130                 :     nsCString                   mJarDirSpec;
     131                 :     nsCOMPtr<nsIInputStream>    mJarStream;
     132                 :     nsCString                   mJarEntry;
     133                 :     PRInt32                     mContentLength;
     134                 : };
     135                 : 
     136            1555 : NS_IMPL_THREADSAFE_ISUPPORTS1(nsJARInputThunk, nsIInputStream)
     137                 : 
     138                 : nsresult
     139             357 : nsJARInputThunk::EnsureJarStream()
     140                 : {
     141             357 :     if (mJarStream)
     142             164 :         return NS_OK;
     143                 : 
     144                 :     nsresult rv;
     145             193 :     if (ENTRY_IS_DIRECTORY(mJarEntry)) {
     146                 :         // A directory stream also needs the Spec of the FullJarURI
     147                 :         // because is included in the stream data itself.
     148                 : 
     149               0 :         NS_ENSURE_STATE(!mJarDirSpec.IsEmpty());
     150                 : 
     151               0 :         rv = mJarReader->GetInputStreamWithSpec(mJarDirSpec,
     152                 :                                                 mJarEntry,
     153               0 :                                                 getter_AddRefs(mJarStream));
     154                 :     }
     155                 :     else {
     156             193 :         rv = mJarReader->GetInputStream(mJarEntry,
     157             193 :                                         getter_AddRefs(mJarStream));
     158                 :     }
     159             193 :     if (NS_FAILED(rv)) {
     160                 :         // convert to the proper result if the entry wasn't found
     161                 :         // so that error pages work
     162              41 :         if (rv == NS_ERROR_FILE_TARGET_DOES_NOT_EXIST)
     163              41 :             rv = NS_ERROR_FILE_NOT_FOUND;
     164              41 :         return rv;
     165                 :     }
     166                 : 
     167                 :     // ask the JarStream for the content length
     168             152 :     rv = mJarStream->Available((PRUint32 *) &mContentLength);
     169             152 :     if (NS_FAILED(rv)) return rv;
     170                 : 
     171             152 :     return NS_OK;
     172                 : }
     173                 : 
     174                 : NS_IMETHODIMP
     175               0 : nsJARInputThunk::Close()
     176                 : {
     177               0 :     if (mJarStream)
     178               0 :         return mJarStream->Close();
     179                 : 
     180               0 :     return NS_OK;
     181                 : }
     182                 : 
     183                 : NS_IMETHODIMP
     184              54 : nsJARInputThunk::Available(PRUint32 *avail)
     185                 : {
     186              54 :     nsresult rv = EnsureJarStream();
     187              54 :     if (NS_FAILED(rv)) return rv;
     188                 : 
     189              54 :     return mJarStream->Available(avail);
     190                 : }
     191                 : 
     192                 : NS_IMETHODIMP
     193             110 : nsJARInputThunk::Read(char *buf, PRUint32 count, PRUint32 *countRead)
     194                 : {
     195             110 :     nsresult rv = EnsureJarStream();
     196             110 :     if (NS_FAILED(rv)) return rv;
     197                 : 
     198             110 :     return mJarStream->Read(buf, count, countRead);
     199                 : }
     200                 : 
     201                 : NS_IMETHODIMP
     202               1 : nsJARInputThunk::ReadSegments(nsWriteSegmentFun writer, void *closure,
     203                 :                               PRUint32 count, PRUint32 *countRead)
     204                 : {
     205                 :     // stream transport does only calls Read()
     206               1 :     return NS_ERROR_NOT_IMPLEMENTED;
     207                 : }
     208                 : 
     209                 : NS_IMETHODIMP
     210               0 : nsJARInputThunk::IsNonBlocking(bool *nonBlocking)
     211                 : {
     212               0 :     *nonBlocking = false;
     213               0 :     return NS_OK;
     214                 : }
     215                 : 
     216                 : //-----------------------------------------------------------------------------
     217                 : // nsJARChannel
     218                 : //-----------------------------------------------------------------------------
     219                 : 
     220                 : 
     221             399 : nsJARChannel::nsJARChannel()
     222                 :     : mContentLength(-1)
     223                 :     , mLoadFlags(LOAD_NORMAL)
     224                 :     , mStatus(NS_OK)
     225                 :     , mIsPending(false)
     226                 :     , mIsUnsafe(true)
     227             399 :     , mJarInput(nsnull)
     228                 : {
     229                 : #if defined(PR_LOGGING)
     230             399 :     if (!gJarProtocolLog)
     231              25 :         gJarProtocolLog = PR_NewLogModule("nsJarProtocol");
     232                 : #endif
     233                 : 
     234                 :     // hold an owning reference to the jar handler
     235             399 :     NS_ADDREF(gJarHandler);
     236             399 : }
     237                 : 
     238            1197 : nsJARChannel::~nsJARChannel()
     239                 : {
     240                 :     // with the exception of certain error cases mJarInput will already be null.
     241             399 :     NS_IF_RELEASE(mJarInput);
     242                 : 
     243                 :     // release owning reference to the jar handler
     244             399 :     nsJARProtocolHandler *handler = gJarHandler;
     245             399 :     NS_RELEASE(handler); // NULL parameter
     246            1596 : }
     247                 : 
     248            2762 : NS_IMPL_ISUPPORTS_INHERITED6(nsJARChannel,
     249                 :                              nsHashPropertyBag,
     250                 :                              nsIRequest,
     251                 :                              nsIChannel,
     252                 :                              nsIStreamListener,
     253                 :                              nsIRequestObserver,
     254                 :                              nsIDownloadObserver,
     255                 :                              nsIJARChannel)
     256                 : 
     257                 : nsresult 
     258             399 : nsJARChannel::Init(nsIURI *uri)
     259                 : {
     260                 :     nsresult rv;
     261             399 :     rv = nsHashPropertyBag::Init();
     262             399 :     if (NS_FAILED(rv))
     263               0 :         return rv;
     264                 : 
     265             399 :     mJarURI = do_QueryInterface(uri, &rv);
     266             399 :     if (NS_FAILED(rv))
     267               0 :         return rv;
     268                 : 
     269             399 :     mOriginalURI = mJarURI;
     270                 : 
     271                 :     // Prevent loading jar:javascript URIs (see bug 290982).
     272             798 :     nsCOMPtr<nsIURI> innerURI;
     273             399 :     rv = mJarURI->GetJARFile(getter_AddRefs(innerURI));
     274             399 :     if (NS_FAILED(rv))
     275               0 :         return rv;
     276                 :     bool isJS;
     277             399 :     rv = innerURI->SchemeIs("javascript", &isJS);
     278             399 :     if (NS_FAILED(rv))
     279               0 :         return rv;
     280             399 :     if (isJS) {
     281               0 :         NS_WARNING("blocking jar:javascript:");
     282               0 :         return NS_ERROR_INVALID_ARG;
     283                 :     }
     284                 : 
     285                 : #if defined(PR_LOGGING)
     286             399 :     mJarURI->GetSpec(mSpec);
     287                 : #endif
     288             399 :     return rv;
     289                 : }
     290                 : 
     291                 : nsresult
     292             195 : nsJARChannel::CreateJarInput(nsIZipReaderCache *jarCache)
     293                 : {
     294                 :     // important to pass a clone of the file since the nsIFile impl is not
     295                 :     // necessarily MT-safe
     296             390 :     nsCOMPtr<nsIFile> clonedFile;
     297             195 :     nsresult rv = mJarFile->Clone(getter_AddRefs(clonedFile));
     298             195 :     if (NS_FAILED(rv))
     299               0 :         return rv;
     300                 : 
     301             390 :     nsCOMPtr<nsIZipReader> reader;
     302             195 :     if (jarCache) {
     303             195 :         if (mInnerJarEntry.IsEmpty())
     304             151 :             rv = jarCache->GetZip(mJarFile, getter_AddRefs(reader));
     305                 :         else 
     306                 :             rv = jarCache->GetInnerZip(mJarFile, mInnerJarEntry,
     307              44 :                                        getter_AddRefs(reader));
     308                 :     } else {
     309                 :         // create an uncached jar reader
     310               0 :         nsCOMPtr<nsIZipReader> outerReader = do_CreateInstance(kZipReaderCID, &rv);
     311               0 :         if (NS_FAILED(rv))
     312               0 :             return rv;
     313                 : 
     314               0 :         rv = outerReader->Open(mJarFile);
     315               0 :         if (NS_FAILED(rv))
     316               0 :             return rv;
     317                 : 
     318               0 :         if (mInnerJarEntry.IsEmpty())
     319               0 :             reader = outerReader;
     320                 :         else {
     321               0 :             reader = do_CreateInstance(kZipReaderCID, &rv);
     322               0 :             if (NS_FAILED(rv))
     323               0 :                 return rv;
     324                 : 
     325               0 :             rv = reader->OpenInner(outerReader, mInnerJarEntry);
     326                 :         }
     327                 :     }
     328             195 :     if (NS_FAILED(rv))
     329               2 :         return rv;
     330                 : 
     331             386 :     mJarInput = new nsJARInputThunk(reader, mJarURI, mJarEntry, jarCache);
     332             193 :     if (!mJarInput)
     333               0 :         return NS_ERROR_OUT_OF_MEMORY;
     334             193 :     NS_ADDREF(mJarInput);
     335             193 :     return NS_OK;
     336                 : }
     337                 : 
     338                 : nsresult
     339             196 : nsJARChannel::EnsureJarInput(bool blocking)
     340                 : {
     341             196 :     LOG(("nsJARChannel::EnsureJarInput [this=%x %s]\n", this, mSpec.get()));
     342                 : 
     343                 :     nsresult rv;
     344             392 :     nsCOMPtr<nsIURI> uri;
     345                 : 
     346             196 :     rv = mJarURI->GetJARFile(getter_AddRefs(mJarBaseURI));
     347             196 :     if (NS_FAILED(rv)) return rv;
     348                 : 
     349             196 :     rv = mJarURI->GetJAREntry(mJarEntry);
     350             196 :     if (NS_FAILED(rv)) return rv;
     351                 : 
     352                 :     // The name of the JAR entry must not contain URL-escaped characters:
     353                 :     // we're moving from URL domain to a filename domain here. nsStandardURL
     354                 :     // does basic escaping by default, which breaks reading zipped files which
     355                 :     // have e.g. spaces in their filenames.
     356             196 :     NS_UnescapeURL(mJarEntry);
     357                 : 
     358                 :     // try to get a nsIFile directly from the url, which will often succeed.
     359                 :     {
     360             392 :         nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(mJarBaseURI);
     361             196 :         if (fileURL)
     362             151 :             fileURL->GetFile(getter_AddRefs(mJarFile));
     363                 :     }
     364                 :     // try to handle a nested jar
     365             196 :     if (!mJarFile) {
     366              90 :         nsCOMPtr<nsIJARURI> jarURI = do_QueryInterface(mJarBaseURI);
     367              45 :         if (jarURI) {
     368              88 :             nsCOMPtr<nsIFileURL> fileURL;
     369              88 :             nsCOMPtr<nsIURI> innerJarURI;
     370              44 :             rv = jarURI->GetJARFile(getter_AddRefs(innerJarURI));
     371              44 :             if (NS_SUCCEEDED(rv))
     372              44 :                 fileURL = do_QueryInterface(innerJarURI);
     373              44 :             if (fileURL) {
     374              44 :                 fileURL->GetFile(getter_AddRefs(mJarFile));
     375              44 :                 jarURI->GetJAREntry(mInnerJarEntry);
     376                 :             }
     377                 :         }
     378                 :     }
     379                 : 
     380             196 :     if (mJarFile) {
     381             195 :         mIsUnsafe = false;
     382                 : 
     383                 :         // NOTE: we do not need to deal with mSecurityInfo here,
     384                 :         // because we're loading from a local file
     385             195 :         rv = CreateJarInput(gJarHandler->JarCache());
     386                 :     }
     387               1 :     else if (blocking) {
     388               0 :         NS_NOTREACHED("need sync downloader");
     389               0 :         rv = NS_ERROR_NOT_IMPLEMENTED;
     390                 :     }
     391                 :     else {
     392                 :         // kick off an async download of the base URI...
     393               1 :         rv = NS_NewDownloader(getter_AddRefs(mDownloader), this);
     394               1 :         if (NS_SUCCEEDED(rv))
     395                 :             rv = NS_OpenURI(mDownloader, nsnull, mJarBaseURI, nsnull,
     396                 :                             mLoadGroup, mCallbacks,
     397               1 :                             mLoadFlags & ~(LOAD_DOCUMENT_URI | LOAD_CALL_CONTENT_SNIFFERS));
     398                 :     }
     399             196 :     return rv;
     400                 : 
     401                 : }
     402                 : 
     403                 : //-----------------------------------------------------------------------------
     404                 : // nsIRequest
     405                 : //-----------------------------------------------------------------------------
     406                 : 
     407                 : NS_IMETHODIMP
     408               0 : nsJARChannel::GetName(nsACString &result)
     409                 : {
     410               0 :     return mJarURI->GetSpec(result);
     411                 : }
     412                 : 
     413                 : NS_IMETHODIMP
     414               0 : nsJARChannel::IsPending(bool *result)
     415                 : {
     416               0 :     *result = mIsPending;
     417               0 :     return NS_OK;
     418                 : }
     419                 : 
     420                 : NS_IMETHODIMP
     421               0 : nsJARChannel::GetStatus(nsresult *status)
     422                 : {
     423               0 :     if (mPump && NS_SUCCEEDED(mStatus))
     424               0 :         mPump->GetStatus(status);
     425                 :     else
     426               0 :         *status = mStatus;
     427               0 :     return NS_OK;
     428                 : }
     429                 : 
     430                 : NS_IMETHODIMP
     431               0 : nsJARChannel::Cancel(nsresult status)
     432                 : {
     433               0 :     mStatus = status;
     434               0 :     if (mPump)
     435               0 :         return mPump->Cancel(status);
     436                 : 
     437               0 :     NS_ASSERTION(!mIsPending, "need to implement cancel when downloading");
     438               0 :     return NS_OK;
     439                 : }
     440                 : 
     441                 : NS_IMETHODIMP
     442               0 : nsJARChannel::Suspend()
     443                 : {
     444               0 :     if (mPump)
     445               0 :         return mPump->Suspend();
     446                 : 
     447               0 :     NS_ASSERTION(!mIsPending, "need to implement suspend when downloading");
     448               0 :     return NS_OK;
     449                 : }
     450                 : 
     451                 : NS_IMETHODIMP
     452               0 : nsJARChannel::Resume()
     453                 : {
     454               0 :     if (mPump)
     455               0 :         return mPump->Resume();
     456                 : 
     457               0 :     NS_ASSERTION(!mIsPending, "need to implement resume when downloading");
     458               0 :     return NS_OK;
     459                 : }
     460                 : 
     461                 : NS_IMETHODIMP
     462               3 : nsJARChannel::GetLoadFlags(nsLoadFlags *aLoadFlags)
     463                 : {
     464               3 :     *aLoadFlags = mLoadFlags;
     465               3 :     return NS_OK;
     466                 : }
     467                 : 
     468                 : NS_IMETHODIMP
     469               3 : nsJARChannel::SetLoadFlags(nsLoadFlags aLoadFlags)
     470                 : {
     471               3 :     mLoadFlags = aLoadFlags;
     472               3 :     return NS_OK;
     473                 : }
     474                 : 
     475                 : NS_IMETHODIMP
     476               0 : nsJARChannel::GetLoadGroup(nsILoadGroup **aLoadGroup)
     477                 : {
     478               0 :     NS_IF_ADDREF(*aLoadGroup = mLoadGroup);
     479               0 :     return NS_OK;
     480                 : }
     481                 : 
     482                 : NS_IMETHODIMP
     483               0 : nsJARChannel::SetLoadGroup(nsILoadGroup *aLoadGroup)
     484                 : {
     485               0 :     mLoadGroup = aLoadGroup;
     486               0 :     return NS_OK;
     487                 : }
     488                 : 
     489                 : //-----------------------------------------------------------------------------
     490                 : // nsIChannel
     491                 : //-----------------------------------------------------------------------------
     492                 : 
     493                 : NS_IMETHODIMP
     494               0 : nsJARChannel::GetOriginalURI(nsIURI **aURI)
     495                 : {
     496               0 :     *aURI = mOriginalURI;
     497               0 :     NS_ADDREF(*aURI);
     498               0 :     return NS_OK;
     499                 : }
     500                 : 
     501                 : NS_IMETHODIMP
     502               3 : nsJARChannel::SetOriginalURI(nsIURI *aURI)
     503                 : {
     504               3 :     NS_ENSURE_ARG_POINTER(aURI);
     505               3 :     mOriginalURI = aURI;
     506               3 :     return NS_OK;
     507                 : }
     508                 : 
     509                 : NS_IMETHODIMP
     510             202 : nsJARChannel::GetURI(nsIURI **aURI)
     511                 : {
     512             202 :     NS_IF_ADDREF(*aURI = mJarURI);
     513             202 :     return NS_OK;
     514                 : }
     515                 : 
     516                 : NS_IMETHODIMP
     517               0 : nsJARChannel::GetOwner(nsISupports **result)
     518                 : {
     519                 :     nsresult rv;
     520                 : 
     521               0 :     if (mOwner) {
     522               0 :         NS_ADDREF(*result = mOwner);
     523               0 :         return NS_OK;
     524                 :     }
     525                 : 
     526               0 :     if (!mJarInput) {
     527               0 :         *result = nsnull;
     528               0 :         return NS_OK;
     529                 :     }
     530                 : 
     531                 :     //-- Verify signature, if one is present, and set owner accordingly
     532               0 :     nsCOMPtr<nsIZipReader> jarReader;
     533               0 :     mJarInput->GetJarReader(getter_AddRefs(jarReader));
     534               0 :     if (!jarReader)
     535               0 :         return NS_ERROR_NOT_INITIALIZED;
     536                 : 
     537               0 :     nsCOMPtr<nsIPrincipal> cert;
     538               0 :     rv = jarReader->GetCertificatePrincipal(mJarEntry, getter_AddRefs(cert));
     539               0 :     if (NS_FAILED(rv)) return rv;
     540                 : 
     541               0 :     if (cert) {
     542               0 :         nsCAutoString certFingerprint;
     543               0 :         rv = cert->GetFingerprint(certFingerprint);
     544               0 :         if (NS_FAILED(rv)) return rv;
     545                 : 
     546               0 :         nsCAutoString subjectName;
     547               0 :         rv = cert->GetSubjectName(subjectName);
     548               0 :         if (NS_FAILED(rv)) return rv;
     549                 : 
     550               0 :         nsCAutoString prettyName;
     551               0 :         rv = cert->GetPrettyName(prettyName);
     552               0 :         if (NS_FAILED(rv)) return rv;
     553                 : 
     554               0 :         nsCOMPtr<nsISupports> certificate;
     555               0 :         rv = cert->GetCertificate(getter_AddRefs(certificate));
     556               0 :         if (NS_FAILED(rv)) return rv;
     557                 :         
     558                 :         nsCOMPtr<nsIScriptSecurityManager> secMan = 
     559               0 :                  do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
     560               0 :         if (NS_FAILED(rv)) return rv;
     561                 : 
     562               0 :         rv = secMan->GetCertificatePrincipal(certFingerprint, subjectName,
     563                 :                                              prettyName, certificate,
     564                 :                                              mJarBaseURI,
     565               0 :                                              getter_AddRefs(cert));
     566               0 :         if (NS_FAILED(rv)) return rv;
     567                 : 
     568               0 :         mOwner = do_QueryInterface(cert, &rv);
     569               0 :         if (NS_FAILED(rv)) return rv;
     570                 : 
     571               0 :         NS_ADDREF(*result = mOwner);
     572                 :     }
     573               0 :     return NS_OK;
     574                 : }
     575                 : 
     576                 : NS_IMETHODIMP
     577               1 : nsJARChannel::SetOwner(nsISupports *aOwner)
     578                 : {
     579               1 :     mOwner = aOwner;
     580               1 :     return NS_OK;
     581                 : }
     582                 : 
     583                 : NS_IMETHODIMP
     584               0 : nsJARChannel::GetNotificationCallbacks(nsIInterfaceRequestor **aCallbacks)
     585                 : {
     586               0 :     NS_IF_ADDREF(*aCallbacks = mCallbacks);
     587               0 :     return NS_OK;
     588                 : }
     589                 : 
     590                 : NS_IMETHODIMP
     591               0 : nsJARChannel::SetNotificationCallbacks(nsIInterfaceRequestor *aCallbacks)
     592                 : {
     593               0 :     mCallbacks = aCallbacks;
     594               0 :     return NS_OK;
     595                 : }
     596                 : 
     597                 : NS_IMETHODIMP 
     598               0 : nsJARChannel::GetSecurityInfo(nsISupports **aSecurityInfo)
     599                 : {
     600               0 :     NS_PRECONDITION(aSecurityInfo, "Null out param");
     601               0 :     NS_IF_ADDREF(*aSecurityInfo = mSecurityInfo);
     602               0 :     return NS_OK;
     603                 : }
     604                 : 
     605                 : NS_IMETHODIMP
     606               0 : nsJARChannel::GetContentType(nsACString &result)
     607                 : {
     608               0 :     if (mContentType.IsEmpty()) {
     609                 :         //
     610                 :         // generate content type and set it
     611                 :         //
     612               0 :         const char *ext = nsnull, *fileName = mJarEntry.get();
     613               0 :         PRInt32 len = mJarEntry.Length();
     614                 : 
     615                 :         // check if we're displaying a directory
     616                 :         // mJarEntry will be empty if we're trying to display
     617                 :         // the topmost directory in a zip, e.g. jar:foo.zip!/
     618               0 :         if (ENTRY_IS_DIRECTORY(mJarEntry)) {
     619               0 :             mContentType.AssignLiteral(APPLICATION_HTTP_INDEX_FORMAT);
     620                 :         }
     621                 :         else {
     622                 :             // not a directory, take a guess by its extension
     623               0 :             for (PRInt32 i = len-1; i >= 0; i--) {
     624               0 :                 if (fileName[i] == '.') {
     625               0 :                     ext = &fileName[i + 1];
     626               0 :                     break;
     627                 :                 }
     628                 :             }
     629               0 :             if (ext) {
     630               0 :                 nsIMIMEService *mimeServ = gJarHandler->MimeService();
     631               0 :                 if (mimeServ)
     632               0 :                     mimeServ->GetTypeFromExtension(nsDependentCString(ext), mContentType);
     633                 :             }
     634               0 :             if (mContentType.IsEmpty())
     635               0 :                 mContentType.AssignLiteral(UNKNOWN_CONTENT_TYPE);
     636                 :         }
     637                 :     }
     638               0 :     result = mContentType;
     639               0 :     return NS_OK;
     640                 : }
     641                 : 
     642                 : NS_IMETHODIMP
     643              97 : nsJARChannel::SetContentType(const nsACString &aContentType)
     644                 : {
     645                 :     // If someone gives us a type hint we should just use that type instead of
     646                 :     // doing our guessing.  So we don't care when this is being called.
     647                 : 
     648                 :     // mContentCharset is unchanged if not parsed
     649              97 :     NS_ParseContentType(aContentType, mContentType, mContentCharset);
     650              97 :     return NS_OK;
     651                 : }
     652                 : 
     653                 : NS_IMETHODIMP
     654               0 : nsJARChannel::GetContentCharset(nsACString &aContentCharset)
     655                 : {
     656                 :     // If someone gives us a charset hint we should just use that charset.
     657                 :     // So we don't care when this is being called.
     658               0 :     aContentCharset = mContentCharset;
     659               0 :     return NS_OK;
     660                 : }
     661                 : 
     662                 : NS_IMETHODIMP
     663               0 : nsJARChannel::SetContentCharset(const nsACString &aContentCharset)
     664                 : {
     665               0 :     mContentCharset = aContentCharset;
     666               0 :     return NS_OK;
     667                 : }
     668                 : 
     669                 : NS_IMETHODIMP
     670               1 : nsJARChannel::GetContentDisposition(PRUint32 *aContentDisposition)
     671                 : {
     672               1 :     if (mContentDispositionHeader.IsEmpty())
     673               1 :         return NS_ERROR_NOT_AVAILABLE;
     674                 : 
     675               0 :     *aContentDisposition = mContentDisposition;
     676               0 :     return NS_OK;
     677                 : }
     678                 : 
     679                 : NS_IMETHODIMP
     680               0 : nsJARChannel::GetContentDispositionFilename(nsAString &aContentDispositionFilename)
     681                 : {
     682               0 :     return NS_ERROR_NOT_AVAILABLE;
     683                 : }
     684                 : 
     685                 : NS_IMETHODIMP
     686               0 : nsJARChannel::GetContentDispositionHeader(nsACString &aContentDispositionHeader)
     687                 : {
     688               0 :     if (mContentDispositionHeader.IsEmpty())
     689               0 :         return NS_ERROR_NOT_AVAILABLE;
     690                 : 
     691               0 :     aContentDispositionHeader = mContentDispositionHeader;
     692               0 :     return NS_OK;
     693                 : }
     694                 : 
     695                 : NS_IMETHODIMP
     696              57 : nsJARChannel::GetContentLength(PRInt32 *result)
     697                 : {
     698                 :     // if content length is unknown, query mJarInput...
     699              57 :     if (mContentLength < 0 && mJarInput)
     700              57 :         mContentLength = mJarInput->GetContentLength();
     701                 : 
     702              57 :     *result = mContentLength;
     703              57 :     return NS_OK;
     704                 : }
     705                 : 
     706                 : NS_IMETHODIMP
     707               0 : nsJARChannel::SetContentLength(PRInt32 aContentLength)
     708                 : {
     709                 :     // XXX does this really make any sense at all?
     710               0 :     mContentLength = aContentLength;
     711               0 :     return NS_OK;
     712                 : }
     713                 : 
     714                 : NS_IMETHODIMP
     715             195 : nsJARChannel::Open(nsIInputStream **stream)
     716                 : {
     717             195 :     LOG(("nsJARChannel::Open [this=%x]\n", this));
     718                 : 
     719             195 :     NS_ENSURE_TRUE(!mJarInput, NS_ERROR_IN_PROGRESS);
     720             195 :     NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
     721                 : 
     722             195 :     mJarFile = nsnull;
     723             195 :     mIsUnsafe = true;
     724                 : 
     725             195 :     nsresult rv = EnsureJarInput(true);
     726             195 :     if (NS_FAILED(rv)) return rv;
     727                 : 
     728             193 :     if (!mJarInput)
     729               0 :         return NS_ERROR_UNEXPECTED;
     730                 : 
     731                 :     // force load the jar file now so GetContentLength will return a
     732                 :     // meaningful value once we return.
     733             193 :     rv = mJarInput->EnsureJarStream();
     734             193 :     if (NS_FAILED(rv)) return rv;
     735                 : 
     736             152 :     NS_ADDREF(*stream = mJarInput);
     737             152 :     return NS_OK;
     738                 : }
     739                 : 
     740                 : NS_IMETHODIMP
     741               2 : nsJARChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctx)
     742                 : {
     743               2 :     LOG(("nsJARChannel::AsyncOpen [this=%x]\n", this));
     744                 : 
     745               2 :     NS_ENSURE_ARG_POINTER(listener);
     746               1 :     NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
     747                 : 
     748               1 :     mJarFile = nsnull;
     749               1 :     mIsUnsafe = true;
     750                 : 
     751                 :     // Initialize mProgressSink
     752               1 :     NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup, mProgressSink);
     753                 : 
     754               1 :     nsresult rv = EnsureJarInput(false);
     755               1 :     if (NS_FAILED(rv)) return rv;
     756                 : 
     757                 :     // These variables must only be set if we're going to trigger an
     758                 :     // OnStartRequest, either from AsyncRead or OnDownloadComplete.
     759               1 :     mListener = listener;
     760               1 :     mListenerContext = ctx;
     761               1 :     mIsPending = true;
     762               1 :     if (mJarInput) {
     763                 :         // create input stream pump and call AsyncRead as a block
     764               0 :         rv = NS_NewInputStreamPump(getter_AddRefs(mPump), mJarInput);
     765               0 :         if (NS_SUCCEEDED(rv))
     766               0 :             rv = mPump->AsyncRead(this, nsnull);
     767                 : 
     768                 :         // If we failed to create the pump or initiate the AsyncRead,
     769                 :         // then we need to clear these variables.
     770               0 :         if (NS_FAILED(rv)) {
     771               0 :             mIsPending = false;
     772               0 :             mListenerContext = nsnull;
     773               0 :             mListener = nsnull;
     774               0 :             return rv;
     775                 :         }
     776                 :     }
     777                 : 
     778               1 :     if (mLoadGroup)
     779               0 :         mLoadGroup->AddRequest(this, nsnull);
     780                 : 
     781               1 :     return NS_OK;
     782                 : }
     783                 : 
     784                 : //-----------------------------------------------------------------------------
     785                 : // nsIJARChannel
     786                 : //-----------------------------------------------------------------------------
     787                 : NS_IMETHODIMP
     788               0 : nsJARChannel::GetIsUnsafe(bool *isUnsafe)
     789                 : {
     790               0 :     *isUnsafe = mIsUnsafe;
     791               0 :     return NS_OK;
     792                 : }
     793                 : 
     794                 : //-----------------------------------------------------------------------------
     795                 : // nsIDownloadObserver
     796                 : //-----------------------------------------------------------------------------
     797                 : 
     798                 : NS_IMETHODIMP
     799               1 : nsJARChannel::OnDownloadComplete(nsIDownloader *downloader,
     800                 :                                  nsIRequest    *request,
     801                 :                                  nsISupports   *context,
     802                 :                                  nsresult       status,
     803                 :                                  nsIFile       *file)
     804                 : {
     805                 :     nsresult rv;
     806                 : 
     807               2 :     nsCOMPtr<nsIChannel> channel(do_QueryInterface(request));
     808               1 :     if (channel) {
     809                 :         PRUint32 loadFlags;
     810               1 :         channel->GetLoadFlags(&loadFlags);
     811               1 :         if (loadFlags & LOAD_REPLACE) {
     812               0 :             mLoadFlags |= LOAD_REPLACE;
     813                 : 
     814               0 :             if (!mOriginalURI) {
     815               0 :                 SetOriginalURI(mJarURI);
     816                 :             }
     817                 : 
     818               0 :             nsCOMPtr<nsIURI> innerURI;
     819               0 :             rv = channel->GetURI(getter_AddRefs(innerURI));
     820               0 :             if (NS_SUCCEEDED(rv)) {
     821               0 :                 nsCOMPtr<nsIJARURI> newURI;
     822               0 :                 rv = mJarURI->CloneWithJARFile(innerURI,
     823               0 :                                                getter_AddRefs(newURI));
     824               0 :                 if (NS_SUCCEEDED(rv)) {
     825               0 :                     mJarURI = newURI;
     826                 :                 }
     827                 :             }
     828               0 :             if (NS_SUCCEEDED(status)) {
     829               0 :                 status = rv;
     830                 :             }
     831                 :         }
     832                 :     }
     833                 : 
     834               1 :     if (NS_SUCCEEDED(status) && channel) {
     835                 :         // Grab the security info from our base channel
     836               0 :         channel->GetSecurityInfo(getter_AddRefs(mSecurityInfo));
     837                 : 
     838               0 :         nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
     839               0 :         if (httpChannel) {
     840                 :             // We only want to run scripts if the server really intended to
     841                 :             // send us a JAR file.  Check the server-supplied content type for
     842                 :             // a JAR type.
     843               0 :             nsCAutoString header;
     844               0 :             httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("Content-Type"),
     845               0 :                                            header);
     846               0 :             nsCAutoString contentType;
     847               0 :             nsCAutoString charset;
     848               0 :             NS_ParseContentType(header, contentType, charset);
     849               0 :             nsCAutoString channelContentType;
     850               0 :             channel->GetContentType(channelContentType);
     851               0 :             mIsUnsafe = !(contentType.Equals(channelContentType) &&
     852               0 :                           (contentType.EqualsLiteral("application/java-archive") ||
     853               0 :                            contentType.EqualsLiteral("application/x-jar")));
     854                 :         } else {
     855               0 :             nsCOMPtr<nsIJARChannel> innerJARChannel(do_QueryInterface(channel));
     856               0 :             if (innerJARChannel) {
     857                 :                 bool unsafe;
     858               0 :                 innerJARChannel->GetIsUnsafe(&unsafe);
     859               0 :                 mIsUnsafe = unsafe;
     860                 :             }
     861                 :         }
     862                 : 
     863               0 :         channel->GetContentDispositionHeader(mContentDispositionHeader);
     864               0 :         mContentDisposition = NS_GetContentDispositionFromHeader(mContentDispositionHeader, this);
     865                 :     }
     866                 : 
     867               1 :     if (NS_SUCCEEDED(status) && mIsUnsafe &&
     868               0 :         !Preferences::GetBool("network.jar.open-unsafe-types", false)) {
     869               0 :         status = NS_ERROR_UNSAFE_CONTENT_TYPE;
     870                 :     }
     871                 : 
     872               1 :     if (NS_SUCCEEDED(status)) {
     873                 :         // Refuse to unpack view-source: jars even if open-unsafe-types is set.
     874               0 :         nsCOMPtr<nsIViewSourceChannel> viewSource = do_QueryInterface(channel);
     875               0 :         if (viewSource) {
     876               0 :             status = NS_ERROR_UNSAFE_CONTENT_TYPE;
     877                 :         }
     878                 :     }
     879                 : 
     880               1 :     if (NS_SUCCEEDED(status)) {
     881               0 :         mJarFile = file;
     882                 :     
     883               0 :         rv = CreateJarInput(nsnull);
     884               0 :         if (NS_SUCCEEDED(rv)) {
     885                 :             // create input stream pump
     886               0 :             rv = NS_NewInputStreamPump(getter_AddRefs(mPump), mJarInput);
     887               0 :             if (NS_SUCCEEDED(rv))
     888               0 :                 rv = mPump->AsyncRead(this, nsnull);
     889                 :         }
     890               0 :         status = rv;
     891                 :     }
     892                 : 
     893               1 :     if (NS_FAILED(status)) {
     894               1 :         mStatus = status;
     895               1 :         OnStartRequest(nsnull, nsnull);
     896               1 :         OnStopRequest(nsnull, nsnull, status);
     897                 :     }
     898                 : 
     899               1 :     return NS_OK;
     900                 : }
     901                 : 
     902                 : //-----------------------------------------------------------------------------
     903                 : // nsIStreamListener
     904                 : //-----------------------------------------------------------------------------
     905                 : 
     906                 : NS_IMETHODIMP
     907               1 : nsJARChannel::OnStartRequest(nsIRequest *req, nsISupports *ctx)
     908                 : {
     909               1 :     LOG(("nsJARChannel::OnStartRequest [this=%x %s]\n", this, mSpec.get()));
     910                 : 
     911               1 :     return mListener->OnStartRequest(this, mListenerContext);
     912                 : }
     913                 : 
     914                 : NS_IMETHODIMP
     915               1 : nsJARChannel::OnStopRequest(nsIRequest *req, nsISupports *ctx, nsresult status)
     916                 : {
     917               1 :     LOG(("nsJARChannel::OnStopRequest [this=%x %s status=%x]\n",
     918                 :         this, mSpec.get(), status));
     919                 : 
     920               1 :     if (NS_SUCCEEDED(mStatus))
     921               0 :         mStatus = status;
     922                 : 
     923               1 :     if (mListener) {
     924               1 :         mListener->OnStopRequest(this, mListenerContext, status);
     925               1 :         mListener = 0;
     926               1 :         mListenerContext = 0;
     927                 :     }
     928                 : 
     929               1 :     if (mLoadGroup)
     930               0 :         mLoadGroup->RemoveRequest(this, nsnull, status);
     931                 : 
     932               1 :     mPump = 0;
     933               1 :     NS_IF_RELEASE(mJarInput);
     934               1 :     mIsPending = false;
     935               1 :     mDownloader = 0; // this may delete the underlying jar file
     936                 : 
     937                 :     // Drop notification callbacks to prevent cycles.
     938               1 :     mCallbacks = 0;
     939               1 :     mProgressSink = 0;
     940                 : 
     941               1 :     return NS_OK;
     942                 : }
     943                 : 
     944                 : NS_IMETHODIMP
     945               0 : nsJARChannel::OnDataAvailable(nsIRequest *req, nsISupports *ctx,
     946                 :                                nsIInputStream *stream,
     947                 :                                PRUint32 offset, PRUint32 count)
     948                 : {
     949                 : #if defined(PR_LOGGING)
     950               0 :     LOG(("nsJARChannel::OnDataAvailable [this=%x %s]\n", this, mSpec.get()));
     951                 : #endif
     952                 : 
     953                 :     nsresult rv;
     954                 : 
     955               0 :     rv = mListener->OnDataAvailable(this, mListenerContext, stream, offset, count);
     956                 : 
     957                 :     // simply report progress here instead of hooking ourselves up as a
     958                 :     // nsITransportEventSink implementation.
     959                 :     // XXX do the 64-bit stuff for real
     960               0 :     if (mProgressSink && NS_SUCCEEDED(rv) && !(mLoadFlags & LOAD_BACKGROUND))
     961               0 :         mProgressSink->OnProgress(this, nsnull, PRUint64(offset + count),
     962               0 :                                   PRUint64(mContentLength));
     963                 : 
     964               0 :     return rv; // let the pump cancel on failure
     965                 : }

Generated by: LCOV version 1.7