netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     2  *
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "nsWyciwyg.h"
     8 #include "nsWyciwygChannel.h"
     9 #include "nsILoadGroup.h"
    10 #include "nsNetUtil.h"
    11 #include "LoadContextInfo.h"
    12 #include "nsICacheService.h" // only to initialize
    13 #include "nsICacheStorageService.h"
    14 #include "nsICacheStorage.h"
    15 #include "nsICacheEntry.h"
    16 #include "CacheObserver.h"
    17 #include "nsCharsetSource.h"
    18 #include "nsProxyRelease.h"
    19 #include "nsThreadUtils.h"
    20 #include "nsIEventTarget.h"
    21 #include "nsIInputStream.h"
    22 #include "nsIInputStreamPump.h"
    23 #include "nsIOutputStream.h"
    24 #include "nsIProgressEventSink.h"
    25 #include "nsIURI.h"
    26 #include "mozilla/DebugOnly.h"
    27 #include "mozilla/unused.h"
    29 typedef mozilla::net::LoadContextInfo LoadContextInfo;
    31 // Must release mChannel on the main thread
    32 class nsWyciwygAsyncEvent : public nsRunnable {
    33 public:
    34   nsWyciwygAsyncEvent(nsWyciwygChannel *aChannel) : mChannel(aChannel) {}
    36   ~nsWyciwygAsyncEvent()
    37   {
    38     nsCOMPtr<nsIThread> thread = do_GetMainThread();
    39     NS_WARN_IF_FALSE(thread, "Couldn't get the main thread!");
    40     if (thread) {
    41       nsIWyciwygChannel *chan = static_cast<nsIWyciwygChannel *>(mChannel);
    42       mozilla::unused << mChannel.forget();
    43       NS_ProxyRelease(thread, chan);
    44     }
    45   }
    46 protected:
    47   nsRefPtr<nsWyciwygChannel> mChannel;
    48 };
    50 class nsWyciwygSetCharsetandSourceEvent : public nsWyciwygAsyncEvent {
    51 public:
    52   nsWyciwygSetCharsetandSourceEvent(nsWyciwygChannel *aChannel)
    53     : nsWyciwygAsyncEvent(aChannel) {}
    55   NS_IMETHOD Run()
    56   {
    57     mChannel->SetCharsetAndSourceInternal();
    58     return NS_OK;
    59   }
    60 };
    62 class nsWyciwygWriteEvent : public nsWyciwygAsyncEvent {
    63 public:
    64   nsWyciwygWriteEvent(nsWyciwygChannel *aChannel, const nsAString &aData)
    65     : nsWyciwygAsyncEvent(aChannel), mData(aData) {}
    67   NS_IMETHOD Run()
    68   {
    69     mChannel->WriteToCacheEntryInternal(mData);
    70     return NS_OK;
    71   }
    72 private:
    73   nsString mData;
    74 };
    76 class nsWyciwygCloseEvent : public nsWyciwygAsyncEvent {
    77 public:
    78   nsWyciwygCloseEvent(nsWyciwygChannel *aChannel, nsresult aReason)
    79     : nsWyciwygAsyncEvent(aChannel), mReason(aReason) {}
    81   NS_IMETHOD Run()
    82   {
    83     mChannel->CloseCacheEntryInternal(mReason);
    84     return NS_OK;
    85   }
    86 private:
    87   nsresult mReason;
    88 };
    91 // nsWyciwygChannel methods 
    92 nsWyciwygChannel::nsWyciwygChannel()
    93   : mMode(NONE),
    94     mStatus(NS_OK),
    95     mIsPending(false),
    96     mCharsetAndSourceSet(false),
    97     mNeedToWriteCharset(false),
    98     mCharsetSource(kCharsetUninitialized),
    99     mContentLength(-1),
   100     mLoadFlags(LOAD_NORMAL),
   101     mAppId(NECKO_NO_APP_ID),
   102     mInBrowser(false)
   103 {
   104 }
   106 nsWyciwygChannel::~nsWyciwygChannel() 
   107 {
   108 }
   110 NS_IMPL_ISUPPORTS(nsWyciwygChannel,
   111                   nsIChannel,
   112                   nsIRequest,
   113                   nsIStreamListener,
   114                   nsIRequestObserver,
   115                   nsICacheEntryOpenCallback,
   116                   nsIWyciwygChannel,
   117                   nsIPrivateBrowsingChannel)
   119 nsresult
   120 nsWyciwygChannel::Init(nsIURI* uri)
   121 {
   122   NS_ENSURE_ARG_POINTER(uri);
   124   nsresult rv;
   126   if (!mozilla::net::CacheObserver::UseNewCache()) {
   127     // Since nsWyciwygChannel can use the new cache API off the main thread
   128     // and that API normally does this initiation, we need to take care
   129     // of initiating the old cache service here manually.  Will be removed
   130     // with bug 913828.
   131     MOZ_ASSERT(NS_IsMainThread());
   132     nsCOMPtr<nsICacheService> service =
   133       do_GetService(NS_CACHESERVICE_CONTRACTID, &rv);
   134   }
   136   mURI = uri;
   137   mOriginalURI = uri;
   139   nsCOMPtr<nsICacheStorageService> serv =
   140     do_GetService("@mozilla.org/netwerk/cache-storage-service;1", &rv);
   141   NS_ENSURE_SUCCESS(rv, rv);
   143   rv = serv->GetIoTarget(getter_AddRefs(mCacheIOTarget));
   144   NS_ENSURE_SUCCESS(rv, rv);
   146   return NS_OK;
   147 }
   149 ///////////////////////////////////////////////////////////////////////////////
   150 // nsIRequest methods:
   151 ///////////////////////////////////////////////////////////////////////////////
   153 NS_IMETHODIMP
   154 nsWyciwygChannel::GetName(nsACString &aName)
   155 {
   156   return mURI->GetSpec(aName);
   157 }
   159 NS_IMETHODIMP
   160 nsWyciwygChannel::IsPending(bool *aIsPending)
   161 {
   162   *aIsPending = mIsPending;
   163   return NS_OK;
   164 }
   166 NS_IMETHODIMP
   167 nsWyciwygChannel::GetStatus(nsresult *aStatus)
   168 {
   169   if (NS_SUCCEEDED(mStatus) && mPump)
   170     mPump->GetStatus(aStatus);
   171   else
   172     *aStatus = mStatus;
   173   return NS_OK;
   174 }
   176 NS_IMETHODIMP
   177 nsWyciwygChannel::Cancel(nsresult status)
   178 {
   179   mStatus = status;
   180   if (mPump)
   181     mPump->Cancel(status);
   182   // else we're waiting for OnCacheEntryAvailable
   183   return NS_OK;
   184 }
   186 NS_IMETHODIMP
   187 nsWyciwygChannel::Suspend()
   188 {
   189   if (mPump)
   190     mPump->Suspend();
   191   // XXX else, we'll ignore this ... and that's probably bad!
   192   return NS_OK;
   193 }
   195 NS_IMETHODIMP
   196 nsWyciwygChannel::Resume()
   197 {
   198   if (mPump)
   199     mPump->Resume();
   200   // XXX else, we'll ignore this ... and that's probably bad!
   201   return NS_OK;
   202 }
   204 NS_IMETHODIMP
   205 nsWyciwygChannel::GetLoadGroup(nsILoadGroup* *aLoadGroup)
   206 {
   207   *aLoadGroup = mLoadGroup;
   208   NS_IF_ADDREF(*aLoadGroup);
   209   return NS_OK;
   210 }
   212 NS_IMETHODIMP
   213 nsWyciwygChannel::SetLoadGroup(nsILoadGroup* aLoadGroup)
   214 {
   215   if (!CanSetLoadGroup(aLoadGroup)) {
   216     return NS_ERROR_FAILURE;
   217   }
   219   mLoadGroup = aLoadGroup;
   220   NS_QueryNotificationCallbacks(mCallbacks,
   221                                 mLoadGroup,
   222                                 NS_GET_IID(nsIProgressEventSink),
   223                                 getter_AddRefs(mProgressSink));
   224   mPrivateBrowsing = NS_UsePrivateBrowsing(this);
   225   NS_GetAppInfo(this, &mAppId, &mInBrowser);
   226   return NS_OK;
   227 }
   229 NS_IMETHODIMP
   230 nsWyciwygChannel::SetLoadFlags(uint32_t aLoadFlags)
   231 {
   232   mLoadFlags = aLoadFlags;
   233   return NS_OK;
   234 }
   236 NS_IMETHODIMP
   237 nsWyciwygChannel::GetLoadFlags(uint32_t * aLoadFlags)
   238 {
   239   *aLoadFlags = mLoadFlags;
   240   return NS_OK;
   241 }
   243 ////////////////////////////////////////////////////////////////////////////////
   244 // nsIChannel methods:
   245 ///////////////////////////////////////////////////////////////////////////////
   247 NS_IMETHODIMP
   248 nsWyciwygChannel::GetOriginalURI(nsIURI* *aURI)
   249 {
   250   *aURI = mOriginalURI;
   251   NS_ADDREF(*aURI);
   252   return NS_OK;
   253 }
   255 NS_IMETHODIMP
   256 nsWyciwygChannel::SetOriginalURI(nsIURI* aURI)
   257 {
   258   NS_ENSURE_ARG_POINTER(aURI);
   259   mOriginalURI = aURI;
   260   return NS_OK;
   261 }
   263 NS_IMETHODIMP
   264 nsWyciwygChannel::GetURI(nsIURI* *aURI)
   265 {
   266   *aURI = mURI;
   267   NS_IF_ADDREF(*aURI);
   268   return NS_OK;
   269 }
   271 NS_IMETHODIMP
   272 nsWyciwygChannel::GetOwner(nsISupports **aOwner)
   273 {
   274   NS_PRECONDITION(mOwner, "Must have a principal!");
   275   NS_ENSURE_STATE(mOwner);
   277   NS_ADDREF(*aOwner = mOwner);
   278   return NS_OK;
   279 }
   281 NS_IMETHODIMP
   282 nsWyciwygChannel::SetOwner(nsISupports* aOwner)
   283 {
   284   mOwner = aOwner;
   285   return NS_OK;
   286 }
   288 NS_IMETHODIMP
   289 nsWyciwygChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aCallbacks)
   290 {
   291   *aCallbacks = mCallbacks.get();
   292   NS_IF_ADDREF(*aCallbacks);
   293   return NS_OK;
   294 }
   296 NS_IMETHODIMP
   297 nsWyciwygChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCallbacks)
   298 {
   299   if (!CanSetCallbacks(aNotificationCallbacks)) {
   300     return NS_ERROR_FAILURE;
   301   }
   303   mCallbacks = aNotificationCallbacks;
   304   NS_QueryNotificationCallbacks(mCallbacks,
   305                                 mLoadGroup,
   306                                 NS_GET_IID(nsIProgressEventSink),
   307                                 getter_AddRefs(mProgressSink));
   309   mPrivateBrowsing = NS_UsePrivateBrowsing(this);
   310   NS_GetAppInfo(this, &mAppId, &mInBrowser);
   312   return NS_OK;
   313 }
   315 NS_IMETHODIMP 
   316 nsWyciwygChannel::GetSecurityInfo(nsISupports * *aSecurityInfo)
   317 {
   318   NS_IF_ADDREF(*aSecurityInfo = mSecurityInfo);
   320   return NS_OK;
   321 }
   323 NS_IMETHODIMP
   324 nsWyciwygChannel::GetContentType(nsACString &aContentType)
   325 {
   326   aContentType.AssignLiteral(WYCIWYG_TYPE);
   327   return NS_OK;
   328 }
   330 NS_IMETHODIMP
   331 nsWyciwygChannel::SetContentType(const nsACString &aContentType)
   332 {
   333   return NS_ERROR_NOT_IMPLEMENTED;
   334 }
   336 NS_IMETHODIMP
   337 nsWyciwygChannel::GetContentCharset(nsACString &aContentCharset)
   338 {
   339   aContentCharset.Assign("UTF-16");
   340   return NS_OK;
   341 }
   343 NS_IMETHODIMP
   344 nsWyciwygChannel::SetContentCharset(const nsACString &aContentCharset)
   345 {
   346   return NS_ERROR_NOT_IMPLEMENTED;
   347 }
   349 NS_IMETHODIMP
   350 nsWyciwygChannel::GetContentDisposition(uint32_t *aContentDisposition)
   351 {
   352   return NS_ERROR_NOT_AVAILABLE;
   353 }
   355 NS_IMETHODIMP
   356 nsWyciwygChannel::SetContentDisposition(uint32_t aContentDisposition)
   357 {
   358   return NS_ERROR_NOT_AVAILABLE;
   359 }
   361 NS_IMETHODIMP
   362 nsWyciwygChannel::GetContentDispositionFilename(nsAString &aContentDispositionFilename)
   363 {
   364   return NS_ERROR_NOT_AVAILABLE;
   365 }
   367 NS_IMETHODIMP
   368 nsWyciwygChannel::SetContentDispositionFilename(const nsAString &aContentDispositionFilename)
   369 {
   370   return NS_ERROR_NOT_AVAILABLE;
   371 }
   373 NS_IMETHODIMP
   374 nsWyciwygChannel::GetContentDispositionHeader(nsACString &aContentDispositionHeader)
   375 {
   376   return NS_ERROR_NOT_AVAILABLE;
   377 }
   379 NS_IMETHODIMP
   380 nsWyciwygChannel::GetContentLength(int64_t *aContentLength)
   381 {
   382   *aContentLength = mContentLength;
   383   return NS_OK;
   384 }
   386 NS_IMETHODIMP
   387 nsWyciwygChannel::SetContentLength(int64_t aContentLength)
   388 {
   389   mContentLength = aContentLength;
   391   return NS_OK;
   392 }
   394 NS_IMETHODIMP
   395 nsWyciwygChannel::Open(nsIInputStream ** aReturn)
   396 {
   397   return NS_ERROR_NOT_IMPLEMENTED;
   398 }
   400 NS_IMETHODIMP
   401 nsWyciwygChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctx)
   402 {
   403   LOG(("nsWyciwygChannel::AsyncOpen [this=%p]\n", this));
   404   MOZ_ASSERT(mMode == NONE, "nsWyciwygChannel already open");
   406   NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
   407   NS_ENSURE_TRUE(mMode == NONE, NS_ERROR_IN_PROGRESS);
   408   NS_ENSURE_ARG_POINTER(listener);
   410   mMode = READING;
   412   // open a cache entry for this channel...
   413   // mIsPending set to true since OnCacheEntryAvailable may be called
   414   // synchronously and fails when mIsPending found false.
   415   mIsPending = true;
   416   nsresult rv = OpenCacheEntry(mURI, nsICacheStorage::OPEN_READONLY |
   417                                      nsICacheStorage::CHECK_MULTITHREADED);
   418   if (NS_FAILED(rv)) {
   419     LOG(("nsWyciwygChannel::OpenCacheEntry failed [rv=%x]\n", rv));
   420     mIsPending = false;
   421     return rv;
   422   }
   424   // There is no code path that would invoke the listener sooner than
   425   // we get to this line in case OnCacheEntryAvailable is invoked
   426   // synchronously.
   427   mListener = listener;
   428   mListenerContext = ctx;
   430   if (mLoadGroup)
   431     mLoadGroup->AddRequest(this, nullptr);
   433   return NS_OK;
   434 }
   436 //////////////////////////////////////////////////////////////////////////////
   437 // nsIWyciwygChannel
   438 //////////////////////////////////////////////////////////////////////////////
   440 nsresult
   441 nsWyciwygChannel::EnsureWriteCacheEntry()
   442 {
   443   MOZ_ASSERT(mMode == WRITING, "nsWyciwygChannel not open for writing");
   445   if (!mCacheEntry) {
   446     // OPEN_TRUNCATE will give us the entry instantly
   447     nsresult rv = OpenCacheEntry(mURI, nsICacheStorage::OPEN_TRUNCATE);
   448     if (NS_FAILED(rv) || !mCacheEntry) {
   449       LOG(("  could not synchronously open cache entry for write!"));
   450       return NS_ERROR_FAILURE;
   451     }
   452   }
   454   return NS_OK;
   455 }
   457 NS_IMETHODIMP
   458 nsWyciwygChannel::WriteToCacheEntry(const nsAString &aData)
   459 {
   460   if (mMode == READING) {
   461     LOG(("nsWyciwygChannel::WriteToCacheEntry already open for reading"));
   462     MOZ_ASSERT(false);
   463     return NS_ERROR_UNEXPECTED;
   464   }
   466   mMode = WRITING;
   468   if (mozilla::net::CacheObserver::UseNewCache()) {
   469     nsresult rv = EnsureWriteCacheEntry();
   470     if (NS_FAILED(rv)) return rv;
   471   }
   473   return mCacheIOTarget->Dispatch(new nsWyciwygWriteEvent(this, aData),
   474                                   NS_DISPATCH_NORMAL);
   475 }
   477 nsresult
   478 nsWyciwygChannel::WriteToCacheEntryInternal(const nsAString &aData)
   479 {
   480   LOG(("nsWyciwygChannel::WriteToCacheEntryInternal [this=%p]", this));
   481   NS_ASSERTION(IsOnCacheIOThread(), "wrong thread");
   483   nsresult rv;
   485   // With the new cache entry this will just pass as a no-op since we
   486   // are opening the entry in WriteToCacheEntry.
   487   rv = EnsureWriteCacheEntry();
   488   if (NS_WARN_IF(NS_FAILED(rv))) {
   489     return rv;
   490   }
   492   if (mLoadFlags & INHIBIT_PERSISTENT_CACHING) {
   493     rv = mCacheEntry->SetMetaDataElement("inhibit-persistent-caching", "1");
   494     if (NS_FAILED(rv)) return rv;
   495   }
   497   if (mSecurityInfo) {
   498     mCacheEntry->SetSecurityInfo(mSecurityInfo);
   499   }
   501   if (mNeedToWriteCharset) {
   502     WriteCharsetAndSourceToCache(mCharsetSource, mCharset);
   503     mNeedToWriteCharset = false;
   504   }
   506   uint32_t out;
   507   if (!mCacheOutputStream) {
   508     // Get the outputstream from the cache entry.
   509     rv = mCacheEntry->OpenOutputStream(0, getter_AddRefs(mCacheOutputStream));    
   510     if (NS_FAILED(rv)) return rv;
   512     // Write out a Byte Order Mark, so that we'll know if the data is
   513     // BE or LE when we go to read it.
   514     char16_t bom = 0xFEFF;
   515     rv = mCacheOutputStream->Write((char *)&bom, sizeof(bom), &out);
   516     if (NS_FAILED(rv)) return rv;
   517   }
   519   return mCacheOutputStream->Write((const char *)PromiseFlatString(aData).get(),
   520                                    aData.Length() * sizeof(char16_t), &out);
   521 }
   524 NS_IMETHODIMP
   525 nsWyciwygChannel::CloseCacheEntry(nsresult reason)
   526 {
   527   return mCacheIOTarget->Dispatch(new nsWyciwygCloseEvent(this, reason),
   528                                   NS_DISPATCH_NORMAL);
   529 }
   531 nsresult
   532 nsWyciwygChannel::CloseCacheEntryInternal(nsresult reason)
   533 {
   534   NS_ASSERTION(IsOnCacheIOThread(), "wrong thread");
   536   if (mCacheEntry) {
   537     LOG(("nsWyciwygChannel::CloseCacheEntryInternal [this=%p ]", this));
   538     mCacheOutputStream = 0;
   539     mCacheInputStream = 0;
   541     if (NS_FAILED(reason))
   542       mCacheEntry->AsyncDoom(nullptr); // here we were calling Doom() ...
   544     mCacheEntry = 0;
   545   }
   546   return NS_OK;
   547 }
   549 NS_IMETHODIMP
   550 nsWyciwygChannel::SetSecurityInfo(nsISupports *aSecurityInfo)
   551 {
   552   mSecurityInfo = aSecurityInfo;
   554   return NS_OK;
   555 }
   557 NS_IMETHODIMP
   558 nsWyciwygChannel::SetCharsetAndSource(int32_t aSource,
   559                                       const nsACString& aCharset)
   560 {
   561   NS_ENSURE_ARG(!aCharset.IsEmpty());
   563   mCharsetAndSourceSet = true;
   564   mCharset = aCharset;
   565   mCharsetSource = aSource;
   567   return mCacheIOTarget->Dispatch(new nsWyciwygSetCharsetandSourceEvent(this),
   568                                   NS_DISPATCH_NORMAL);
   569 }
   571 void
   572 nsWyciwygChannel::SetCharsetAndSourceInternal()
   573 {
   574   NS_ASSERTION(IsOnCacheIOThread(), "wrong thread");
   576   if (mCacheEntry) {
   577     WriteCharsetAndSourceToCache(mCharsetSource, mCharset);
   578   } else {
   579     mNeedToWriteCharset = true;
   580   }
   581 }
   583 NS_IMETHODIMP
   584 nsWyciwygChannel::GetCharsetAndSource(int32_t* aSource, nsACString& aCharset)
   585 {
   586   if (mCharsetAndSourceSet) {
   587     *aSource = mCharsetSource;
   588     aCharset = mCharset;
   589     return NS_OK;
   590   }
   592   if (!mCacheEntry) {
   593     return NS_ERROR_NOT_AVAILABLE;
   594   }
   596   nsXPIDLCString data;
   597   mCacheEntry->GetMetaDataElement("charset", getter_Copies(data));
   599   if (data.IsEmpty()) {
   600     return NS_ERROR_NOT_AVAILABLE;
   601   }
   603   nsXPIDLCString sourceStr;
   604   mCacheEntry->GetMetaDataElement("charset-source", getter_Copies(sourceStr));
   606   int32_t source;
   607   nsresult err;
   608   source = sourceStr.ToInteger(&err);
   609   if (NS_FAILED(err) || source == 0) {
   610     return NS_ERROR_NOT_AVAILABLE;
   611   }
   613   *aSource = source;
   614   aCharset = data;
   615   return NS_OK;
   616 }
   618 //////////////////////////////////////////////////////////////////////////////
   619 // nsICacheEntryOpenCallback
   620 //////////////////////////////////////////////////////////////////////////////
   622 NS_IMETHODIMP
   623 nsWyciwygChannel::OnCacheEntryCheck(nsICacheEntry* entry, nsIApplicationCache* appCache,
   624                                     uint32_t* aResult)
   625 {
   626   *aResult = ENTRY_WANTED;
   627   return NS_OK;
   628 }
   630 NS_IMETHODIMP
   631 nsWyciwygChannel::OnCacheEntryAvailable(nsICacheEntry *aCacheEntry,
   632                                         bool aNew,
   633                                         nsIApplicationCache* aAppCache,
   634                                         nsresult aStatus)
   635 {
   636   LOG(("nsWyciwygChannel::OnCacheEntryAvailable [this=%p entry=%p "
   637        "new=%d status=%x]\n", this, aCacheEntry, aNew, aStatus));
   639   // if the channel's already fired onStopRequest, 
   640   // then we should ignore this event.
   641   if (!mIsPending && !aNew)
   642     return NS_OK;
   644   // otherwise, we have to handle this event.
   645   if (NS_SUCCEEDED(aStatus))
   646     mCacheEntry = aCacheEntry;
   647   else if (NS_SUCCEEDED(mStatus))
   648     mStatus = aStatus;
   650   nsresult rv = NS_OK;
   651   if (NS_FAILED(mStatus)) {
   652     LOG(("channel was canceled [this=%p status=%x]\n", this, mStatus));
   653     rv = mStatus;
   654   }
   655   else if (!aNew) { // advance to the next state...
   656     rv = ReadFromCache();
   657   }
   659   // a failure from Connect means that we have to abort the channel.
   660   if (NS_FAILED(rv)) {
   661     CloseCacheEntry(rv);
   663     if (!aNew) {
   664       // Since OnCacheEntryAvailable can be called directly from AsyncOpen
   665       // we must dispatch.
   666       NS_DispatchToCurrentThread(NS_NewRunnableMethod(
   667         this, &nsWyciwygChannel::NotifyListener));
   668     }
   669   }
   671   return NS_OK;
   672 }
   674 //-----------------------------------------------------------------------------
   675 // nsWyciwygChannel::nsIStreamListener
   676 //-----------------------------------------------------------------------------
   678 NS_IMETHODIMP
   679 nsWyciwygChannel::OnDataAvailable(nsIRequest *request, nsISupports *ctx,
   680                                   nsIInputStream *input,
   681                                   uint64_t offset, uint32_t count)
   682 {
   683   LOG(("nsWyciwygChannel::OnDataAvailable [this=%p request=%x offset=%llu count=%u]\n",
   684       this, request, offset, count));
   686   nsresult rv;
   688   rv = mListener->OnDataAvailable(this, mListenerContext, input, offset, count);
   690   // XXX handle 64-bit stuff for real
   691   if (mProgressSink && NS_SUCCEEDED(rv) && !(mLoadFlags & LOAD_BACKGROUND))
   692     mProgressSink->OnProgress(this, nullptr, offset + count,
   693                               uint64_t(mContentLength));
   695   return rv; // let the pump cancel on failure
   696 }
   698 //////////////////////////////////////////////////////////////////////////////
   699 // nsIRequestObserver
   700 //////////////////////////////////////////////////////////////////////////////
   702 NS_IMETHODIMP
   703 nsWyciwygChannel::OnStartRequest(nsIRequest *request, nsISupports *ctx)
   704 {
   705   LOG(("nsWyciwygChannel::OnStartRequest [this=%p request=%x\n",
   706       this, request));
   708   return mListener->OnStartRequest(this, mListenerContext);
   709 }
   712 NS_IMETHODIMP
   713 nsWyciwygChannel::OnStopRequest(nsIRequest *request, nsISupports *ctx, nsresult status)
   714 {
   715   LOG(("nsWyciwygChannel::OnStopRequest [this=%p request=%x status=%d\n",
   716       this, request, status));
   718   if (NS_SUCCEEDED(mStatus))
   719     mStatus = status;
   721   mListener->OnStopRequest(this, mListenerContext, mStatus);
   722   mListener = 0;
   723   mListenerContext = 0;
   725   if (mLoadGroup)
   726     mLoadGroup->RemoveRequest(this, nullptr, mStatus);
   728   CloseCacheEntry(mStatus);
   729   mPump = 0;
   730   mIsPending = false;
   732   // Drop notification callbacks to prevent cycles.
   733   mCallbacks = 0;
   734   mProgressSink = 0;
   736   return NS_OK;
   737 }
   739 //////////////////////////////////////////////////////////////////////////////
   740 // Helper functions
   741 //////////////////////////////////////////////////////////////////////////////
   743 nsresult
   744 nsWyciwygChannel::OpenCacheEntry(nsIURI *aURI,
   745                                  uint32_t aOpenFlags)
   746 {
   747   nsresult rv;
   749   nsCOMPtr<nsICacheStorageService> cacheService =
   750     do_GetService("@mozilla.org/netwerk/cache-storage-service;1", &rv);
   751   NS_ENSURE_SUCCESS(rv, rv);
   753   bool anonymous = mLoadFlags & LOAD_ANONYMOUS;
   754   nsRefPtr<LoadContextInfo> loadInfo = mozilla::net::GetLoadContextInfo(
   755     mPrivateBrowsing, mAppId, mInBrowser, anonymous);
   757   nsCOMPtr<nsICacheStorage> cacheStorage;
   758   if (mLoadFlags & INHIBIT_PERSISTENT_CACHING)
   759     rv = cacheService->MemoryCacheStorage(loadInfo, getter_AddRefs(cacheStorage));
   760   else
   761     rv = cacheService->DiskCacheStorage(loadInfo, false, getter_AddRefs(cacheStorage));
   762   NS_ENSURE_SUCCESS(rv, rv);
   764   rv = cacheStorage->AsyncOpenURI(aURI, EmptyCString(), aOpenFlags, this);
   765   NS_ENSURE_SUCCESS(rv, rv);
   767   return NS_OK;
   768 }
   770 nsresult
   771 nsWyciwygChannel::ReadFromCache()
   772 {
   773   LOG(("nsWyciwygChannel::ReadFromCache [this=%p] ", this));
   775   NS_ENSURE_TRUE(mCacheEntry, NS_ERROR_FAILURE);
   776   nsresult rv;
   778   // Get the stored security info
   779   mCacheEntry->GetSecurityInfo(getter_AddRefs(mSecurityInfo));
   781   nsAutoCString tmpStr;
   782   rv = mCacheEntry->GetMetaDataElement("inhibit-persistent-caching",
   783                                        getter_Copies(tmpStr));
   784   if (NS_SUCCEEDED(rv) && tmpStr == NS_LITERAL_CSTRING("1"))
   785     mLoadFlags |= INHIBIT_PERSISTENT_CACHING;
   787   // Get a transport to the cached data...
   788   rv = mCacheEntry->OpenInputStream(0, getter_AddRefs(mCacheInputStream));
   789   if (NS_FAILED(rv))
   790     return rv;
   791   NS_ENSURE_TRUE(mCacheInputStream, NS_ERROR_UNEXPECTED);
   793   rv = NS_NewInputStreamPump(getter_AddRefs(mPump), mCacheInputStream);
   794   if (NS_FAILED(rv)) return rv;
   796   // Pump the cache data downstream
   797   return mPump->AsyncRead(this, nullptr);
   798 }
   800 void
   801 nsWyciwygChannel::WriteCharsetAndSourceToCache(int32_t aSource,
   802                                                const nsCString& aCharset)
   803 {
   804   NS_ASSERTION(IsOnCacheIOThread(), "wrong thread");
   805   NS_PRECONDITION(mCacheEntry, "Better have cache entry!");
   807   mCacheEntry->SetMetaDataElement("charset", aCharset.get());
   809   nsAutoCString source;
   810   source.AppendInt(aSource);
   811   mCacheEntry->SetMetaDataElement("charset-source", source.get());
   812 }
   814 void
   815 nsWyciwygChannel::NotifyListener()
   816 {    
   817   if (mListener) {
   818     mListener->OnStartRequest(this, mListenerContext);
   819     mListener->OnStopRequest(this, mListenerContext, mStatus);
   820     mListener = 0;
   821     mListenerContext = 0;
   822   }
   824   mIsPending = false;
   826   // Remove ourselves from the load group.
   827   if (mLoadGroup) {
   828     mLoadGroup->RemoveRequest(this, nullptr, mStatus);
   829   }
   830 }
   832 bool
   833 nsWyciwygChannel::IsOnCacheIOThread()
   834 {
   835   bool correctThread;
   836   mCacheIOTarget->IsOnCurrentThread(&correctThread);
   837   return correctThread;
   838 }
   840 // vim: ts=2 sw=2

mercurial