netwerk/base/src/nsBaseChannel.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     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/. */
     6 #include "nsBaseChannel.h"
     7 #include "nsURLHelper.h"
     8 #include "nsNetUtil.h"
     9 #include "nsMimeTypes.h"
    10 #include "nsIHttpEventSink.h"
    11 #include "nsIHttpChannel.h"
    12 #include "nsIChannelEventSink.h"
    13 #include "nsIStreamConverterService.h"
    14 #include "nsChannelClassifier.h"
    15 #include "nsAsyncRedirectVerifyHelper.h"
    17 static PLDHashOperator
    18 CopyProperties(const nsAString &key, nsIVariant *data, void *closure)
    19 {
    20   nsIWritablePropertyBag *bag =
    21       static_cast<nsIWritablePropertyBag *>(closure);
    23   bag->SetProperty(key, data);
    24   return PL_DHASH_NEXT;
    25 }
    27 // This class is used to suspend a request across a function scope.
    28 class ScopedRequestSuspender {
    29 public:
    30   ScopedRequestSuspender(nsIRequest *request)
    31     : mRequest(request) {
    32     if (mRequest && NS_FAILED(mRequest->Suspend())) {
    33       NS_WARNING("Couldn't suspend pump");
    34       mRequest = nullptr;
    35     }
    36   }
    37   ~ScopedRequestSuspender() {
    38     if (mRequest)
    39       mRequest->Resume();
    40   }
    41 private:
    42   nsIRequest *mRequest;
    43 };
    45 // Used to suspend data events from mPump within a function scope.  This is
    46 // usually needed when a function makes callbacks that could process events.
    47 #define SUSPEND_PUMP_FOR_SCOPE() \
    48   ScopedRequestSuspender pump_suspender__(mPump)
    50 //-----------------------------------------------------------------------------
    51 // nsBaseChannel
    53 nsBaseChannel::nsBaseChannel()
    54   : mLoadFlags(LOAD_NORMAL)
    55   , mQueriedProgressSink(true)
    56   , mSynthProgressEvents(false)
    57   , mWasOpened(false)
    58   , mWaitingOnAsyncRedirect(false)
    59   , mStatus(NS_OK)
    60   , mContentDispositionHint(UINT32_MAX)
    61   , mContentLength(-1)
    62 {
    63   mContentType.AssignLiteral(UNKNOWN_CONTENT_TYPE);
    64 }
    66 nsresult
    67 nsBaseChannel::Redirect(nsIChannel *newChannel, uint32_t redirectFlags,
    68                         bool openNewChannel)
    69 {
    70   SUSPEND_PUMP_FOR_SCOPE();
    72   // Transfer properties
    74   newChannel->SetLoadGroup(mLoadGroup);
    75   newChannel->SetNotificationCallbacks(mCallbacks);
    76   newChannel->SetLoadFlags(mLoadFlags | LOAD_REPLACE);
    78   // Try to preserve the privacy bit if it has been overridden
    79   if (mPrivateBrowsingOverriden) {
    80     nsCOMPtr<nsIPrivateBrowsingChannel> newPBChannel =
    81       do_QueryInterface(newChannel);
    82     if (newPBChannel) {
    83       newPBChannel->SetPrivate(mPrivateBrowsing);
    84     }
    85   }
    87   nsCOMPtr<nsIWritablePropertyBag> bag = ::do_QueryInterface(newChannel);
    88   if (bag)
    89     mPropertyHash.EnumerateRead(CopyProperties, bag.get());
    91   // Notify consumer, giving chance to cancel redirect.  For backwards compat,
    92   // we support nsIHttpEventSink if we are an HTTP channel and if this is not
    93   // an internal redirect.
    95   nsRefPtr<nsAsyncRedirectVerifyHelper> redirectCallbackHelper =
    96       new nsAsyncRedirectVerifyHelper();
    98   bool checkRedirectSynchronously = !openNewChannel;
   100   mRedirectChannel = newChannel;
   101   mRedirectFlags = redirectFlags;
   102   mOpenRedirectChannel = openNewChannel;
   103   nsresult rv = redirectCallbackHelper->Init(this, newChannel, redirectFlags,
   104                                              checkRedirectSynchronously);
   105   if (NS_FAILED(rv))
   106     return rv;
   108   if (checkRedirectSynchronously && NS_FAILED(mStatus))
   109     return mStatus;
   111   return NS_OK;
   112 }
   114 nsresult
   115 nsBaseChannel::ContinueRedirect()
   116 {
   117   // Backwards compat for non-internal redirects from a HTTP channel.
   118   // XXX Is our http channel implementation going to derive from nsBaseChannel?
   119   //     If not, this code can be removed.
   120   if (!(mRedirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL)) {
   121     nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface();
   122     if (httpChannel) {
   123       nsCOMPtr<nsIHttpEventSink> httpEventSink;
   124       GetCallback(httpEventSink);
   125       if (httpEventSink) {
   126         nsresult rv = httpEventSink->OnRedirect(httpChannel, mRedirectChannel);
   127         if (NS_FAILED(rv)) {
   128           return rv;
   129         }
   130       }
   131     }
   132   }
   134   // Make sure to do this _after_ making all the OnChannelRedirect calls
   135   mRedirectChannel->SetOriginalURI(OriginalURI());
   137   // If we fail to open the new channel, then we want to leave this channel
   138   // unaffected, so we defer tearing down our channel until we have succeeded
   139   // with the redirect.
   141   if (mOpenRedirectChannel) {
   142     nsresult rv = mRedirectChannel->AsyncOpen(mListener, mListenerContext);
   143     if (NS_FAILED(rv))
   144       return rv;
   145   }
   147   mRedirectChannel = nullptr;
   149   // close down this channel
   150   Cancel(NS_BINDING_REDIRECTED);
   151   ChannelDone();
   153   return NS_OK;
   154 }
   156 bool
   157 nsBaseChannel::HasContentTypeHint() const
   158 {
   159   NS_ASSERTION(!Pending(), "HasContentTypeHint called too late");
   160   return !mContentType.EqualsLiteral(UNKNOWN_CONTENT_TYPE);
   161 }
   163 nsresult
   164 nsBaseChannel::PushStreamConverter(const char *fromType,
   165                                    const char *toType,
   166                                    bool invalidatesContentLength,
   167                                    nsIStreamListener **result)
   168 {
   169   NS_ASSERTION(mListener, "no listener");
   171   nsresult rv;
   172   nsCOMPtr<nsIStreamConverterService> scs =
   173       do_GetService(NS_STREAMCONVERTERSERVICE_CONTRACTID, &rv);
   174   if (NS_FAILED(rv))
   175     return rv;
   177   nsCOMPtr<nsIStreamListener> converter;
   178   rv = scs->AsyncConvertData(fromType, toType, mListener, mListenerContext,
   179                              getter_AddRefs(converter));
   180   if (NS_SUCCEEDED(rv)) {
   181     mListener = converter;
   182     if (invalidatesContentLength)
   183       mContentLength = -1;
   184     if (result) {
   185       *result = nullptr;
   186       converter.swap(*result);
   187     }
   188   }
   189   return rv;
   190 }
   192 nsresult
   193 nsBaseChannel::BeginPumpingData()
   194 {
   195   nsCOMPtr<nsIInputStream> stream;
   196   nsCOMPtr<nsIChannel> channel;
   197   nsresult rv = OpenContentStream(true, getter_AddRefs(stream),
   198                                   getter_AddRefs(channel));
   199   if (NS_FAILED(rv))
   200     return rv;
   202   NS_ASSERTION(!stream || !channel, "Got both a channel and a stream?");
   204   if (channel) {
   205       rv = NS_DispatchToCurrentThread(new RedirectRunnable(this, channel));
   206       if (NS_SUCCEEDED(rv))
   207           mWaitingOnAsyncRedirect = true;
   208       return rv;
   209   }
   211   // By assigning mPump, we flag this channel as pending (see Pending).  It's
   212   // important that the pending flag is set when we call into the stream (the
   213   // call to AsyncRead results in the stream's AsyncWait method being called)
   214   // and especially when we call into the loadgroup.  Our caller takes care to
   215   // release mPump if we return an error.
   217   rv = nsInputStreamPump::Create(getter_AddRefs(mPump), stream, -1, -1, 0, 0,
   218                                  true);
   219   if (NS_SUCCEEDED(rv))
   220     rv = mPump->AsyncRead(this, nullptr);
   222   return rv;
   223 }
   225 void
   226 nsBaseChannel::HandleAsyncRedirect(nsIChannel* newChannel)
   227 {
   228   NS_ASSERTION(!mPump, "Shouldn't have gotten here");
   230   nsresult rv = mStatus;
   231   if (NS_SUCCEEDED(mStatus)) {
   232     rv = Redirect(newChannel,
   233                   nsIChannelEventSink::REDIRECT_TEMPORARY,
   234                   true);
   235     if (NS_SUCCEEDED(rv)) {
   236       // OnRedirectVerifyCallback will be called asynchronously
   237       return;
   238     }
   239   }
   241   ContinueHandleAsyncRedirect(rv);
   242 }
   244 void
   245 nsBaseChannel::ContinueHandleAsyncRedirect(nsresult result)
   246 {
   247   mWaitingOnAsyncRedirect = false;
   249   if (NS_FAILED(result))
   250     Cancel(result);
   252   if (NS_FAILED(result) && mListener) {
   253     // Notify our consumer ourselves
   254     mListener->OnStartRequest(this, mListenerContext);
   255     mListener->OnStopRequest(this, mListenerContext, mStatus);
   256     ChannelDone();
   257   }
   259   if (mLoadGroup)
   260     mLoadGroup->RemoveRequest(this, nullptr, mStatus);
   262   // Drop notification callbacks to prevent cycles.
   263   mCallbacks = nullptr;
   264   CallbacksChanged();
   265 }
   267 void
   268 nsBaseChannel::ClassifyURI()
   269 {
   270   nsresult rv;
   272   if (mLoadFlags & LOAD_CLASSIFY_URI) {
   273     nsRefPtr<nsChannelClassifier> classifier = new nsChannelClassifier();
   274     if (classifier) {
   275       rv = classifier->Start(this);
   276       if (NS_FAILED(rv)) {
   277         Cancel(rv);
   278       }
   279     } else {
   280       Cancel(NS_ERROR_OUT_OF_MEMORY);
   281     }
   282   }
   283 }
   285 //-----------------------------------------------------------------------------
   286 // nsBaseChannel::nsISupports
   288 NS_IMPL_ISUPPORTS_INHERITED(nsBaseChannel,
   289                             nsHashPropertyBag,
   290                             nsIRequest,
   291                             nsIChannel,
   292                             nsIInterfaceRequestor,
   293                             nsITransportEventSink,
   294                             nsIRequestObserver,
   295                             nsIStreamListener,
   296                             nsIAsyncVerifyRedirectCallback,
   297                             nsIPrivateBrowsingChannel)
   299 //-----------------------------------------------------------------------------
   300 // nsBaseChannel::nsIRequest
   302 NS_IMETHODIMP
   303 nsBaseChannel::GetName(nsACString &result)
   304 {
   305   if (!mURI) {
   306     result.Truncate();
   307     return NS_OK;
   308   }
   309   return mURI->GetSpec(result);
   310 }
   312 NS_IMETHODIMP
   313 nsBaseChannel::IsPending(bool *result)
   314 {
   315   *result = Pending();
   316   return NS_OK;
   317 }
   319 NS_IMETHODIMP
   320 nsBaseChannel::GetStatus(nsresult *status)
   321 {
   322   if (mPump && NS_SUCCEEDED(mStatus)) {
   323     mPump->GetStatus(status);
   324   } else {
   325     *status = mStatus;
   326   }
   327   return NS_OK;
   328 }
   330 NS_IMETHODIMP
   331 nsBaseChannel::Cancel(nsresult status)
   332 {
   333   // Ignore redundant cancelation
   334   if (NS_FAILED(mStatus))
   335     return NS_OK;
   337   mStatus = status;
   339   if (mPump)
   340     mPump->Cancel(status);
   342   return NS_OK;
   343 }
   345 NS_IMETHODIMP
   346 nsBaseChannel::Suspend()
   347 {
   348   NS_ENSURE_TRUE(mPump, NS_ERROR_NOT_INITIALIZED);
   349   return mPump->Suspend();
   350 }
   352 NS_IMETHODIMP
   353 nsBaseChannel::Resume()
   354 {
   355   NS_ENSURE_TRUE(mPump, NS_ERROR_NOT_INITIALIZED);
   356   return mPump->Resume();
   357 }
   359 NS_IMETHODIMP
   360 nsBaseChannel::GetLoadFlags(nsLoadFlags *aLoadFlags)
   361 {
   362   *aLoadFlags = mLoadFlags;
   363   return NS_OK;
   364 }
   366 NS_IMETHODIMP
   367 nsBaseChannel::SetLoadFlags(nsLoadFlags aLoadFlags)
   368 {
   369   mLoadFlags = aLoadFlags;
   370   return NS_OK;
   371 }
   373 NS_IMETHODIMP
   374 nsBaseChannel::GetLoadGroup(nsILoadGroup **aLoadGroup)
   375 {
   376   NS_IF_ADDREF(*aLoadGroup = mLoadGroup);
   377   return NS_OK;
   378 }
   380 NS_IMETHODIMP
   381 nsBaseChannel::SetLoadGroup(nsILoadGroup *aLoadGroup)
   382 {
   383   if (!CanSetLoadGroup(aLoadGroup)) {
   384     return NS_ERROR_FAILURE;
   385   }
   387   mLoadGroup = aLoadGroup;
   388   CallbacksChanged();
   389   return NS_OK;
   390 }
   392 //-----------------------------------------------------------------------------
   393 // nsBaseChannel::nsIChannel
   395 NS_IMETHODIMP
   396 nsBaseChannel::GetOriginalURI(nsIURI **aURI)
   397 {
   398   *aURI = OriginalURI();
   399   NS_ADDREF(*aURI);
   400   return NS_OK;
   401 }
   403 NS_IMETHODIMP
   404 nsBaseChannel::SetOriginalURI(nsIURI *aURI)
   405 {
   406   NS_ENSURE_ARG_POINTER(aURI);
   407   mOriginalURI = aURI;
   408   return NS_OK;
   409 }
   411 NS_IMETHODIMP
   412 nsBaseChannel::GetURI(nsIURI **aURI)
   413 {
   414   NS_IF_ADDREF(*aURI = mURI);
   415   return NS_OK;
   416 }
   418 NS_IMETHODIMP
   419 nsBaseChannel::GetOwner(nsISupports **aOwner)
   420 {
   421   NS_IF_ADDREF(*aOwner = mOwner);
   422   return NS_OK;
   423 }
   425 NS_IMETHODIMP
   426 nsBaseChannel::SetOwner(nsISupports *aOwner)
   427 {
   428   mOwner = aOwner;
   429   return NS_OK;
   430 }
   432 NS_IMETHODIMP
   433 nsBaseChannel::GetNotificationCallbacks(nsIInterfaceRequestor **aCallbacks)
   434 {
   435   NS_IF_ADDREF(*aCallbacks = mCallbacks);
   436   return NS_OK;
   437 }
   439 NS_IMETHODIMP
   440 nsBaseChannel::SetNotificationCallbacks(nsIInterfaceRequestor *aCallbacks)
   441 {
   442   if (!CanSetCallbacks(aCallbacks)) {
   443     return NS_ERROR_FAILURE;
   444   }
   446   mCallbacks = aCallbacks;
   447   CallbacksChanged();
   448   return NS_OK;
   449 }
   451 NS_IMETHODIMP 
   452 nsBaseChannel::GetSecurityInfo(nsISupports **aSecurityInfo)
   453 {
   454   NS_IF_ADDREF(*aSecurityInfo = mSecurityInfo);
   455   return NS_OK;
   456 }
   458 NS_IMETHODIMP
   459 nsBaseChannel::GetContentType(nsACString &aContentType)
   460 {
   461   aContentType = mContentType;
   462   return NS_OK;
   463 }
   465 NS_IMETHODIMP
   466 nsBaseChannel::SetContentType(const nsACString &aContentType)
   467 {
   468   // mContentCharset is unchanged if not parsed
   469   bool dummy;
   470   net_ParseContentType(aContentType, mContentType, mContentCharset, &dummy);
   471   return NS_OK;
   472 }
   474 NS_IMETHODIMP
   475 nsBaseChannel::GetContentCharset(nsACString &aContentCharset)
   476 {
   477   aContentCharset = mContentCharset;
   478   return NS_OK;
   479 }
   481 NS_IMETHODIMP
   482 nsBaseChannel::SetContentCharset(const nsACString &aContentCharset)
   483 {
   484   mContentCharset = aContentCharset;
   485   return NS_OK;
   486 }
   488 NS_IMETHODIMP
   489 nsBaseChannel::GetContentDisposition(uint32_t *aContentDisposition)
   490 {
   491   // preserve old behavior, fail unless explicitly set.
   492   if (mContentDispositionHint == UINT32_MAX) {
   493     return NS_ERROR_NOT_AVAILABLE;
   494   }
   496   *aContentDisposition = mContentDispositionHint;
   497   return NS_OK;
   498 }
   500 NS_IMETHODIMP
   501 nsBaseChannel::SetContentDisposition(uint32_t aContentDisposition)
   502 {
   503   mContentDispositionHint = aContentDisposition;
   504   return NS_OK;
   505 }
   507 NS_IMETHODIMP
   508 nsBaseChannel::GetContentDispositionFilename(nsAString &aContentDispositionFilename)
   509 {
   510   if (!mContentDispositionFilename) {
   511     return NS_ERROR_NOT_AVAILABLE;
   512   }
   514   aContentDispositionFilename = *mContentDispositionFilename;
   515   return NS_OK;
   516 }
   518 NS_IMETHODIMP
   519 nsBaseChannel::SetContentDispositionFilename(const nsAString &aContentDispositionFilename)
   520 {
   521   mContentDispositionFilename = new nsString(aContentDispositionFilename);
   522   return NS_OK;
   523 }
   525 NS_IMETHODIMP
   526 nsBaseChannel::GetContentDispositionHeader(nsACString &aContentDispositionHeader)
   527 {
   528   return NS_ERROR_NOT_AVAILABLE;
   529 }
   531 NS_IMETHODIMP
   532 nsBaseChannel::GetContentLength(int64_t *aContentLength)
   533 {
   534   *aContentLength = mContentLength;
   535   return NS_OK;
   536 }
   538 NS_IMETHODIMP
   539 nsBaseChannel::SetContentLength(int64_t aContentLength)
   540 {
   541   mContentLength = aContentLength;
   542   return NS_OK;
   543 }
   545 NS_IMETHODIMP
   546 nsBaseChannel::Open(nsIInputStream **result)
   547 {
   548   NS_ENSURE_TRUE(mURI, NS_ERROR_NOT_INITIALIZED);
   549   NS_ENSURE_TRUE(!mPump, NS_ERROR_IN_PROGRESS);
   550   NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_IN_PROGRESS);
   552   nsCOMPtr<nsIChannel> chan;
   553   nsresult rv = OpenContentStream(false, result, getter_AddRefs(chan));
   554   NS_ASSERTION(!chan || !*result, "Got both a channel and a stream?");
   555   if (NS_SUCCEEDED(rv) && chan) {
   556       rv = Redirect(chan, nsIChannelEventSink::REDIRECT_INTERNAL, false);
   557       if (NS_FAILED(rv))
   558           return rv;
   559       rv = chan->Open(result);
   560   } else if (rv == NS_ERROR_NOT_IMPLEMENTED)
   561     return NS_ImplementChannelOpen(this, result);
   563   if (NS_SUCCEEDED(rv)) {
   564     mWasOpened = true;
   565     ClassifyURI();
   566   }
   568   return rv;
   569 }
   571 NS_IMETHODIMP
   572 nsBaseChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt)
   573 {
   574   NS_ENSURE_TRUE(mURI, NS_ERROR_NOT_INITIALIZED);
   575   NS_ENSURE_TRUE(!mPump, NS_ERROR_IN_PROGRESS);
   576   NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
   577   NS_ENSURE_ARG(listener);
   579   // Ensure that this is an allowed port before proceeding.
   580   nsresult rv = NS_CheckPortSafety(mURI);
   581   if (NS_FAILED(rv)) {
   582     mCallbacks = nullptr;
   583     return rv;
   584   }
   586   // Store the listener and context early so that OpenContentStream and the
   587   // stream's AsyncWait method (called by AsyncRead) can have access to them
   588   // via PushStreamConverter and the StreamListener methods.  However, since
   589   // this typically introduces a reference cycle between this and the listener,
   590   // we need to be sure to break the reference if this method does not succeed.
   591   mListener = listener;
   592   mListenerContext = ctxt;
   594   // This method assigns mPump as a side-effect.  We need to clear mPump if
   595   // this method fails.
   596   rv = BeginPumpingData();
   597   if (NS_FAILED(rv)) {
   598     mPump = nullptr;
   599     ChannelDone();
   600     mCallbacks = nullptr;
   601     return rv;
   602   }
   604   // At this point, we are going to return success no matter what.
   606   mWasOpened = true;
   608   SUSPEND_PUMP_FOR_SCOPE();
   610   if (mLoadGroup)
   611     mLoadGroup->AddRequest(this, nullptr);
   613   ClassifyURI();
   615   return NS_OK;
   616 }
   618 //-----------------------------------------------------------------------------
   619 // nsBaseChannel::nsITransportEventSink
   621 NS_IMETHODIMP
   622 nsBaseChannel::OnTransportStatus(nsITransport *transport, nsresult status,
   623                                  uint64_t progress, uint64_t progressMax)
   624 {
   625   // In some cases, we may wish to suppress transport-layer status events.
   627   if (!mPump || NS_FAILED(mStatus) || HasLoadFlag(LOAD_BACKGROUND))
   628     return NS_OK;
   630   SUSPEND_PUMP_FOR_SCOPE();
   632   // Lazily fetch mProgressSink
   633   if (!mProgressSink) {
   634     if (mQueriedProgressSink)
   635       return NS_OK;
   636     GetCallback(mProgressSink);
   637     mQueriedProgressSink = true;
   638     if (!mProgressSink)
   639       return NS_OK;
   640   }
   642   nsAutoString statusArg;
   643   if (GetStatusArg(status, statusArg))
   644     mProgressSink->OnStatus(this, mListenerContext, status, statusArg.get());
   646   if (progress)
   647     mProgressSink->OnProgress(this, mListenerContext, progress, progressMax);
   649   return NS_OK;
   650 }
   652 //-----------------------------------------------------------------------------
   653 // nsBaseChannel::nsIInterfaceRequestor
   655 NS_IMETHODIMP
   656 nsBaseChannel::GetInterface(const nsIID &iid, void **result)
   657 {
   658   NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup, iid, result);
   659   return *result ? NS_OK : NS_ERROR_NO_INTERFACE; 
   660 }
   662 //-----------------------------------------------------------------------------
   663 // nsBaseChannel::nsIRequestObserver
   665 static void
   666 CallTypeSniffers(void *aClosure, const uint8_t *aData, uint32_t aCount)
   667 {
   668   nsIChannel *chan = static_cast<nsIChannel*>(aClosure);
   670   nsAutoCString newType;
   671   NS_SniffContent(NS_CONTENT_SNIFFER_CATEGORY, chan, aData, aCount, newType);
   672   if (!newType.IsEmpty()) {
   673     chan->SetContentType(newType);
   674   }
   675 }
   677 static void
   678 CallUnknownTypeSniffer(void *aClosure, const uint8_t *aData, uint32_t aCount)
   679 {
   680   nsIChannel *chan = static_cast<nsIChannel*>(aClosure);
   682   nsCOMPtr<nsIContentSniffer> sniffer =
   683     do_CreateInstance(NS_GENERIC_CONTENT_SNIFFER);
   684   if (!sniffer)
   685     return;
   687   nsAutoCString detected;
   688   nsresult rv = sniffer->GetMIMETypeFromContent(chan, aData, aCount, detected);
   689   if (NS_SUCCEEDED(rv))
   690     chan->SetContentType(detected);
   691 }
   693 NS_IMETHODIMP
   694 nsBaseChannel::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
   695 {
   696   // If our content type is unknown or if the content type is
   697   // application/octet-stream and the caller requested it, use the content type
   698   // sniffer. If the sniffer is not available for some reason, then we just keep
   699   // going as-is.
   700   bool shouldSniff = mContentType.EqualsLiteral(UNKNOWN_CONTENT_TYPE) ||
   701             ((mLoadFlags & LOAD_TREAT_APPLICATION_OCTET_STREAM_AS_UNKNOWN) &&
   702             mContentType.EqualsLiteral(APPLICATION_OCTET_STREAM));
   704   if (NS_SUCCEEDED(mStatus) && shouldSniff) {
   705     mPump->PeekStream(CallUnknownTypeSniffer, static_cast<nsIChannel*>(this));
   706   }
   708   // Now, the general type sniffers. Skip this if we have none.
   709   if (mLoadFlags & LOAD_CALL_CONTENT_SNIFFERS)
   710     mPump->PeekStream(CallTypeSniffers, static_cast<nsIChannel*>(this));
   712   SUSPEND_PUMP_FOR_SCOPE();
   714   if (mListener) // null in case of redirect
   715       return mListener->OnStartRequest(this, mListenerContext);
   716   return NS_OK;
   717 }
   719 NS_IMETHODIMP
   720 nsBaseChannel::OnStopRequest(nsIRequest *request, nsISupports *ctxt,
   721                              nsresult status)
   722 {
   723   // If both mStatus and status are failure codes, we keep mStatus as-is since
   724   // that is consistent with our GetStatus and Cancel methods.
   725   if (NS_SUCCEEDED(mStatus))
   726     mStatus = status;
   728   // Cause Pending to return false.
   729   mPump = nullptr;
   731   if (mListener) // null in case of redirect
   732       mListener->OnStopRequest(this, mListenerContext, mStatus);
   733   ChannelDone();
   735   // No need to suspend pump in this scope since we will not be receiving
   736   // any more events from it.
   738   if (mLoadGroup)
   739     mLoadGroup->RemoveRequest(this, nullptr, mStatus);
   741   // Drop notification callbacks to prevent cycles.
   742   mCallbacks = nullptr;
   743   CallbacksChanged();
   745   return NS_OK;
   746 }
   748 //-----------------------------------------------------------------------------
   749 // nsBaseChannel::nsIStreamListener
   751 NS_IMETHODIMP
   752 nsBaseChannel::OnDataAvailable(nsIRequest *request, nsISupports *ctxt,
   753                                nsIInputStream *stream, uint64_t offset,
   754                                uint32_t count)
   755 {
   756   SUSPEND_PUMP_FOR_SCOPE();
   758   nsresult rv = mListener->OnDataAvailable(this, mListenerContext, stream,
   759                                            offset, count);
   760   if (mSynthProgressEvents && NS_SUCCEEDED(rv)) {
   761     uint64_t prog = offset + count;
   762     OnTransportStatus(nullptr, NS_NET_STATUS_READING, prog, mContentLength);
   763   }
   765   return rv;
   766 }
   768 NS_IMETHODIMP
   769 nsBaseChannel::OnRedirectVerifyCallback(nsresult result)
   770 {
   771   if (NS_SUCCEEDED(result))
   772     result = ContinueRedirect();
   774   if (NS_FAILED(result) && !mWaitingOnAsyncRedirect) {
   775     if (NS_SUCCEEDED(mStatus))
   776       mStatus = result;
   777     return NS_OK;
   778   }
   780   if (mWaitingOnAsyncRedirect)
   781     ContinueHandleAsyncRedirect(result);
   783   return NS_OK;
   784 }

mercurial