LCOV - code coverage report
Current view: top level - dom/plugins/base - nsPluginStreamListenerPeer.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 633 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 61 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "nsPluginStreamListenerPeer.h"
       7             : #include "nsIContentPolicy.h"
       8             : #include "nsContentPolicyUtils.h"
       9             : #include "nsIDOMElement.h"
      10             : #include "nsIStreamConverterService.h"
      11             : #include "nsIStreamLoader.h"
      12             : #include "nsIHttpChannel.h"
      13             : #include "nsIHttpChannelInternal.h"
      14             : #include "nsIFileChannel.h"
      15             : #include "nsMimeTypes.h"
      16             : #include "nsISupportsPrimitives.h"
      17             : #include "nsNetCID.h"
      18             : #include "nsPluginInstanceOwner.h"
      19             : #include "nsPluginLogging.h"
      20             : #include "nsIURI.h"
      21             : #include "nsIURL.h"
      22             : #include "nsPluginHost.h"
      23             : #include "nsIByteRangeRequest.h"
      24             : #include "nsIMultiPartChannel.h"
      25             : #include "nsIInputStreamTee.h"
      26             : #include "nsPrintfCString.h"
      27             : #include "nsIScriptGlobalObject.h"
      28             : #include "nsIDocument.h"
      29             : #include "nsIWebNavigation.h"
      30             : #include "nsContentUtils.h"
      31             : #include "nsNetUtil.h"
      32             : #include "nsPluginNativeWindow.h"
      33             : #include "GeckoProfiler.h"
      34             : #include "nsPluginInstanceOwner.h"
      35             : #include "nsDataHashtable.h"
      36             : #include "NullPrincipal.h"
      37             : 
      38             : #define BYTERANGE_REQUEST_CONTEXT 0x01020304
      39             : 
      40             : // nsPluginByteRangeStreamListener
      41             : 
      42             : class nsPluginByteRangeStreamListener
      43             :   : public nsIStreamListener
      44             :   , public nsIInterfaceRequestor
      45             : {
      46             : public:
      47             :   explicit nsPluginByteRangeStreamListener(nsIWeakReference* aWeakPtr);
      48             : 
      49             :   NS_DECL_ISUPPORTS
      50             :   NS_DECL_NSIREQUESTOBSERVER
      51             :   NS_DECL_NSISTREAMLISTENER
      52             :   NS_DECL_NSIINTERFACEREQUESTOR
      53             : 
      54             : private:
      55             :   virtual ~nsPluginByteRangeStreamListener();
      56             : 
      57             :   nsCOMPtr<nsIStreamListener> mStreamConverter;
      58             :   nsWeakPtr mWeakPtrPluginStreamListenerPeer;
      59             :   bool mRemoveByteRangeRequest;
      60             : };
      61             : 
      62           0 : NS_IMPL_ISUPPORTS(nsPluginByteRangeStreamListener,
      63             :                   nsIRequestObserver,
      64             :                   nsIStreamListener,
      65             :                   nsIInterfaceRequestor)
      66             : 
      67           0 : nsPluginByteRangeStreamListener::nsPluginByteRangeStreamListener(nsIWeakReference* aWeakPtr)
      68             : {
      69           0 :   mWeakPtrPluginStreamListenerPeer = aWeakPtr;
      70           0 :   mRemoveByteRangeRequest = false;
      71           0 : }
      72             : 
      73           0 : nsPluginByteRangeStreamListener::~nsPluginByteRangeStreamListener()
      74             : {
      75           0 :   mStreamConverter = nullptr;
      76           0 :   mWeakPtrPluginStreamListenerPeer = nullptr;
      77           0 : }
      78             : 
      79             : /**
      80             :  * Unwrap any byte-range requests so that we can check whether the base channel
      81             :  * is being tracked properly.
      82             :  */
      83             : static nsCOMPtr<nsIRequest>
      84           0 : GetBaseRequest(nsIRequest* r)
      85             : {
      86           0 :   nsCOMPtr<nsIMultiPartChannel> mp = do_QueryInterface(r);
      87           0 :   if (!mp)
      88           0 :     return r;
      89             : 
      90           0 :   nsCOMPtr<nsIChannel> base;
      91           0 :   mp->GetBaseChannel(getter_AddRefs(base));
      92           0 :   return already_AddRefed<nsIRequest>(base.forget());
      93             : }
      94             : 
      95             : NS_IMETHODIMP
      96           0 : nsPluginByteRangeStreamListener::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
      97             : {
      98             :   nsresult rv;
      99             : 
     100           0 :   nsCOMPtr<nsIStreamListener> finalStreamListener = do_QueryReferent(mWeakPtrPluginStreamListenerPeer);
     101           0 :   if (!finalStreamListener)
     102           0 :     return NS_ERROR_FAILURE;
     103             : 
     104             :   nsPluginStreamListenerPeer *pslp =
     105           0 :     static_cast<nsPluginStreamListenerPeer*>(finalStreamListener.get());
     106             : 
     107             : #ifdef DEBUG
     108           0 :   nsCOMPtr<nsIRequest> baseRequest = GetBaseRequest(request);
     109             : #endif
     110           0 :   NS_ASSERTION(pslp->mRequests.IndexOfObject(baseRequest) != -1,
     111             :                "Untracked byte-range request?");
     112             : 
     113           0 :   nsCOMPtr<nsIStreamConverterService> serv = do_GetService(NS_STREAMCONVERTERSERVICE_CONTRACTID, &rv);
     114           0 :   if (NS_SUCCEEDED(rv)) {
     115           0 :     rv = serv->AsyncConvertData(MULTIPART_BYTERANGES,
     116             :                                 "*/*",
     117             :                                 finalStreamListener,
     118             :                                 nullptr,
     119           0 :                                 getter_AddRefs(mStreamConverter));
     120           0 :     if (NS_SUCCEEDED(rv)) {
     121           0 :       rv = mStreamConverter->OnStartRequest(request, ctxt);
     122           0 :       if (NS_SUCCEEDED(rv))
     123           0 :         return rv;
     124             :     }
     125             :   }
     126           0 :   mStreamConverter = nullptr;
     127             : 
     128           0 :   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(request));
     129           0 :   if (!httpChannel) {
     130           0 :     return NS_ERROR_FAILURE;
     131             :   }
     132             : 
     133           0 :   uint32_t responseCode = 0;
     134           0 :   rv = httpChannel->GetResponseStatus(&responseCode);
     135           0 :   if (NS_FAILED(rv)) {
     136           0 :     return NS_ERROR_FAILURE;
     137             :   }
     138             : 
     139           0 :   if (responseCode != 200) {
     140           0 :     uint32_t wantsAllNetworkStreams = 0;
     141           0 :     rv = pslp->GetPluginInstance()->GetValueFromPlugin(NPPVpluginWantsAllNetworkStreams,
     142             :                                                        &wantsAllNetworkStreams);
     143             :     // If the call returned an error code make sure we still use our default value.
     144           0 :     if (NS_FAILED(rv)) {
     145           0 :       wantsAllNetworkStreams = 0;
     146             :     }
     147             : 
     148           0 :     if (!wantsAllNetworkStreams){
     149           0 :       return NS_ERROR_FAILURE;
     150             :     }
     151             :   }
     152             : 
     153             :   // if server cannot continue with byte range (206 status) and sending us whole object (200 status)
     154             :   // reset this seekable stream & try serve it to plugin instance as a file
     155           0 :   mStreamConverter = finalStreamListener;
     156           0 :   mRemoveByteRangeRequest = true;
     157             : 
     158           0 :   rv = pslp->ServeStreamAsFile(request, ctxt);
     159           0 :   return rv;
     160             : }
     161             : 
     162             : NS_IMETHODIMP
     163           0 : nsPluginByteRangeStreamListener::OnStopRequest(nsIRequest *request, nsISupports *ctxt,
     164             :                                                nsresult status)
     165             : {
     166           0 :   if (!mStreamConverter)
     167           0 :     return NS_ERROR_FAILURE;
     168             : 
     169           0 :   nsCOMPtr<nsIStreamListener> finalStreamListener = do_QueryReferent(mWeakPtrPluginStreamListenerPeer);
     170           0 :   if (!finalStreamListener)
     171           0 :     return NS_ERROR_FAILURE;
     172             : 
     173             :   nsPluginStreamListenerPeer *pslp =
     174           0 :     static_cast<nsPluginStreamListenerPeer*>(finalStreamListener.get());
     175           0 :   bool found = pslp->mRequests.RemoveObject(request);
     176           0 :   if (!found) {
     177           0 :     NS_ERROR("OnStopRequest received for untracked byte-range request!");
     178             :   }
     179             : 
     180           0 :   if (mRemoveByteRangeRequest) {
     181             :     // remove byte range request from container
     182           0 :     nsCOMPtr<nsISupportsPRUint32> container = do_QueryInterface(ctxt);
     183           0 :     if (container) {
     184           0 :       uint32_t byteRangeRequest = 0;
     185           0 :       container->GetData(&byteRangeRequest);
     186           0 :       if (byteRangeRequest == BYTERANGE_REQUEST_CONTEXT) {
     187             :         // to allow properly finish nsPluginStreamListenerPeer->OnStopRequest()
     188             :         // set it to something that is not the byte range request.
     189           0 :         container->SetData(0);
     190             :       }
     191             :     } else {
     192           0 :       NS_WARNING("Bad state of nsPluginByteRangeStreamListener");
     193             :     }
     194             :   }
     195             : 
     196           0 :   return mStreamConverter->OnStopRequest(request, ctxt, status);
     197             : }
     198             : 
     199             : // CachedFileHolder
     200             : 
     201           0 : CachedFileHolder::CachedFileHolder(nsIFile* cacheFile)
     202           0 : : mFile(cacheFile)
     203             : {
     204           0 :   NS_ASSERTION(mFile, "Empty CachedFileHolder");
     205           0 : }
     206             : 
     207           0 : CachedFileHolder::~CachedFileHolder()
     208             : {
     209           0 :   mFile->Remove(false);
     210           0 : }
     211             : 
     212             : void
     213           0 : CachedFileHolder::AddRef()
     214             : {
     215           0 :   ++mRefCnt;
     216           0 :   NS_LOG_ADDREF(this, mRefCnt, "CachedFileHolder", sizeof(*this));
     217           0 : }
     218             : 
     219             : void
     220           0 : CachedFileHolder::Release()
     221             : {
     222           0 :   --mRefCnt;
     223           0 :   NS_LOG_RELEASE(this, mRefCnt, "CachedFileHolder");
     224           0 :   if (0 == mRefCnt)
     225           0 :     delete this;
     226           0 : }
     227             : 
     228             : 
     229             : NS_IMETHODIMP
     230           0 : nsPluginByteRangeStreamListener::OnDataAvailable(nsIRequest *request, nsISupports *ctxt,
     231             :                                                  nsIInputStream *inStr,
     232             :                                                  uint64_t sourceOffset,
     233             :                                                  uint32_t count)
     234             : {
     235           0 :   if (!mStreamConverter)
     236           0 :     return NS_ERROR_FAILURE;
     237             : 
     238           0 :   nsCOMPtr<nsIStreamListener> finalStreamListener = do_QueryReferent(mWeakPtrPluginStreamListenerPeer);
     239           0 :   if (!finalStreamListener)
     240           0 :     return NS_ERROR_FAILURE;
     241             : 
     242           0 :   return mStreamConverter->OnDataAvailable(request, ctxt, inStr, sourceOffset, count);
     243             : }
     244             : 
     245             : NS_IMETHODIMP
     246           0 : nsPluginByteRangeStreamListener::GetInterface(const nsIID& aIID, void** result)
     247             : {
     248             :   // Forward interface requests to our parent
     249           0 :   nsCOMPtr<nsIInterfaceRequestor> finalStreamListener = do_QueryReferent(mWeakPtrPluginStreamListenerPeer);
     250           0 :   if (!finalStreamListener)
     251           0 :     return NS_ERROR_FAILURE;
     252             : 
     253           0 :   return finalStreamListener->GetInterface(aIID, result);
     254             : }
     255             : 
     256             : // nsPluginStreamListenerPeer
     257             : 
     258           0 : NS_IMPL_ISUPPORTS(nsPluginStreamListenerPeer,
     259             :                   nsIStreamListener,
     260             :                   nsIRequestObserver,
     261             :                   nsIHttpHeaderVisitor,
     262             :                   nsISupportsWeakReference,
     263             :                   nsIInterfaceRequestor,
     264             :                   nsIChannelEventSink)
     265             : 
     266           0 : nsPluginStreamListenerPeer::nsPluginStreamListenerPeer()
     267             : {
     268           0 :   mStreamType = NP_NORMAL;
     269           0 :   mStartBinding = false;
     270           0 :   mAbort = false;
     271           0 :   mRequestFailed = false;
     272             : 
     273           0 :   mPendingRequests = 0;
     274           0 :   mHaveFiredOnStartRequest = false;
     275           0 :   mDataForwardToRequest = nullptr;
     276             : 
     277           0 :   mUseLocalCache = false;
     278           0 :   mSeekable = false;
     279           0 :   mModified = 0;
     280           0 :   mStreamOffset = 0;
     281           0 :   mStreamComplete = 0;
     282           0 : }
     283             : 
     284           0 : nsPluginStreamListenerPeer::~nsPluginStreamListenerPeer()
     285             : {
     286             : #ifdef PLUGIN_LOGGING
     287             :   MOZ_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
     288             :          ("nsPluginStreamListenerPeer::dtor this=%p, url=%s\n",this, mURLSpec.get()));
     289             : #endif
     290             : 
     291           0 :   if (mPStreamListener) {
     292           0 :     mPStreamListener->SetStreamListenerPeer(nullptr);
     293             :   }
     294             : 
     295             :   // close FD of mFileCacheOutputStream if it's still open
     296             :   // or we won't be able to remove the cache file
     297           0 :   if (mFileCacheOutputStream)
     298           0 :     mFileCacheOutputStream = nullptr;
     299             : 
     300           0 :   delete mDataForwardToRequest;
     301             : 
     302           0 :   if (mPluginInstance)
     303           0 :     mPluginInstance->FileCachedStreamListeners()->RemoveElement(this);
     304           0 : }
     305             : 
     306             : // Called as a result of GetURL and PostURL, or by the host in the case of the
     307             : // initial plugin stream.
     308           0 : nsresult nsPluginStreamListenerPeer::Initialize(nsIURI *aURL,
     309             :                                                 nsNPAPIPluginInstance *aInstance,
     310             :                                                 nsNPAPIPluginStreamListener* aListener)
     311             : {
     312             : #ifdef PLUGIN_LOGGING
     313             :   MOZ_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
     314             :           ("nsPluginStreamListenerPeer::Initialize instance=%p, url=%s\n",
     315             :            aInstance, aURL ? aURL->GetSpecOrDefault().get() : ""));
     316             : 
     317             :   PR_LogFlush();
     318             : #endif
     319             : 
     320             :   // Not gonna work out
     321           0 :   if (!aInstance) {
     322           0 :     return NS_ERROR_FAILURE;
     323             :   }
     324             : 
     325           0 :   mURL = aURL;
     326             : 
     327           0 :   NS_ASSERTION(mPluginInstance == nullptr,
     328             :                "nsPluginStreamListenerPeer::Initialize mPluginInstance != nullptr");
     329           0 :   mPluginInstance = aInstance;
     330             : 
     331             :   // If the plugin did not request this stream, e.g. the initial stream, we wont
     332             :   // have a nsNPAPIPluginStreamListener yet - this will be handled by
     333             :   // SetUpStreamListener
     334           0 :   if (aListener) {
     335           0 :     mPStreamListener = aListener;
     336           0 :     mPStreamListener->SetStreamListenerPeer(this);
     337             :   }
     338             : 
     339           0 :   mPendingRequests = 1;
     340             : 
     341           0 :   mDataForwardToRequest = new nsDataHashtable<nsUint32HashKey, uint32_t>();
     342             : 
     343           0 :   return NS_OK;
     344             : }
     345             : 
     346             : // SetupPluginCacheFile is called if we have to save the stream to disk.
     347             : //
     348             : // These files will be deleted when the host is destroyed.
     349             : //
     350             : // TODO? What if we fill up the the dest dir?
     351             : nsresult
     352           0 : nsPluginStreamListenerPeer::SetupPluginCacheFile(nsIChannel* channel)
     353             : {
     354           0 :   nsresult rv = NS_OK;
     355             : 
     356           0 :   bool useExistingCacheFile = false;
     357           0 :   RefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
     358             : 
     359             :   // Look for an existing cache file for the URI.
     360           0 :   nsTArray< RefPtr<nsNPAPIPluginInstance> > *instances = pluginHost->InstanceArray();
     361           0 :   for (uint32_t i = 0; i < instances->Length(); i++) {
     362             :     // most recent streams are at the end of list
     363           0 :     nsTArray<nsPluginStreamListenerPeer*> *streamListeners = instances->ElementAt(i)->FileCachedStreamListeners();
     364           0 :     for (int32_t i = streamListeners->Length() - 1; i >= 0; --i) {
     365           0 :       nsPluginStreamListenerPeer *lp = streamListeners->ElementAt(i);
     366           0 :       if (lp && lp->mLocalCachedFileHolder) {
     367           0 :         useExistingCacheFile = lp->UseExistingPluginCacheFile(this);
     368           0 :         if (useExistingCacheFile) {
     369           0 :           mLocalCachedFileHolder = lp->mLocalCachedFileHolder;
     370           0 :           break;
     371             :         }
     372             :       }
     373           0 :       if (useExistingCacheFile)
     374           0 :         break;
     375             :     }
     376             :   }
     377             : 
     378             :   // Create a new cache file if one could not be found.
     379           0 :   if (!useExistingCacheFile) {
     380           0 :     nsCOMPtr<nsIFile> pluginTmp;
     381           0 :     rv = nsPluginHost::GetPluginTempDir(getter_AddRefs(pluginTmp));
     382           0 :     if (NS_FAILED(rv)) {
     383           0 :       return rv;
     384             :     }
     385             : 
     386             :     // Get the filename from the channel
     387           0 :     nsCOMPtr<nsIURI> uri;
     388           0 :     rv = channel->GetURI(getter_AddRefs(uri));
     389           0 :     if (NS_FAILED(rv)) return rv;
     390             : 
     391           0 :     nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
     392           0 :     if (!url)
     393           0 :       return NS_ERROR_FAILURE;
     394             : 
     395           0 :     nsAutoCString filename;
     396           0 :     url->GetFileName(filename);
     397           0 :     if (NS_FAILED(rv))
     398           0 :       return rv;
     399             : 
     400             :     // Create a file to save our stream into. Should we scramble the name?
     401           0 :     filename.Insert(NS_LITERAL_CSTRING("plugin-"), 0);
     402           0 :     rv = pluginTmp->AppendNative(filename);
     403           0 :     if (NS_FAILED(rv))
     404           0 :       return rv;
     405             : 
     406             :     // Yes, make it unique.
     407           0 :     rv = pluginTmp->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
     408           0 :     if (NS_FAILED(rv))
     409           0 :       return rv;
     410             : 
     411             :     // create a file output stream to write to...
     412           0 :     rv = NS_NewLocalFileOutputStream(getter_AddRefs(mFileCacheOutputStream), pluginTmp, -1, 00600);
     413           0 :     if (NS_FAILED(rv))
     414           0 :       return rv;
     415             : 
     416             :     // save the file.
     417           0 :     mLocalCachedFileHolder = new CachedFileHolder(pluginTmp);
     418             :   }
     419             : 
     420             :   // add this listenerPeer to list of stream peers for this instance
     421           0 :   mPluginInstance->FileCachedStreamListeners()->AppendElement(this);
     422             : 
     423           0 :   return rv;
     424             : }
     425             : 
     426             : NS_IMETHODIMP
     427           0 : nsPluginStreamListenerPeer::OnStartRequest(nsIRequest *request,
     428             :                                            nsISupports* aContext)
     429             : {
     430           0 :   nsresult rv = NS_OK;
     431           0 :   AUTO_PROFILER_LABEL("nsPluginStreamListenerPeer::OnStartRequest", OTHER);
     432             : 
     433           0 :   nsCOMPtr<nsIRequest> baseRequest = GetBaseRequest(request);
     434           0 :   if (mRequests.IndexOfObject(baseRequest) == -1) {
     435           0 :     NS_ASSERTION(mRequests.Count() == 0,
     436             :                  "Only our initial stream should be unknown!");
     437           0 :     TrackRequest(request);
     438             :   }
     439             : 
     440           0 :   if (mHaveFiredOnStartRequest) {
     441           0 :     return NS_OK;
     442             :   }
     443             : 
     444           0 :   mHaveFiredOnStartRequest = true;
     445             : 
     446           0 :   nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
     447           0 :   NS_ENSURE_TRUE(channel, NS_ERROR_FAILURE);
     448             : 
     449             :   // deal with 404 (Not Found) HTTP response,
     450             :   // just return, this causes the request to be ignored.
     451           0 :   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
     452           0 :   if (httpChannel) {
     453           0 :     uint32_t responseCode = 0;
     454           0 :     rv = httpChannel->GetResponseStatus(&responseCode);
     455           0 :     if (NS_FAILED(rv)) {
     456             :       // NPP_Notify() will be called from OnStopRequest
     457             :       // in nsNPAPIPluginStreamListener::CleanUpStream
     458             :       // return error will cancel this request
     459             :       // ...and we also need to tell the plugin that
     460           0 :       mRequestFailed = true;
     461           0 :       return NS_ERROR_FAILURE;
     462             :     }
     463             : 
     464           0 :     if (responseCode > 206) { // not normal
     465           0 :       uint32_t wantsAllNetworkStreams = 0;
     466             : 
     467             :       // We don't always have an instance here already, but if we do, check
     468             :       // to see if it wants all streams.
     469           0 :       if (mPluginInstance) {
     470           0 :         rv = mPluginInstance->GetValueFromPlugin(NPPVpluginWantsAllNetworkStreams,
     471           0 :                                                  &wantsAllNetworkStreams);
     472             :         // If the call returned an error code make sure we still use our default value.
     473           0 :         if (NS_FAILED(rv)) {
     474           0 :           wantsAllNetworkStreams = 0;
     475             :         }
     476             :       }
     477             : 
     478           0 :       if (!wantsAllNetworkStreams) {
     479           0 :         mRequestFailed = true;
     480           0 :         return NS_ERROR_FAILURE;
     481             :       }
     482             :     }
     483             :   }
     484             : 
     485           0 :   nsAutoCString contentType;
     486           0 :   rv = channel->GetContentType(contentType);
     487           0 :   if (NS_FAILED(rv))
     488           0 :     return rv;
     489             : 
     490             :   // Check ShouldProcess with content policy
     491           0 :   RefPtr<nsPluginInstanceOwner> owner;
     492           0 :   if (mPluginInstance) {
     493           0 :     owner = mPluginInstance->GetOwner();
     494             :   }
     495           0 :   nsCOMPtr<nsIDOMElement> element;
     496           0 :   nsCOMPtr<nsIDocument> doc;
     497           0 :   if (owner) {
     498           0 :     owner->GetDOMElement(getter_AddRefs(element));
     499           0 :     owner->GetDocument(getter_AddRefs(doc));
     500             :   }
     501           0 :   nsCOMPtr<nsIPrincipal> principal = doc ? doc->NodePrincipal() : nullptr;
     502             : 
     503           0 :   int16_t shouldLoad = nsIContentPolicy::ACCEPT;
     504           0 :   rv = NS_CheckContentProcessPolicy(nsIContentPolicy::TYPE_OBJECT_SUBREQUEST,
     505             :                                     mURL,
     506             :                                     principal,
     507             :                                     element,
     508             :                                     contentType,
     509             :                                     nullptr,
     510           0 :                                     &shouldLoad);
     511           0 :   if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
     512           0 :     mRequestFailed = true;
     513           0 :     return NS_ERROR_CONTENT_BLOCKED;
     514             :   }
     515             : 
     516             :   // Get the notification callbacks from the channel and save it as
     517             :   // week ref we'll use it in nsPluginStreamInfo::RequestRead() when
     518             :   // we'll create channel for byte range request.
     519           0 :   nsCOMPtr<nsIInterfaceRequestor> callbacks;
     520           0 :   channel->GetNotificationCallbacks(getter_AddRefs(callbacks));
     521           0 :   if (callbacks)
     522           0 :     mWeakPtrChannelCallbacks = do_GetWeakReference(callbacks);
     523             : 
     524           0 :   nsCOMPtr<nsILoadGroup> loadGroup;
     525           0 :   channel->GetLoadGroup(getter_AddRefs(loadGroup));
     526           0 :   if (loadGroup)
     527           0 :     mWeakPtrChannelLoadGroup = do_GetWeakReference(loadGroup);
     528             : 
     529             :   int64_t length;
     530           0 :   rv = channel->GetContentLength(&length);
     531             : 
     532             :   // it's possible for the server to not send a Content-Length.
     533             :   // we should still work in this case.
     534           0 :   if (NS_FAILED(rv) || length < 0 || length > UINT32_MAX) {
     535             :     // check out if this is file channel
     536           0 :     nsCOMPtr<nsIFileChannel> fileChannel = do_QueryInterface(channel);
     537           0 :     if (fileChannel) {
     538             :       // file does not exist
     539           0 :       mRequestFailed = true;
     540           0 :       return NS_ERROR_FAILURE;
     541             :     }
     542           0 :     mLength = 0;
     543             :   }
     544             :   else {
     545           0 :     mLength = uint32_t(length);
     546             :   }
     547             : 
     548           0 :   nsCOMPtr<nsIURI> aURL;
     549           0 :   rv = channel->GetURI(getter_AddRefs(aURL));
     550           0 :   if (NS_FAILED(rv))
     551           0 :     return rv;
     552             : 
     553           0 :   aURL->GetSpec(mURLSpec);
     554             : 
     555           0 :   if (!contentType.IsEmpty())
     556           0 :     mContentType = contentType;
     557             : 
     558             : #ifdef PLUGIN_LOGGING
     559             :   MOZ_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NOISY,
     560             :          ("nsPluginStreamListenerPeer::OnStartRequest this=%p request=%p mime=%s, url=%s\n",
     561             :           this, request, contentType.get(), mURLSpec.get()));
     562             : 
     563             :   PR_LogFlush();
     564             : #endif
     565             : 
     566             :   // Set up the stream listener...
     567           0 :   rv = SetUpStreamListener(request, aURL);
     568           0 :   if (NS_FAILED(rv)) {
     569           0 :     return rv;
     570             :   }
     571             : 
     572           0 :   return rv;
     573             : }
     574             : 
     575           0 : NS_IMETHODIMP nsPluginStreamListenerPeer::OnProgress(nsIRequest *request,
     576             :                                                      nsISupports* aContext,
     577             :                                                      int64_t aProgress,
     578             :                                                      int64_t aProgressMax)
     579             : {
     580           0 :   nsresult rv = NS_OK;
     581           0 :   return rv;
     582             : }
     583             : 
     584           0 : NS_IMETHODIMP nsPluginStreamListenerPeer::OnStatus(nsIRequest *request,
     585             :                                                    nsISupports* aContext,
     586             :                                                    nsresult aStatus,
     587             :                                                    const char16_t* aStatusArg)
     588             : {
     589           0 :   return NS_OK;
     590             : }
     591             : 
     592             : nsresult
     593           0 : nsPluginStreamListenerPeer::GetContentType(char** result)
     594             : {
     595           0 :   *result = const_cast<char*>(mContentType.get());
     596           0 :   return NS_OK;
     597             : }
     598             : 
     599             : 
     600             : nsresult
     601           0 : nsPluginStreamListenerPeer::IsSeekable(bool* result)
     602             : {
     603           0 :   *result = mSeekable;
     604           0 :   return NS_OK;
     605             : }
     606             : 
     607             : nsresult
     608           0 : nsPluginStreamListenerPeer::GetLength(uint32_t* result)
     609             : {
     610           0 :   *result = mLength;
     611           0 :   return NS_OK;
     612             : }
     613             : 
     614             : nsresult
     615           0 : nsPluginStreamListenerPeer::GetLastModified(uint32_t* result)
     616             : {
     617           0 :   *result = mModified;
     618           0 :   return NS_OK;
     619             : }
     620             : 
     621             : nsresult
     622           0 : nsPluginStreamListenerPeer::GetURL(const char** result)
     623             : {
     624           0 :   *result = mURLSpec.get();
     625           0 :   return NS_OK;
     626             : }
     627             : 
     628             : void
     629           0 : nsPluginStreamListenerPeer::MakeByteRangeString(NPByteRange* aRangeList, nsACString &rangeRequest,
     630             :                                                 int32_t *numRequests)
     631             : {
     632           0 :   rangeRequest.Truncate();
     633           0 :   *numRequests  = 0;
     634             :   //the string should look like this: bytes=500-700,601-999
     635           0 :   if (!aRangeList)
     636           0 :     return;
     637             : 
     638           0 :   int32_t requestCnt = 0;
     639           0 :   nsAutoCString string("bytes=");
     640             : 
     641           0 :   for (NPByteRange * range = aRangeList; range != nullptr; range = range->next) {
     642             :     // XXX zero length?
     643           0 :     if (!range->length)
     644           0 :       continue;
     645             : 
     646             :     // XXX needs to be fixed for negative offsets
     647           0 :     string.AppendInt(range->offset);
     648           0 :     string.Append('-');
     649           0 :     string.AppendInt(range->offset + range->length - 1);
     650           0 :     if (range->next)
     651           0 :       string.Append(',');
     652             : 
     653           0 :     requestCnt++;
     654             :   }
     655             : 
     656             :   // get rid of possible trailing comma
     657           0 :   string.Trim(",", false);
     658             : 
     659           0 :   rangeRequest = string;
     660           0 :   *numRequests  = requestCnt;
     661           0 :   return;
     662             : }
     663             : 
     664             : // XXX: Converting the channel within nsPluginStreamListenerPeer
     665             : // to use asyncOpen2() and do not want to touch the fragile logic
     666             : // of byte range requests. Hence we just introduce this lightweight
     667             : // wrapper to proxy the context.
     668             : class PluginContextProxy final : public nsIStreamListener
     669             : {
     670             : public:
     671             :   NS_DECL_ISUPPORTS
     672             : 
     673           0 :   PluginContextProxy(nsIStreamListener *aListener, nsISupports* aContext)
     674           0 :     : mListener(aListener)
     675           0 :     , mContext(aContext)
     676             :   {
     677           0 :     MOZ_ASSERT(aListener);
     678           0 :     MOZ_ASSERT(aContext);
     679           0 :   }
     680             : 
     681             :   NS_IMETHOD
     682           0 :   OnDataAvailable(nsIRequest* aRequest,
     683             :                   nsISupports* aContext,
     684             :                   nsIInputStream *aIStream,
     685             :                   uint64_t aSourceOffset,
     686             :                   uint32_t aLength) override
     687             :   {
     688             :     // Proxy OnDataAvailable using the internal context
     689           0 :     return mListener->OnDataAvailable(aRequest,
     690             :                                       mContext,
     691             :                                       aIStream,
     692             :                                       aSourceOffset,
     693           0 :                                       aLength);
     694             :   }
     695             : 
     696             :   NS_IMETHOD
     697           0 :   OnStartRequest(nsIRequest* aRequest, nsISupports* aContext) override
     698             :   {
     699             :     // Proxy OnStartRequest using the internal context
     700           0 :     return mListener->OnStartRequest(aRequest, mContext);
     701             :   }
     702             : 
     703             :   NS_IMETHOD
     704           0 :   OnStopRequest(nsIRequest* aRequest, nsISupports* aContext,
     705             :                 nsresult aStatusCode) override
     706             :   {
     707             :     // Proxy OnStopRequest using the inernal context
     708           0 :     return mListener->OnStopRequest(aRequest,
     709             :                                     mContext,
     710           0 :                                     aStatusCode);
     711             :   }
     712             : 
     713             : private:
     714           0 :   ~PluginContextProxy() {}
     715             :   nsCOMPtr<nsIStreamListener> mListener;
     716             :   nsCOMPtr<nsISupports> mContext;
     717             : };
     718             : 
     719           0 : NS_IMPL_ISUPPORTS(PluginContextProxy, nsIStreamListener)
     720             : 
     721             : nsresult
     722           0 : nsPluginStreamListenerPeer::RequestRead(NPByteRange* rangeList)
     723             : {
     724           0 :   nsAutoCString rangeString;
     725             :   int32_t numRequests;
     726             : 
     727           0 :   MakeByteRangeString(rangeList, rangeString, &numRequests);
     728             : 
     729           0 :   if (numRequests == 0)
     730           0 :     return NS_ERROR_FAILURE;
     731             : 
     732           0 :   nsresult rv = NS_OK;
     733             : 
     734           0 :   RefPtr<nsPluginInstanceOwner> owner = mPluginInstance->GetOwner();
     735           0 :   nsCOMPtr<nsIDOMElement> element;
     736           0 :   nsCOMPtr<nsIDocument> doc;
     737           0 :   if (owner) {
     738           0 :     rv = owner->GetDOMElement(getter_AddRefs(element));
     739           0 :     NS_ENSURE_SUCCESS(rv, rv);
     740           0 :     rv = owner->GetDocument(getter_AddRefs(doc));
     741           0 :     NS_ENSURE_SUCCESS(rv, rv);
     742             :   }
     743             : 
     744           0 :   nsCOMPtr<nsIInterfaceRequestor> callbacks = do_QueryReferent(mWeakPtrChannelCallbacks);
     745           0 :   nsCOMPtr<nsILoadGroup> loadGroup = do_QueryReferent(mWeakPtrChannelLoadGroup);
     746             : 
     747           0 :   nsCOMPtr<nsIChannel> channel;
     748           0 :   nsCOMPtr<nsINode> requestingNode(do_QueryInterface(element));
     749           0 :   if (requestingNode) {
     750           0 :     rv = NS_NewChannel(getter_AddRefs(channel),
     751             :                        mURL,
     752             :                        requestingNode,
     753             :                        nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
     754             :                        nsIContentPolicy::TYPE_OTHER,
     755             :                        loadGroup,
     756             :                        callbacks,
     757             :                        nsIChannel::LOAD_BYPASS_SERVICE_WORKER);
     758             :   }
     759             :   else {
     760             :     // In this else branch we really don't know where the load is coming
     761             :     // from. Let's fall back to using the SystemPrincipal for such Plugins.
     762           0 :     rv = NS_NewChannel(getter_AddRefs(channel),
     763             :                        mURL,
     764             :                        nsContentUtils::GetSystemPrincipal(),
     765             :                        nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
     766             :                        nsIContentPolicy::TYPE_OTHER,
     767             :                        loadGroup,
     768             :                        callbacks,
     769             :                        nsIChannel::LOAD_BYPASS_SERVICE_WORKER);
     770             :   }
     771             : 
     772           0 :   if (NS_FAILED(rv))
     773           0 :     return rv;
     774             : 
     775           0 :   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
     776           0 :   if (!httpChannel)
     777           0 :     return NS_ERROR_FAILURE;
     778             : 
     779           0 :   rv = httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Range"), rangeString, false);
     780           0 :   MOZ_ASSERT(NS_SUCCEEDED(rv));
     781             : 
     782           0 :   mAbort = true; // instruct old stream listener to cancel
     783             :   // the request on the next ODA.
     784             : 
     785           0 :   nsCOMPtr<nsIStreamListener> converter;
     786             : 
     787           0 :   if (numRequests == 1) {
     788           0 :     converter = this;
     789             :     // set current stream offset equal to the first offset in the range list
     790             :     // it will work for single byte range request
     791             :     // for multy range we'll reset it in ODA
     792           0 :     SetStreamOffset(rangeList->offset);
     793             :   } else {
     794             :     nsWeakPtr weakpeer =
     795           0 :     do_GetWeakReference(static_cast<nsISupportsWeakReference*>(this));
     796           0 :     converter = new nsPluginByteRangeStreamListener(weakpeer);
     797             :   }
     798             : 
     799           0 :   mPendingRequests += numRequests;
     800             : 
     801           0 :   nsCOMPtr<nsISupportsPRUint32> container = do_CreateInstance(NS_SUPPORTS_PRUINT32_CONTRACTID, &rv);
     802           0 :   NS_ENSURE_SUCCESS(rv, rv);
     803           0 :   rv = container->SetData(BYTERANGE_REQUEST_CONTEXT);
     804           0 :   NS_ENSURE_SUCCESS(rv, rv);
     805             : 
     806             :   RefPtr<PluginContextProxy> pluginContextProxy =
     807           0 :     new PluginContextProxy(converter, container);
     808           0 :   rv = channel->AsyncOpen2(pluginContextProxy);
     809           0 :   NS_ENSURE_SUCCESS(rv, rv);
     810           0 :   TrackRequest(channel);
     811           0 :   return NS_OK;
     812             : }
     813             : 
     814             : nsresult
     815           0 : nsPluginStreamListenerPeer::GetStreamOffset(int32_t* result)
     816             : {
     817           0 :   *result = mStreamOffset;
     818           0 :   return NS_OK;
     819             : }
     820             : 
     821             : nsresult
     822           0 : nsPluginStreamListenerPeer::SetStreamOffset(int32_t value)
     823             : {
     824           0 :   mStreamOffset = value;
     825           0 :   return NS_OK;
     826             : }
     827             : 
     828           0 : nsresult nsPluginStreamListenerPeer::ServeStreamAsFile(nsIRequest *request,
     829             :                                                        nsISupports* aContext)
     830             : {
     831           0 :   if (!mPluginInstance)
     832           0 :     return NS_ERROR_FAILURE;
     833             : 
     834             :   // mPluginInstance->Stop calls mPStreamListener->CleanUpStream(), so stream will be properly clean up
     835           0 :   mPluginInstance->Stop();
     836           0 :   mPluginInstance->Start();
     837           0 :   RefPtr<nsPluginInstanceOwner> owner = mPluginInstance->GetOwner();
     838           0 :   if (owner) {
     839           0 :     NPWindow* window = nullptr;
     840           0 :     owner->GetWindow(window);
     841             : #if (MOZ_WIDGET_GTK == 2)
     842             :     // Should call GetPluginPort() here.
     843             :     // This part is copied from nsPluginInstanceOwner::GetPluginPort().
     844             :     nsCOMPtr<nsIWidget> widget;
     845             :     ((nsPluginNativeWindow*)window)->GetPluginWidget(getter_AddRefs(widget));
     846             :     if (widget) {
     847             :       window->window = widget->GetNativeData(NS_NATIVE_PLUGIN_PORT);
     848             :     }
     849             : #endif
     850           0 :     owner->CallSetWindow();
     851             :   }
     852             : 
     853           0 :   mSeekable = false;
     854           0 :   mPStreamListener->OnStartBinding(this);
     855           0 :   mStreamOffset = 0;
     856             : 
     857             :   // force the plugin to use stream as file
     858           0 :   mStreamType = NP_ASFILE;
     859             : 
     860           0 :   nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
     861           0 :   if (channel) {
     862           0 :     SetupPluginCacheFile(channel);
     863             :   }
     864             : 
     865             :   // unset mPendingRequests
     866           0 :   mPendingRequests = 0;
     867             : 
     868           0 :   return NS_OK;
     869             : }
     870             : 
     871             : bool
     872           0 : nsPluginStreamListenerPeer::UseExistingPluginCacheFile(nsPluginStreamListenerPeer* psi)
     873             : {
     874           0 :   NS_ENSURE_TRUE(psi, false);
     875             : 
     876           0 :   if (psi->mLength == mLength &&
     877           0 :       psi->mModified == mModified &&
     878           0 :       mStreamComplete &&
     879           0 :       mURLSpec.Equals(psi->mURLSpec))
     880             :   {
     881           0 :     return true;
     882             :   }
     883           0 :   return false;
     884             : }
     885             : 
     886           0 : NS_IMETHODIMP nsPluginStreamListenerPeer::OnDataAvailable(nsIRequest *request,
     887             :                                                           nsISupports* aContext,
     888             :                                                           nsIInputStream *aIStream,
     889             :                                                           uint64_t sourceOffset,
     890             :                                                           uint32_t aLength)
     891             : {
     892           0 :   nsCOMPtr<nsIRequest> baseRequest = GetBaseRequest(request);
     893           0 :   if (mRequests.IndexOfObject(baseRequest) == -1) {
     894           0 :     MOZ_ASSERT(false, "Received OnDataAvailable for untracked request.");
     895             :     return NS_ERROR_UNEXPECTED;
     896             :   }
     897             : 
     898           0 :   if (mRequestFailed)
     899           0 :     return NS_ERROR_FAILURE;
     900             : 
     901           0 :   if (mAbort) {
     902           0 :     uint32_t byteRangeRequest = 0;  // set it to something that is not the byte range request.
     903           0 :     nsCOMPtr<nsISupportsPRUint32> container = do_QueryInterface(aContext);
     904           0 :     if (container)
     905           0 :       container->GetData(&byteRangeRequest);
     906             : 
     907           0 :     if (byteRangeRequest != BYTERANGE_REQUEST_CONTEXT) {
     908             :       // this is not one of our range requests
     909           0 :       mAbort = false;
     910           0 :       return NS_BINDING_ABORTED;
     911             :     }
     912             :   }
     913             : 
     914           0 :   nsresult rv = NS_OK;
     915             : 
     916           0 :   if (!mPStreamListener)
     917           0 :     return NS_ERROR_FAILURE;
     918             : 
     919           0 :   const char * url = nullptr;
     920           0 :   GetURL(&url);
     921             : 
     922           0 :   PLUGIN_LOG(PLUGIN_LOG_NOISY,
     923             :              ("nsPluginStreamListenerPeer::OnDataAvailable this=%p request=%p, offset=%" PRIu64 ", length=%u, url=%s\n",
     924             :               this, request, sourceOffset, aLength, url ? url : "no url set"));
     925             : 
     926             :   // if the plugin has requested an AsFileOnly stream, then don't
     927             :   // call OnDataAvailable
     928           0 :   if (mStreamType != NP_ASFILEONLY) {
     929             :     // get the absolute offset of the request, if one exists.
     930           0 :     nsCOMPtr<nsIByteRangeRequest> brr = do_QueryInterface(request);
     931           0 :     if (brr) {
     932           0 :       if (!mDataForwardToRequest)
     933           0 :         return NS_ERROR_FAILURE;
     934             : 
     935           0 :       int64_t absoluteOffset64 = 0;
     936           0 :       brr->GetStartRange(&absoluteOffset64);
     937             : 
     938             :       // XXX handle 64-bit for real
     939           0 :       int32_t absoluteOffset = (int32_t)int64_t(absoluteOffset64);
     940             : 
     941             :       // we need to track how much data we have forwarded to the
     942             :       // plugin.
     943             : 
     944             :       // FIXME: http://bugzilla.mozilla.org/show_bug.cgi?id=240130
     945             :       //
     946             :       // Why couldn't this be tracked on the plugin info, and not in a
     947             :       // *hash table*?
     948           0 :       int32_t amtForwardToPlugin = mDataForwardToRequest->Get(absoluteOffset);
     949           0 :       mDataForwardToRequest->Put(absoluteOffset, (amtForwardToPlugin + aLength));
     950             : 
     951           0 :       SetStreamOffset(absoluteOffset + amtForwardToPlugin);
     952             :     }
     953             : 
     954           0 :     nsCOMPtr<nsIInputStream> stream = aIStream;
     955             : 
     956             :     // if we are caching the file ourselves to disk, we want to 'tee' off
     957             :     // the data as the plugin read from the stream.  We do this by the magic
     958             :     // of an input stream tee.
     959             : 
     960           0 :     if (mFileCacheOutputStream) {
     961           0 :       rv = NS_NewInputStreamTee(getter_AddRefs(stream), aIStream, mFileCacheOutputStream);
     962           0 :       if (NS_FAILED(rv))
     963           0 :         return rv;
     964             :     }
     965             : 
     966           0 :     rv =  mPStreamListener->OnDataAvailable(this,
     967             :                                             stream,
     968           0 :                                             aLength);
     969             : 
     970             :     // if a plugin returns an error, the peer must kill the stream
     971             :     //   else the stream and PluginStreamListener leak
     972           0 :     if (NS_FAILED(rv))
     973           0 :       request->Cancel(rv);
     974             :   }
     975             :   else
     976             :   {
     977             :     // if we don't read from the stream, OnStopRequest will never be called
     978           0 :     char* buffer = new char[aLength];
     979           0 :     uint32_t amountRead, amountWrote = 0;
     980           0 :     rv = aIStream->Read(buffer, aLength, &amountRead);
     981             : 
     982             :     // if we are caching this to disk ourselves, lets write the bytes out.
     983           0 :     if (mFileCacheOutputStream) {
     984           0 :       while (amountWrote < amountRead && NS_SUCCEEDED(rv)) {
     985           0 :         rv = mFileCacheOutputStream->Write(buffer, amountRead, &amountWrote);
     986             :       }
     987             :     }
     988           0 :     delete [] buffer;
     989             :   }
     990           0 :   return rv;
     991             : }
     992             : 
     993           0 : NS_IMETHODIMP nsPluginStreamListenerPeer::OnStopRequest(nsIRequest *request,
     994             :                                                         nsISupports* aContext,
     995             :                                                         nsresult aStatus)
     996             : {
     997           0 :   nsresult rv = NS_OK;
     998             : 
     999           0 :   nsCOMPtr<nsIMultiPartChannel> mp = do_QueryInterface(request);
    1000           0 :   if (!mp) {
    1001           0 :     bool found = mRequests.RemoveObject(request);
    1002           0 :     if (!found) {
    1003           0 :       NS_ERROR("Received OnStopRequest for untracked request.");
    1004             :     }
    1005             :   }
    1006             : 
    1007           0 :   PLUGIN_LOG(PLUGIN_LOG_NOISY,
    1008             :              ("nsPluginStreamListenerPeer::OnStopRequest this=%p aStatus=%" PRIu32 " request=%p\n",
    1009             :               this, static_cast<uint32_t>(aStatus), request));
    1010             : 
    1011             :   // for ByteRangeRequest we're just updating the mDataForwardToRequest hash and return.
    1012           0 :   nsCOMPtr<nsIByteRangeRequest> brr = do_QueryInterface(request);
    1013           0 :   if (brr) {
    1014           0 :     int64_t absoluteOffset64 = 0;
    1015           0 :     brr->GetStartRange(&absoluteOffset64);
    1016             :     // XXX support 64-bit offsets
    1017           0 :     int32_t absoluteOffset = (int32_t)int64_t(absoluteOffset64);
    1018             : 
    1019             :     // remove the request from our data forwarding count hash.
    1020           0 :     mDataForwardToRequest->Remove(absoluteOffset);
    1021             : 
    1022             : 
    1023           0 :     PLUGIN_LOG(PLUGIN_LOG_NOISY,
    1024             :                ("                          ::OnStopRequest for ByteRangeRequest Started=%d\n",
    1025             :                 absoluteOffset));
    1026             :   } else {
    1027             :     // if this is not byte range request and
    1028             :     // if we are writting the stream to disk ourselves,
    1029             :     // close & tear it down here
    1030           0 :     mFileCacheOutputStream = nullptr;
    1031             :   }
    1032             : 
    1033             :   // if we still have pending stuff to do, lets not close the plugin socket.
    1034           0 :   if (--mPendingRequests > 0)
    1035           0 :     return NS_OK;
    1036             : 
    1037             :   // we keep our connections around...
    1038           0 :   nsCOMPtr<nsISupportsPRUint32> container = do_QueryInterface(aContext);
    1039           0 :   if (container) {
    1040           0 :     uint32_t byteRangeRequest = 0;  // something other than the byte range request.
    1041           0 :     container->GetData(&byteRangeRequest);
    1042           0 :     if (byteRangeRequest == BYTERANGE_REQUEST_CONTEXT) {
    1043             :       // this is one of our range requests
    1044           0 :       return NS_OK;
    1045             :     }
    1046             :   }
    1047             : 
    1048           0 :   if (!mPStreamListener)
    1049           0 :     return NS_ERROR_FAILURE;
    1050             : 
    1051           0 :   nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
    1052           0 :   if (!channel)
    1053           0 :     return NS_ERROR_FAILURE;
    1054             :   // Set the content type to ensure we don't pass null to the plugin
    1055           0 :   nsAutoCString aContentType;
    1056           0 :   rv = channel->GetContentType(aContentType);
    1057           0 :   if (NS_FAILED(rv) && !mRequestFailed)
    1058           0 :     return rv;
    1059             : 
    1060           0 :   if (!aContentType.IsEmpty())
    1061           0 :     mContentType = aContentType;
    1062             : 
    1063             :   // set error status if stream failed so we notify the plugin
    1064           0 :   if (mRequestFailed)
    1065           0 :     aStatus = NS_ERROR_FAILURE;
    1066             : 
    1067           0 :   if (NS_FAILED(aStatus)) {
    1068             :     // on error status cleanup the stream
    1069             :     // and return w/o OnFileAvailable()
    1070           0 :     mPStreamListener->OnStopBinding(this, aStatus);
    1071           0 :     return NS_OK;
    1072             :   }
    1073             : 
    1074             :   // call OnFileAvailable if plugin requests stream type StreamType_AsFile or StreamType_AsFileOnly
    1075           0 :   if (mStreamType >= NP_ASFILE) {
    1076           0 :     nsCOMPtr<nsIFile> localFile;
    1077           0 :     if (mLocalCachedFileHolder)
    1078           0 :       localFile = mLocalCachedFileHolder->file();
    1079             :     else {
    1080             :       // see if it is a file channel.
    1081           0 :       nsCOMPtr<nsIFileChannel> fileChannel = do_QueryInterface(request);
    1082           0 :       if (fileChannel) {
    1083           0 :         fileChannel->GetFile(getter_AddRefs(localFile));
    1084             :       }
    1085             :     }
    1086             : 
    1087           0 :     if (localFile) {
    1088           0 :       OnFileAvailable(localFile);
    1089             :     }
    1090             :   }
    1091             : 
    1092           0 :   if (mStartBinding) {
    1093             :     // On start binding has been called
    1094           0 :     mPStreamListener->OnStopBinding(this, aStatus);
    1095             :   } else {
    1096             :     // OnStartBinding hasn't been called, so complete the action.
    1097           0 :     mPStreamListener->OnStartBinding(this);
    1098           0 :     mPStreamListener->OnStopBinding(this, aStatus);
    1099             :   }
    1100             : 
    1101           0 :   if (NS_SUCCEEDED(aStatus)) {
    1102           0 :     mStreamComplete = true;
    1103             :   }
    1104             : 
    1105           0 :   return NS_OK;
    1106             : }
    1107             : 
    1108           0 : nsresult nsPluginStreamListenerPeer::SetUpStreamListener(nsIRequest *request,
    1109             :                                                          nsIURI* aURL)
    1110             : {
    1111           0 :   nsresult rv = NS_OK;
    1112             : 
    1113             :   // If we don't yet have a stream listener, we need to get
    1114             :   // one from the plugin.
    1115             :   // NOTE: this should only happen when a stream was NOT created
    1116             :   // with GetURL or PostURL (i.e. it's the initial stream we
    1117             :   // send to the plugin as determined by the SRC or DATA attribute)
    1118           0 :   if (!mPStreamListener) {
    1119           0 :     if (!mPluginInstance) {
    1120           0 :       return NS_ERROR_FAILURE;
    1121             :     }
    1122             : 
    1123           0 :     RefPtr<nsNPAPIPluginStreamListener> streamListener;
    1124           0 :     rv = mPluginInstance->NewStreamListener(nullptr, nullptr,
    1125           0 :                                             getter_AddRefs(streamListener));
    1126           0 :     if (NS_FAILED(rv) || !streamListener) {
    1127           0 :       return NS_ERROR_FAILURE;
    1128             :     }
    1129             : 
    1130           0 :     mPStreamListener = static_cast<nsNPAPIPluginStreamListener*>(streamListener.get());
    1131             :   }
    1132             : 
    1133           0 :   mPStreamListener->SetStreamListenerPeer(this);
    1134             : 
    1135             :   // get httpChannel to retrieve some info we need for nsIPluginStreamInfo setup
    1136           0 :   nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
    1137           0 :   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel);
    1138             : 
    1139             :   /*
    1140             :    * Assumption
    1141             :    * By the time nsPluginStreamListenerPeer::OnDataAvailable() gets
    1142             :    * called, all the headers have been read.
    1143             :    */
    1144           0 :   if (httpChannel) {
    1145             :     // Reassemble the HTTP response status line and provide it to our
    1146             :     // listener.  Would be nice if we could get the raw status line,
    1147             :     // but nsIHttpChannel doesn't currently provide that.
    1148             :     // Status code: required; the status line isn't useful without it.
    1149             :     uint32_t statusNum;
    1150           0 :     if (NS_SUCCEEDED(httpChannel->GetResponseStatus(&statusNum)) &&
    1151           0 :         statusNum < 1000) {
    1152             :       // HTTP version: provide if available.  Defaults to empty string.
    1153           0 :       nsCString ver;
    1154             :       nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal =
    1155           0 :       do_QueryInterface(channel);
    1156           0 :       if (httpChannelInternal) {
    1157             :         uint32_t major, minor;
    1158           0 :         if (NS_SUCCEEDED(httpChannelInternal->GetResponseVersion(&major,
    1159             :                                                                  &minor))) {
    1160           0 :           ver = nsPrintfCString("/%" PRIu32 ".%" PRIu32, major, minor);
    1161             :         }
    1162             :       }
    1163             : 
    1164             :       // Status text: provide if available.  Defaults to "OK".
    1165           0 :       nsCString statusText;
    1166           0 :       if (NS_FAILED(httpChannel->GetResponseStatusText(statusText))) {
    1167           0 :         statusText = "OK";
    1168             :       }
    1169             : 
    1170             :       // Assemble everything and pass to listener.
    1171             :       nsPrintfCString status("HTTP%s %" PRIu32 " %s", ver.get(), statusNum,
    1172           0 :                              statusText.get());
    1173           0 :       static_cast<nsIHTTPHeaderListener*>(mPStreamListener)->StatusLine(status.get());
    1174             :     }
    1175             : 
    1176             :     // Also provide all HTTP response headers to our listener.
    1177           0 :     rv = httpChannel->VisitResponseHeaders(this);
    1178           0 :     MOZ_ASSERT(NS_SUCCEEDED(rv));
    1179             : 
    1180           0 :     mSeekable = false;
    1181             :     // first we look for a content-encoding header. If we find one, we tell the
    1182             :     // plugin that stream is not seekable, because the plugin always sees
    1183             :     // uncompressed data, so it can't make meaningful range requests on a
    1184             :     // compressed entity.  Also, we force the plugin to use
    1185             :     // nsPluginStreamType_AsFile stream type and we have to save decompressed
    1186             :     // file into local plugin cache, because necko cache contains original
    1187             :     // compressed file.
    1188           0 :     nsAutoCString contentEncoding;
    1189           0 :     if (NS_SUCCEEDED(httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("Content-Encoding"),
    1190             :                                                     contentEncoding))) {
    1191           0 :       mUseLocalCache = true;
    1192             :     } else {
    1193             :       // set seekability (seekable if the stream has a known length and if the
    1194             :       // http server accepts byte ranges).
    1195             :       uint32_t length;
    1196           0 :       GetLength(&length);
    1197           0 :       if (length) {
    1198           0 :         nsAutoCString range;
    1199           0 :         if (NS_SUCCEEDED(httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("accept-ranges"), range)) &&
    1200           0 :             range.Equals(NS_LITERAL_CSTRING("bytes"), nsCaseInsensitiveCStringComparator())) {
    1201           0 :           mSeekable = true;
    1202             :         }
    1203             :       }
    1204             :     }
    1205             : 
    1206             :     // we require a content len
    1207             :     // get Last-Modified header for plugin info
    1208           0 :     nsAutoCString lastModified;
    1209           0 :     if (NS_SUCCEEDED(httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("last-modified"), lastModified)) &&
    1210           0 :         !lastModified.IsEmpty()) {
    1211             :       PRTime time64;
    1212           0 :       PR_ParseTimeString(lastModified.get(), true, &time64);  //convert string time to integer time
    1213             : 
    1214             :       // Convert PRTime to unix-style time_t, i.e. seconds since the epoch
    1215           0 :       double fpTime = double(time64);
    1216           0 :       mModified = (uint32_t)(fpTime * 1e-6 + 0.5);
    1217             :     }
    1218             :   }
    1219             : 
    1220           0 :   MOZ_ASSERT(!mRequest);
    1221           0 :   mRequest = request;
    1222             : 
    1223           0 :   rv = mPStreamListener->OnStartBinding(this);
    1224             : 
    1225           0 :   mStartBinding = true;
    1226             : 
    1227           0 :   if (NS_FAILED(rv))
    1228           0 :     return rv;
    1229             : 
    1230           0 :   int32_t streamType = NP_NORMAL;
    1231           0 :   mPStreamListener->GetStreamType(&streamType);
    1232             : 
    1233           0 :   if (streamType != STREAM_TYPE_UNKNOWN) {
    1234           0 :     OnStreamTypeSet(streamType);
    1235             :   }
    1236             : 
    1237           0 :   return NS_OK;
    1238             : }
    1239             : 
    1240             : void
    1241           0 : nsPluginStreamListenerPeer::OnStreamTypeSet(const int32_t aStreamType)
    1242             : {
    1243           0 :   MOZ_ASSERT(aStreamType != STREAM_TYPE_UNKNOWN);
    1244           0 :   MOZ_ASSERT(mRequest);
    1245           0 :   mStreamType = aStreamType;
    1246           0 :   if (!mUseLocalCache && mStreamType >= NP_ASFILE) {
    1247             :     // check it out if this is not a file channel.
    1248           0 :     nsCOMPtr<nsIFileChannel> fileChannel = do_QueryInterface(mRequest);
    1249           0 :     if (!fileChannel) {
    1250           0 :       mUseLocalCache = true;
    1251             :     }
    1252             :   }
    1253             : 
    1254           0 :   if (mUseLocalCache) {
    1255           0 :     nsCOMPtr<nsIChannel> channel = do_QueryInterface(mRequest);
    1256           0 :     SetupPluginCacheFile(channel);
    1257             :   }
    1258           0 : }
    1259             : 
    1260             : nsresult
    1261           0 : nsPluginStreamListenerPeer::OnFileAvailable(nsIFile* aFile)
    1262             : {
    1263             :   nsresult rv;
    1264           0 :   if (!mPStreamListener)
    1265           0 :     return NS_ERROR_FAILURE;
    1266             : 
    1267           0 :   nsAutoCString path;
    1268           0 :   rv = aFile->GetNativePath(path);
    1269           0 :   if (NS_FAILED(rv)) return rv;
    1270             : 
    1271           0 :   if (path.IsEmpty()) {
    1272           0 :     NS_WARNING("empty path");
    1273           0 :     return NS_OK;
    1274             :   }
    1275             : 
    1276           0 :   rv = mPStreamListener->OnFileAvailable(this, path.get());
    1277           0 :   return rv;
    1278             : }
    1279             : 
    1280             : NS_IMETHODIMP
    1281           0 : nsPluginStreamListenerPeer::VisitHeader(const nsACString &header, const nsACString &value)
    1282             : {
    1283           0 :   return mPStreamListener->NewResponseHeader(PromiseFlatCString(header).get(),
    1284           0 :                                              PromiseFlatCString(value).get());
    1285             : }
    1286             : 
    1287             : nsresult
    1288           0 : nsPluginStreamListenerPeer::GetInterfaceGlobal(const nsIID& aIID, void** result)
    1289             : {
    1290           0 :   if (!mPluginInstance) {
    1291           0 :     return NS_ERROR_FAILURE;
    1292             :   }
    1293             : 
    1294           0 :   RefPtr<nsPluginInstanceOwner> owner = mPluginInstance->GetOwner();
    1295           0 :   if (!owner) {
    1296           0 :     return NS_ERROR_FAILURE;
    1297             :   }
    1298             : 
    1299           0 :   nsCOMPtr<nsIDocument> doc;
    1300           0 :   nsresult rv = owner->GetDocument(getter_AddRefs(doc));
    1301           0 :   if (NS_FAILED(rv) || !doc) {
    1302           0 :     return NS_ERROR_FAILURE;
    1303             :   }
    1304             : 
    1305           0 :   nsPIDOMWindowOuter *window = doc->GetWindow();
    1306           0 :   if (!window) {
    1307           0 :     return NS_ERROR_FAILURE;
    1308             :   }
    1309             : 
    1310           0 :   nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(window);
    1311           0 :   nsCOMPtr<nsIInterfaceRequestor> ir = do_QueryInterface(webNav);
    1312           0 :   if (!ir) {
    1313           0 :     return NS_ERROR_FAILURE;
    1314             :   }
    1315             : 
    1316           0 :   return ir->GetInterface(aIID, result);
    1317             : }
    1318             : 
    1319             : NS_IMETHODIMP
    1320           0 : nsPluginStreamListenerPeer::GetInterface(const nsIID& aIID, void** result)
    1321             : {
    1322             :   // Provide nsIChannelEventSink ourselves, otherwise let our document's
    1323             :   // script global object owner provide the interface.
    1324           0 :   if (aIID.Equals(NS_GET_IID(nsIChannelEventSink))) {
    1325           0 :     return QueryInterface(aIID, result);
    1326             :   }
    1327             : 
    1328           0 :   return GetInterfaceGlobal(aIID, result);
    1329             : }
    1330             : 
    1331             : /**
    1332             :  * Proxy class which forwards async redirect notifications back to the necko
    1333             :  * callback, keeping nsPluginStreamListenerPeer::mRequests in sync with
    1334             :  * which channel is active.
    1335             :  */
    1336             : class ChannelRedirectProxyCallback : public nsIAsyncVerifyRedirectCallback
    1337             : {
    1338             : public:
    1339           0 :   ChannelRedirectProxyCallback(nsPluginStreamListenerPeer* listener,
    1340             :                                nsIAsyncVerifyRedirectCallback* parent,
    1341             :                                nsIChannel* oldChannel,
    1342             :                                nsIChannel* newChannel)
    1343           0 :     : mWeakListener(do_GetWeakReference(static_cast<nsIStreamListener*>(listener)))
    1344             :     , mParent(parent)
    1345             :     , mOldChannel(oldChannel)
    1346           0 :     , mNewChannel(newChannel)
    1347             :   {
    1348           0 :   }
    1349             : 
    1350             :   ChannelRedirectProxyCallback() {}
    1351             : 
    1352             :   NS_DECL_ISUPPORTS
    1353             : 
    1354           0 :   NS_IMETHOD OnRedirectVerifyCallback(nsresult aResult) override
    1355             :   {
    1356           0 :     if (NS_SUCCEEDED(aResult)) {
    1357           0 :       nsCOMPtr<nsIStreamListener> listener = do_QueryReferent(mWeakListener);
    1358           0 :       if (listener)
    1359           0 :         static_cast<nsPluginStreamListenerPeer*>(listener.get())->ReplaceRequest(mOldChannel, mNewChannel);
    1360             :     }
    1361           0 :     return mParent->OnRedirectVerifyCallback(aResult);
    1362             :   }
    1363             : 
    1364             : private:
    1365           0 :   virtual ~ChannelRedirectProxyCallback() {}
    1366             : 
    1367             :   nsWeakPtr mWeakListener;
    1368             :   nsCOMPtr<nsIAsyncVerifyRedirectCallback> mParent;
    1369             :   nsCOMPtr<nsIChannel> mOldChannel;
    1370             :   nsCOMPtr<nsIChannel> mNewChannel;
    1371             : };
    1372             : 
    1373           0 : NS_IMPL_ISUPPORTS(ChannelRedirectProxyCallback, nsIAsyncVerifyRedirectCallback)
    1374             : 
    1375             : 
    1376             : NS_IMETHODIMP
    1377           0 : nsPluginStreamListenerPeer::AsyncOnChannelRedirect(nsIChannel *oldChannel, nsIChannel *newChannel,
    1378             :                                                    uint32_t flags, nsIAsyncVerifyRedirectCallback* callback)
    1379             : {
    1380             :   // Disallow redirects if we don't have a stream listener.
    1381           0 :   if (!mPStreamListener) {
    1382           0 :     return NS_ERROR_FAILURE;
    1383             :   }
    1384             : 
    1385             :   nsCOMPtr<nsIAsyncVerifyRedirectCallback> proxyCallback =
    1386           0 :     new ChannelRedirectProxyCallback(this, callback, oldChannel, newChannel);
    1387             : 
    1388             :   // Give NPAPI a chance to control redirects.
    1389           0 :   bool notificationHandled = mPStreamListener->HandleRedirectNotification(oldChannel, newChannel, proxyCallback);
    1390           0 :   if (notificationHandled) {
    1391           0 :     return NS_OK;
    1392             :   }
    1393             : 
    1394             :   // Don't allow cross-origin 307 POST redirects.
    1395           0 :   nsCOMPtr<nsIHttpChannel> oldHttpChannel(do_QueryInterface(oldChannel));
    1396           0 :   if (oldHttpChannel) {
    1397             :     uint32_t responseStatus;
    1398           0 :     nsresult rv = oldHttpChannel->GetResponseStatus(&responseStatus);
    1399           0 :     if (NS_FAILED(rv)) {
    1400           0 :       return rv;
    1401             :     }
    1402           0 :     if (responseStatus == 307) {
    1403           0 :       nsAutoCString method;
    1404           0 :       rv = oldHttpChannel->GetRequestMethod(method);
    1405           0 :       if (NS_FAILED(rv)) {
    1406           0 :         return rv;
    1407             :       }
    1408           0 :       if (method.EqualsLiteral("POST")) {
    1409           0 :         rv = nsContentUtils::CheckSameOrigin(oldChannel, newChannel);
    1410           0 :         if (NS_FAILED(rv)) {
    1411           0 :           return rv;
    1412             :         }
    1413             :       }
    1414             :     }
    1415             :   }
    1416             : 
    1417             :   // Fall back to channel event sink for window.
    1418           0 :   nsCOMPtr<nsIChannelEventSink> channelEventSink;
    1419           0 :   nsresult rv = GetInterfaceGlobal(NS_GET_IID(nsIChannelEventSink), getter_AddRefs(channelEventSink));
    1420           0 :   if (NS_FAILED(rv)) {
    1421           0 :     return rv;
    1422             :   }
    1423             : 
    1424           0 :   return channelEventSink->AsyncOnChannelRedirect(oldChannel, newChannel, flags, proxyCallback);
    1425             : }

Generated by: LCOV version 1.13