netwerk/protocol/http/HttpBaseChannel.cpp

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim: set sw=2 ts=8 et tw=80 : */
     4 /* This Source Code Form is subject to the terms of the Mozilla Public
     5  * License, v. 2.0. If a copy of the MPL was not distributed with this
     6  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     8 // HttpLog.h should generally be included first
     9 #include "HttpLog.h"
    11 #include "mozilla/net/HttpBaseChannel.h"
    13 #include "nsHttpHandler.h"
    14 #include "nsMimeTypes.h"
    15 #include "nsNetUtil.h"
    17 #include "nsICachingChannel.h"
    18 #include "nsIPrincipal.h"
    19 #include "nsISeekableStream.h"
    20 #include "nsITimedChannel.h"
    21 #include "nsIEncodedChannel.h"
    22 #include "nsIApplicationCacheChannel.h"
    23 #include "nsEscape.h"
    24 #include "nsStreamListenerWrapper.h"
    25 #include "nsISecurityConsoleMessage.h"
    26 #include "nsURLHelper.h"
    27 #include "nsICookieService.h"
    28 #include "nsIStreamConverterService.h"
    29 #include "nsCRT.h"
    30 #include "nsContentUtils.h"
    31 #include "nsIScriptSecurityManager.h"
    32 #include "nsIObserverService.h"
    34 #include <algorithm>
    36 namespace mozilla {
    37 namespace net {
    39 HttpBaseChannel::HttpBaseChannel()
    40   : mStartPos(UINT64_MAX)
    41   , mStatus(NS_OK)
    42   , mLoadFlags(LOAD_NORMAL)
    43   , mCaps(0)
    44   , mPriority(PRIORITY_NORMAL)
    45   , mRedirectionLimit(gHttpHandler->RedirectionLimit())
    46   , mApplyConversion(true)
    47   , mCanceled(false)
    48   , mIsPending(false)
    49   , mWasOpened(false)
    50   , mRequestObserversCalled(false)
    51   , mResponseHeadersModified(false)
    52   , mAllowPipelining(true)
    53   , mForceAllowThirdPartyCookie(false)
    54   , mUploadStreamHasHeaders(false)
    55   , mInheritApplicationCache(true)
    56   , mChooseApplicationCache(false)
    57   , mLoadedFromApplicationCache(false)
    58   , mChannelIsForDownload(false)
    59   , mTracingEnabled(true)
    60   , mTimingEnabled(false)
    61   , mAllowSpdy(true)
    62   , mLoadAsBlocking(false)
    63   , mLoadUnblocked(false)
    64   , mResponseTimeoutEnabled(true)
    65   , mAllRedirectsSameOrigin(true)
    66   , mSuspendCount(0)
    67   , mProxyResolveFlags(0)
    68   , mContentDispositionHint(UINT32_MAX)
    69   , mHttpHandler(gHttpHandler)
    70   , mRedirectCount(0)
    71   , mProxyURI(nullptr)
    72 {
    73   LOG(("Creating HttpBaseChannel @%x\n", this));
    75   // Subfields of unions cannot be targeted in an initializer list
    76   mSelfAddr.raw.family = PR_AF_UNSPEC;
    77   mPeerAddr.raw.family = PR_AF_UNSPEC;
    78 }
    80 HttpBaseChannel::~HttpBaseChannel()
    81 {
    82   LOG(("Destroying HttpBaseChannel @%x\n", this));
    84   // Make sure we don't leak
    85   CleanRedirectCacheChainIfNecessary();
    86 }
    88 nsresult
    89 HttpBaseChannel::Init(nsIURI *aURI,
    90                       uint32_t aCaps,
    91                       nsProxyInfo *aProxyInfo,
    92                       uint32_t aProxyResolveFlags,
    93                       nsIURI *aProxyURI)
    94 {
    95   LOG(("HttpBaseChannel::Init [this=%p]\n", this));
    97   NS_PRECONDITION(aURI, "null uri");
    99   mURI = aURI;
   100   mOriginalURI = aURI;
   101   mDocumentURI = nullptr;
   102   mCaps = aCaps;
   103   mProxyResolveFlags = aProxyResolveFlags;
   104   mProxyURI = aProxyURI;
   106   // Construct connection info object
   107   nsAutoCString host;
   108   int32_t port = -1;
   109   bool usingSSL = false;
   111   nsresult rv = mURI->SchemeIs("https", &usingSSL);
   112   if (NS_FAILED(rv)) return rv;
   114   rv = mURI->GetAsciiHost(host);
   115   if (NS_FAILED(rv)) return rv;
   117   // Reject the URL if it doesn't specify a host
   118   if (host.IsEmpty())
   119     return NS_ERROR_MALFORMED_URI;
   121   rv = mURI->GetPort(&port);
   122   if (NS_FAILED(rv)) return rv;
   124   LOG(("host=%s port=%d\n", host.get(), port));
   126   rv = mURI->GetAsciiSpec(mSpec);
   127   if (NS_FAILED(rv)) return rv;
   128   LOG(("uri=%s\n", mSpec.get()));
   130   // Assert default request method
   131   MOZ_ASSERT(mRequestHead.EqualsMethod(nsHttpRequestHead::kMethod_Get));
   133   // Set request headers
   134   nsAutoCString hostLine;
   135   rv = nsHttpHandler::GenerateHostPort(host, port, hostLine);
   136   if (NS_FAILED(rv)) return rv;
   138   rv = mRequestHead.SetHeader(nsHttp::Host, hostLine);
   139   if (NS_FAILED(rv)) return rv;
   141   rv = gHttpHandler->AddStandardRequestHeaders(&mRequestHead.Headers());
   142   if (NS_FAILED(rv)) return rv;
   144   nsAutoCString type;
   145   if (aProxyInfo && NS_SUCCEEDED(aProxyInfo->GetType(type)) &&
   146       !type.EqualsLiteral("unknown"))
   147     mProxyInfo = aProxyInfo;
   149   return rv;
   150 }
   152 //-----------------------------------------------------------------------------
   153 // HttpBaseChannel::nsISupports
   154 //-----------------------------------------------------------------------------
   156 NS_IMPL_ADDREF(HttpBaseChannel)
   157 NS_IMPL_RELEASE(HttpBaseChannel)
   159 NS_INTERFACE_MAP_BEGIN(HttpBaseChannel)
   160   NS_INTERFACE_MAP_ENTRY(nsIRequest)
   161   NS_INTERFACE_MAP_ENTRY(nsIChannel)
   162   NS_INTERFACE_MAP_ENTRY(nsIEncodedChannel)
   163   NS_INTERFACE_MAP_ENTRY(nsIHttpChannel)
   164   NS_INTERFACE_MAP_ENTRY(nsIHttpChannelInternal)
   165   NS_INTERFACE_MAP_ENTRY(nsIUploadChannel)
   166   NS_INTERFACE_MAP_ENTRY(nsIUploadChannel2)
   167   NS_INTERFACE_MAP_ENTRY(nsISupportsPriority)
   168   NS_INTERFACE_MAP_ENTRY(nsITraceableChannel)
   169   NS_INTERFACE_MAP_ENTRY(nsIPrivateBrowsingChannel)
   170   NS_INTERFACE_MAP_ENTRY(nsITimedChannel)
   171 NS_INTERFACE_MAP_END_INHERITING(nsHashPropertyBag)
   173 //-----------------------------------------------------------------------------
   174 // HttpBaseChannel::nsIRequest
   175 //-----------------------------------------------------------------------------
   177 NS_IMETHODIMP
   178 HttpBaseChannel::GetName(nsACString& aName)
   179 {
   180   aName = mSpec;
   181   return NS_OK;
   182 }
   184 NS_IMETHODIMP
   185 HttpBaseChannel::IsPending(bool *aIsPending)
   186 {
   187   NS_ENSURE_ARG_POINTER(aIsPending);
   188   *aIsPending = mIsPending;
   189   return NS_OK;
   190 }
   192 NS_IMETHODIMP
   193 HttpBaseChannel::GetStatus(nsresult *aStatus)
   194 {
   195   NS_ENSURE_ARG_POINTER(aStatus);
   196   *aStatus = mStatus;
   197   return NS_OK;
   198 }
   200 NS_IMETHODIMP
   201 HttpBaseChannel::GetLoadGroup(nsILoadGroup **aLoadGroup)
   202 {
   203   NS_ENSURE_ARG_POINTER(aLoadGroup);
   204   *aLoadGroup = mLoadGroup;
   205   NS_IF_ADDREF(*aLoadGroup);
   206   return NS_OK;
   207 }
   209 NS_IMETHODIMP
   210 HttpBaseChannel::SetLoadGroup(nsILoadGroup *aLoadGroup)
   211 {
   212   MOZ_ASSERT(NS_IsMainThread(), "Should only be called on the main thread.");
   214   if (!CanSetLoadGroup(aLoadGroup)) {
   215     return NS_ERROR_FAILURE;
   216   }
   218   mLoadGroup = aLoadGroup;
   219   mProgressSink = nullptr;
   220   mPrivateBrowsing = NS_UsePrivateBrowsing(this);
   221   return NS_OK;
   222 }
   224 NS_IMETHODIMP
   225 HttpBaseChannel::GetLoadFlags(nsLoadFlags *aLoadFlags)
   226 {
   227   NS_ENSURE_ARG_POINTER(aLoadFlags);
   228   *aLoadFlags = mLoadFlags;
   229   return NS_OK;
   230 }
   232 NS_IMETHODIMP
   233 HttpBaseChannel::SetLoadFlags(nsLoadFlags aLoadFlags)
   234 {
   235   mLoadFlags = aLoadFlags;
   236   return NS_OK;
   237 }
   239 //-----------------------------------------------------------------------------
   240 // HttpBaseChannel::nsIChannel
   241 //-----------------------------------------------------------------------------
   243 NS_IMETHODIMP
   244 HttpBaseChannel::GetOriginalURI(nsIURI **aOriginalURI)
   245 {
   246   NS_ENSURE_ARG_POINTER(aOriginalURI);
   247   *aOriginalURI = mOriginalURI;
   248   NS_ADDREF(*aOriginalURI);
   249   return NS_OK;
   250 }
   252 NS_IMETHODIMP
   253 HttpBaseChannel::SetOriginalURI(nsIURI *aOriginalURI)
   254 {
   255   ENSURE_CALLED_BEFORE_CONNECT();
   257   NS_ENSURE_ARG_POINTER(aOriginalURI);
   258   mOriginalURI = aOriginalURI;
   259   return NS_OK;
   260 }
   262 NS_IMETHODIMP
   263 HttpBaseChannel::GetURI(nsIURI **aURI)
   264 {
   265   NS_ENSURE_ARG_POINTER(aURI);
   266   *aURI = mURI;
   267   NS_ADDREF(*aURI);
   268   return NS_OK;
   269 }
   271 NS_IMETHODIMP
   272 HttpBaseChannel::GetOwner(nsISupports **aOwner)
   273 {
   274   NS_ENSURE_ARG_POINTER(aOwner);
   275   *aOwner = mOwner;
   276   NS_IF_ADDREF(*aOwner);
   277   return NS_OK;
   278 }
   280 NS_IMETHODIMP
   281 HttpBaseChannel::SetOwner(nsISupports *aOwner)
   282 {
   283   mOwner = aOwner;
   284   return NS_OK;
   285 }
   287 NS_IMETHODIMP
   288 HttpBaseChannel::GetNotificationCallbacks(nsIInterfaceRequestor **aCallbacks)
   289 {
   290   *aCallbacks = mCallbacks;
   291   NS_IF_ADDREF(*aCallbacks);
   292   return NS_OK;
   293 }
   295 NS_IMETHODIMP
   296 HttpBaseChannel::SetNotificationCallbacks(nsIInterfaceRequestor *aCallbacks)
   297 {
   298   MOZ_ASSERT(NS_IsMainThread(), "Should only be called on the main thread.");
   300   if (!CanSetCallbacks(aCallbacks)) {
   301     return NS_ERROR_FAILURE;
   302   }
   304   mCallbacks = aCallbacks;
   305   mProgressSink = nullptr;
   307   mPrivateBrowsing = NS_UsePrivateBrowsing(this);
   308   return NS_OK;
   309 }
   311 NS_IMETHODIMP
   312 HttpBaseChannel::GetContentType(nsACString& aContentType)
   313 {
   314   if (!mResponseHead) {
   315     aContentType.Truncate();
   316     return NS_ERROR_NOT_AVAILABLE;
   317   }
   319   if (!mResponseHead->ContentType().IsEmpty()) {
   320     aContentType = mResponseHead->ContentType();
   321     return NS_OK;
   322   }
   324   aContentType.AssignLiteral(UNKNOWN_CONTENT_TYPE);
   325   return NS_OK;
   326 }
   328 NS_IMETHODIMP
   329 HttpBaseChannel::SetContentType(const nsACString& aContentType)
   330 {
   331   if (mListener || mWasOpened) {
   332     if (!mResponseHead)
   333       return NS_ERROR_NOT_AVAILABLE;
   335     nsAutoCString contentTypeBuf, charsetBuf;
   336     bool hadCharset;
   337     net_ParseContentType(aContentType, contentTypeBuf, charsetBuf, &hadCharset);
   339     mResponseHead->SetContentType(contentTypeBuf);
   341     // take care not to stomp on an existing charset
   342     if (hadCharset)
   343       mResponseHead->SetContentCharset(charsetBuf);
   345   } else {
   346     // We are being given a content-type hint.
   347     bool dummy;
   348     net_ParseContentType(aContentType, mContentTypeHint, mContentCharsetHint,
   349                          &dummy);
   350   }
   352   return NS_OK;
   353 }
   355 NS_IMETHODIMP
   356 HttpBaseChannel::GetContentCharset(nsACString& aContentCharset)
   357 {
   358   if (!mResponseHead)
   359     return NS_ERROR_NOT_AVAILABLE;
   361   aContentCharset = mResponseHead->ContentCharset();
   362   return NS_OK;
   363 }
   365 NS_IMETHODIMP
   366 HttpBaseChannel::SetContentCharset(const nsACString& aContentCharset)
   367 {
   368   if (mListener) {
   369     if (!mResponseHead)
   370       return NS_ERROR_NOT_AVAILABLE;
   372     mResponseHead->SetContentCharset(aContentCharset);
   373   } else {
   374     // Charset hint
   375     mContentCharsetHint = aContentCharset;
   376   }
   377   return NS_OK;
   378 }
   380 NS_IMETHODIMP
   381 HttpBaseChannel::GetContentDisposition(uint32_t *aContentDisposition)
   382 {
   383   nsresult rv;
   384   nsCString header;
   386   rv = GetContentDispositionHeader(header);
   387   if (NS_FAILED(rv)) {
   388     if (mContentDispositionHint == UINT32_MAX)
   389       return rv;
   391     *aContentDisposition = mContentDispositionHint;
   392     return NS_OK;
   393   }
   395   *aContentDisposition = NS_GetContentDispositionFromHeader(header, this);
   396   return NS_OK;
   397 }
   399 NS_IMETHODIMP
   400 HttpBaseChannel::SetContentDisposition(uint32_t aContentDisposition)
   401 {
   402   mContentDispositionHint = aContentDisposition;
   403   return NS_OK;
   404 }
   406 NS_IMETHODIMP
   407 HttpBaseChannel::GetContentDispositionFilename(nsAString& aContentDispositionFilename)
   408 {
   409   aContentDispositionFilename.Truncate();
   410   nsresult rv;
   411   nsCString header;
   413   rv = GetContentDispositionHeader(header);
   414   if (NS_FAILED(rv)) {
   415     if (!mContentDispositionFilename)
   416       return rv;
   418     aContentDispositionFilename = *mContentDispositionFilename;
   419     return NS_OK;
   420   }
   422   return NS_GetFilenameFromDisposition(aContentDispositionFilename,
   423                                        header, mURI);
   424 }
   426 NS_IMETHODIMP
   427 HttpBaseChannel::SetContentDispositionFilename(const nsAString& aContentDispositionFilename)
   428 {
   429   mContentDispositionFilename = new nsString(aContentDispositionFilename);
   430   return NS_OK;
   431 }
   433 NS_IMETHODIMP
   434 HttpBaseChannel::GetContentDispositionHeader(nsACString& aContentDispositionHeader)
   435 {
   436   if (!mResponseHead)
   437     return NS_ERROR_NOT_AVAILABLE;
   439   nsresult rv = mResponseHead->GetHeader(nsHttp::Content_Disposition,
   440                                          aContentDispositionHeader);
   441   if (NS_FAILED(rv) || aContentDispositionHeader.IsEmpty())
   442     return NS_ERROR_NOT_AVAILABLE;
   444   return NS_OK;
   445 }
   447 NS_IMETHODIMP
   448 HttpBaseChannel::GetContentLength(int64_t *aContentLength)
   449 {
   450   NS_ENSURE_ARG_POINTER(aContentLength);
   452   if (!mResponseHead)
   453     return NS_ERROR_NOT_AVAILABLE;
   455   *aContentLength = mResponseHead->ContentLength();
   456   return NS_OK;
   457 }
   459 NS_IMETHODIMP
   460 HttpBaseChannel::SetContentLength(int64_t value)
   461 {
   462   NS_NOTYETIMPLEMENTED("HttpBaseChannel::SetContentLength");
   463   return NS_ERROR_NOT_IMPLEMENTED;
   464 }
   466 NS_IMETHODIMP
   467 HttpBaseChannel::Open(nsIInputStream **aResult)
   468 {
   469   NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_IN_PROGRESS);
   470   return NS_ImplementChannelOpen(this, aResult);
   471 }
   473 //-----------------------------------------------------------------------------
   474 // HttpBaseChannel::nsIUploadChannel
   475 //-----------------------------------------------------------------------------
   477 NS_IMETHODIMP
   478 HttpBaseChannel::GetUploadStream(nsIInputStream **stream)
   479 {
   480   NS_ENSURE_ARG_POINTER(stream);
   481   *stream = mUploadStream;
   482   NS_IF_ADDREF(*stream);
   483   return NS_OK;
   484 }
   486 NS_IMETHODIMP
   487 HttpBaseChannel::SetUploadStream(nsIInputStream *stream,
   488                                const nsACString &contentType,
   489                                int64_t contentLength)
   490 {
   491   // NOTE: for backwards compatibility and for compatibility with old style
   492   // plugins, |stream| may include headers, specifically Content-Type and
   493   // Content-Length headers.  in this case, |contentType| and |contentLength|
   494   // would be unspecified.  this is traditionally the case of a POST request,
   495   // and so we select POST as the request method if contentType and
   496   // contentLength are unspecified.
   498   if (stream) {
   499     nsAutoCString method;
   500     bool hasHeaders;
   502     if (contentType.IsEmpty()) {
   503       method = NS_LITERAL_CSTRING("POST");
   504       hasHeaders = true;
   505     } else {
   506       method = NS_LITERAL_CSTRING("PUT");
   507       hasHeaders = false;
   508     }
   509     return ExplicitSetUploadStream(stream, contentType, contentLength,
   510                                    method, hasHeaders);
   511   }
   513   // if stream is null, ExplicitSetUploadStream returns error.
   514   // So we need special case for GET method.
   515   mUploadStreamHasHeaders = false;
   516   mRequestHead.SetMethod(NS_LITERAL_CSTRING("GET")); // revert to GET request
   517   mUploadStream = stream;
   518   return NS_OK;
   519 }
   521 //-----------------------------------------------------------------------------
   522 // HttpBaseChannel::nsIUploadChannel2
   523 //-----------------------------------------------------------------------------
   525 NS_IMETHODIMP
   526 HttpBaseChannel::ExplicitSetUploadStream(nsIInputStream *aStream,
   527                                        const nsACString &aContentType,
   528                                        int64_t aContentLength,
   529                                        const nsACString &aMethod,
   530                                        bool aStreamHasHeaders)
   531 {
   532   // Ensure stream is set and method is valid
   533   NS_ENSURE_TRUE(aStream, NS_ERROR_FAILURE);
   535   if (aContentLength < 0 && !aStreamHasHeaders) {
   536     nsresult rv = aStream->Available(reinterpret_cast<uint64_t*>(&aContentLength));
   537     if (NS_FAILED(rv) || aContentLength < 0) {
   538       NS_ERROR("unable to determine content length");
   539       return NS_ERROR_FAILURE;
   540     }
   541   }
   543   nsresult rv = SetRequestMethod(aMethod);
   544   NS_ENSURE_SUCCESS(rv, rv);
   546   if (!aStreamHasHeaders) {
   547     // SetRequestHeader propagates headers to chrome if HttpChannelChild
   548     nsAutoCString contentLengthStr;
   549     contentLengthStr.AppendInt(aContentLength);
   550     SetRequestHeader(NS_LITERAL_CSTRING("Content-Length"), contentLengthStr,
   551                      false);
   552     SetRequestHeader(NS_LITERAL_CSTRING("Content-Type"), aContentType,
   553                      false);
   554   }
   556   mUploadStreamHasHeaders = aStreamHasHeaders;
   557   mUploadStream = aStream;
   558   return NS_OK;
   559 }
   561 NS_IMETHODIMP
   562 HttpBaseChannel::GetUploadStreamHasHeaders(bool *hasHeaders)
   563 {
   564   NS_ENSURE_ARG(hasHeaders);
   566   *hasHeaders = mUploadStreamHasHeaders;
   567   return NS_OK;
   568 }
   570 //-----------------------------------------------------------------------------
   571 // HttpBaseChannel::nsIEncodedChannel
   572 //-----------------------------------------------------------------------------
   574 NS_IMETHODIMP
   575 HttpBaseChannel::GetApplyConversion(bool *value)
   576 {
   577   *value = mApplyConversion;
   578   return NS_OK;
   579 }
   581 NS_IMETHODIMP
   582 HttpBaseChannel::SetApplyConversion(bool value)
   583 {
   584   LOG(("HttpBaseChannel::SetApplyConversion [this=%p value=%d]\n", this, value));
   585   mApplyConversion = value;
   586   return NS_OK;
   587 }
   589 nsresult
   590 HttpBaseChannel::ApplyContentConversions()
   591 {
   592   if (!mResponseHead)
   593     return NS_OK;
   595   LOG(("HttpBaseChannel::ApplyContentConversions [this=%p]\n", this));
   597   if (!mApplyConversion) {
   598     LOG(("not applying conversion per mApplyConversion\n"));
   599     return NS_OK;
   600   }
   602   nsAutoCString contentEncoding;
   603   char *cePtr, *val;
   604   nsresult rv;
   606   rv = mResponseHead->GetHeader(nsHttp::Content_Encoding, contentEncoding);
   607   if (NS_FAILED(rv) || contentEncoding.IsEmpty())
   608     return NS_OK;
   610   // The encodings are listed in the order they were applied
   611   // (see rfc 2616 section 14.11), so they need to removed in reverse
   612   // order. This is accomplished because the converter chain ends up
   613   // being a stack with the last converter created being the first one
   614   // to accept the raw network data.
   616   cePtr = contentEncoding.BeginWriting();
   617   uint32_t count = 0;
   618   while ((val = nsCRT::strtok(cePtr, HTTP_LWS ",", &cePtr))) {
   619     if (++count > 16) {
   620       // That's ridiculous. We only understand 2 different ones :)
   621       // but for compatibility with old code, we will just carry on without
   622       // removing the encodings
   623       LOG(("Too many Content-Encodings. Ignoring remainder.\n"));
   624       break;
   625     }
   627     if (gHttpHandler->IsAcceptableEncoding(val)) {
   628       nsCOMPtr<nsIStreamConverterService> serv;
   629       rv = gHttpHandler->GetStreamConverterService(getter_AddRefs(serv));
   631       // we won't fail to load the page just because we couldn't load the
   632       // stream converter service.. carry on..
   633       if (NS_FAILED(rv)) {
   634         if (val)
   635           LOG(("Unknown content encoding '%s', ignoring\n", val));
   636         continue;
   637       }
   639       nsCOMPtr<nsIStreamListener> converter;
   640       nsAutoCString from(val);
   641       ToLowerCase(from);
   642       rv = serv->AsyncConvertData(from.get(),
   643                                   "uncompressed",
   644                                   mListener,
   645                                   mListenerContext,
   646                                   getter_AddRefs(converter));
   647       if (NS_FAILED(rv)) {
   648         LOG(("Unexpected failure of AsyncConvertData %s\n", val));
   649         return rv;
   650       }
   652       LOG(("converter removed '%s' content-encoding\n", val));
   653       mListener = converter;
   654     }
   655     else {
   656       if (val)
   657         LOG(("Unknown content encoding '%s', ignoring\n", val));
   658     }
   659   }
   661   return NS_OK;
   662 }
   664 NS_IMETHODIMP
   665 HttpBaseChannel::GetContentEncodings(nsIUTF8StringEnumerator** aEncodings)
   666 {
   667   if (!mResponseHead) {
   668     *aEncodings = nullptr;
   669     return NS_OK;
   670   }
   672   const char *encoding = mResponseHead->PeekHeader(nsHttp::Content_Encoding);
   673   if (!encoding) {
   674     *aEncodings = nullptr;
   675     return NS_OK;
   676   }
   677   nsContentEncodings* enumerator = new nsContentEncodings(this, encoding);
   678   NS_ADDREF(*aEncodings = enumerator);
   679   return NS_OK;
   680 }
   682 //-----------------------------------------------------------------------------
   683 // HttpBaseChannel::nsContentEncodings <public>
   684 //-----------------------------------------------------------------------------
   686 HttpBaseChannel::nsContentEncodings::nsContentEncodings(nsIHttpChannel* aChannel,
   687                                                         const char* aEncodingHeader)
   688   : mEncodingHeader(aEncodingHeader)
   689   , mChannel(aChannel)
   690   , mReady(false)
   691 {
   692   mCurEnd = aEncodingHeader + strlen(aEncodingHeader);
   693   mCurStart = mCurEnd;
   694 }
   696 HttpBaseChannel::nsContentEncodings::~nsContentEncodings()
   697 {
   698 }
   700 //-----------------------------------------------------------------------------
   701 // HttpBaseChannel::nsContentEncodings::nsISimpleEnumerator
   702 //-----------------------------------------------------------------------------
   704 NS_IMETHODIMP
   705 HttpBaseChannel::nsContentEncodings::HasMore(bool* aMoreEncodings)
   706 {
   707   if (mReady) {
   708     *aMoreEncodings = true;
   709     return NS_OK;
   710   }
   712   nsresult rv = PrepareForNext();
   713   *aMoreEncodings = NS_SUCCEEDED(rv);
   714   return NS_OK;
   715 }
   717 NS_IMETHODIMP
   718 HttpBaseChannel::nsContentEncodings::GetNext(nsACString& aNextEncoding)
   719 {
   720   aNextEncoding.Truncate();
   721   if (!mReady) {
   722     nsresult rv = PrepareForNext();
   723     if (NS_FAILED(rv)) {
   724       return NS_ERROR_FAILURE;
   725     }
   726   }
   728   const nsACString & encoding = Substring(mCurStart, mCurEnd);
   730   nsACString::const_iterator start, end;
   731   encoding.BeginReading(start);
   732   encoding.EndReading(end);
   734   bool haveType = false;
   735   if (CaseInsensitiveFindInReadable(NS_LITERAL_CSTRING("gzip"), start, end)) {
   736     aNextEncoding.AssignLiteral(APPLICATION_GZIP);
   737     haveType = true;
   738   }
   740   if (!haveType) {
   741     encoding.BeginReading(start);
   742     if (CaseInsensitiveFindInReadable(NS_LITERAL_CSTRING("compress"), start, end)) {
   743       aNextEncoding.AssignLiteral(APPLICATION_COMPRESS);
   744       haveType = true;
   745     }
   746   }
   748   if (!haveType) {
   749     encoding.BeginReading(start);
   750     if (CaseInsensitiveFindInReadable(NS_LITERAL_CSTRING("deflate"), start, end)) {
   751       aNextEncoding.AssignLiteral(APPLICATION_ZIP);
   752       haveType = true;
   753     }
   754   }
   756   // Prepare to fetch the next encoding
   757   mCurEnd = mCurStart;
   758   mReady = false;
   760   if (haveType)
   761     return NS_OK;
   763   NS_WARNING("Unknown encoding type");
   764   return NS_ERROR_FAILURE;
   765 }
   767 //-----------------------------------------------------------------------------
   768 // HttpBaseChannel::nsContentEncodings::nsISupports
   769 //-----------------------------------------------------------------------------
   771 NS_IMPL_ISUPPORTS(HttpBaseChannel::nsContentEncodings, nsIUTF8StringEnumerator)
   773 //-----------------------------------------------------------------------------
   774 // HttpBaseChannel::nsContentEncodings <private>
   775 //-----------------------------------------------------------------------------
   777 nsresult
   778 HttpBaseChannel::nsContentEncodings::PrepareForNext(void)
   779 {
   780   MOZ_ASSERT(mCurStart == mCurEnd, "Indeterminate state");
   782   // At this point both mCurStart and mCurEnd point to somewhere
   783   // past the end of the next thing we want to return
   785   while (mCurEnd != mEncodingHeader) {
   786     --mCurEnd;
   787     if (*mCurEnd != ',' && !nsCRT::IsAsciiSpace(*mCurEnd))
   788       break;
   789   }
   790   if (mCurEnd == mEncodingHeader)
   791     return NS_ERROR_NOT_AVAILABLE; // no more encodings
   792   ++mCurEnd;
   794   // At this point mCurEnd points to the first char _after_ the
   795   // header we want.  Furthermore, mCurEnd - 1 != mEncodingHeader
   797   mCurStart = mCurEnd - 1;
   798   while (mCurStart != mEncodingHeader &&
   799          *mCurStart != ',' && !nsCRT::IsAsciiSpace(*mCurStart))
   800     --mCurStart;
   801   if (*mCurStart == ',' || nsCRT::IsAsciiSpace(*mCurStart))
   802     ++mCurStart; // we stopped because of a weird char, so move up one
   804   // At this point mCurStart and mCurEnd bracket the encoding string
   805   // we want.  Check that it's not "identity"
   806   if (Substring(mCurStart, mCurEnd).Equals("identity",
   807                                            nsCaseInsensitiveCStringComparator())) {
   808     mCurEnd = mCurStart;
   809     return PrepareForNext();
   810   }
   812   mReady = true;
   813   return NS_OK;
   814 }
   817 //-----------------------------------------------------------------------------
   818 // HttpBaseChannel::nsIHttpChannel
   819 //-----------------------------------------------------------------------------
   821 NS_IMETHODIMP
   822 HttpBaseChannel::GetRequestMethod(nsACString& aMethod)
   823 {
   824   aMethod = mRequestHead.Method();
   825   return NS_OK;
   826 }
   828 NS_IMETHODIMP
   829 HttpBaseChannel::SetRequestMethod(const nsACString& aMethod)
   830 {
   831   ENSURE_CALLED_BEFORE_CONNECT();
   833   const nsCString& flatMethod = PromiseFlatCString(aMethod);
   835   // Method names are restricted to valid HTTP tokens.
   836   if (!nsHttp::IsValidToken(flatMethod))
   837     return NS_ERROR_INVALID_ARG;
   839   mRequestHead.SetMethod(flatMethod);
   840   return NS_OK;
   841 }
   843 NS_IMETHODIMP
   844 HttpBaseChannel::GetReferrer(nsIURI **referrer)
   845 {
   846   NS_ENSURE_ARG_POINTER(referrer);
   847   *referrer = mReferrer;
   848   NS_IF_ADDREF(*referrer);
   849   return NS_OK;
   850 }
   852 NS_IMETHODIMP
   853 HttpBaseChannel::SetReferrer(nsIURI *referrer)
   854 {
   855   ENSURE_CALLED_BEFORE_CONNECT();
   857   // clear existing referrer, if any
   858   mReferrer = nullptr;
   859   mRequestHead.ClearHeader(nsHttp::Referer);
   861   if (!referrer)
   862       return NS_OK;
   864   // 0: never send referer
   865   // 1: send referer for direct user action
   866   // 2: always send referer
   867   uint32_t userReferrerLevel = gHttpHandler->ReferrerLevel();
   869   // false: use real referrer
   870   // true: spoof with URI of the current request
   871   bool userSpoofReferrerSource = gHttpHandler->SpoofReferrerSource();
   873   // 0: full URI
   874   // 1: scheme+host+port+path
   875   // 2: scheme+host+port
   876   int userReferrerTrimmingPolicy = gHttpHandler->ReferrerTrimmingPolicy();
   878   // 0: send referer no matter what
   879   // 1: send referer ONLY when base domains match
   880   // 2: send referer ONLY when hosts match
   881   int userReferrerXOriginPolicy = gHttpHandler->ReferrerXOriginPolicy();
   883   // check referrer blocking pref
   884   uint32_t referrerLevel;
   885   if (mLoadFlags & LOAD_INITIAL_DOCUMENT_URI)
   886     referrerLevel = 1; // user action
   887   else
   888     referrerLevel = 2; // inline content
   889   if (userReferrerLevel < referrerLevel)
   890     return NS_OK;
   892   nsCOMPtr<nsIURI> referrerGrip;
   893   nsresult rv;
   894   bool match;
   896   //
   897   // Strip off "wyciwyg://123/" from wyciwyg referrers.
   898   //
   899   // XXX this really belongs elsewhere since wyciwyg URLs aren't part of necko.
   900   //   perhaps some sort of generic nsINestedURI could be used.  then, if an URI
   901   //   fails the whitelist test, then we could check for an inner URI and try
   902   //   that instead.  though, that might be too automatic.
   903   //
   904   rv = referrer->SchemeIs("wyciwyg", &match);
   905   if (NS_FAILED(rv)) return rv;
   906   if (match) {
   907     nsAutoCString path;
   908     rv = referrer->GetPath(path);
   909     if (NS_FAILED(rv)) return rv;
   911     uint32_t pathLength = path.Length();
   912     if (pathLength <= 2) return NS_ERROR_FAILURE;
   914     // Path is of the form "//123/http://foo/bar", with a variable number of
   915     // digits. To figure out where the "real" URL starts, search path for a
   916     // '/', starting at the third character.
   917     int32_t slashIndex = path.FindChar('/', 2);
   918     if (slashIndex == kNotFound) return NS_ERROR_FAILURE;
   920     // Get charset of the original URI so we can pass it to our fixed up URI.
   921     nsAutoCString charset;
   922     referrer->GetOriginCharset(charset);
   924     // Replace |referrer| with a URI without wyciwyg://123/.
   925     rv = NS_NewURI(getter_AddRefs(referrerGrip),
   926                    Substring(path, slashIndex + 1, pathLength - slashIndex - 1),
   927                    charset.get());
   928     if (NS_FAILED(rv)) return rv;
   930     referrer = referrerGrip.get();
   931   }
   933   //
   934   // block referrer if not on our white list...
   935   //
   936   static const char *const referrerWhiteList[] = {
   937     "http",
   938     "https",
   939     "ftp",
   940     nullptr
   941   };
   942   match = false;
   943   const char *const *scheme = referrerWhiteList;
   944   for (; *scheme && !match; ++scheme) {
   945     rv = referrer->SchemeIs(*scheme, &match);
   946     if (NS_FAILED(rv)) return rv;
   947   }
   948   if (!match)
   949     return NS_OK; // kick out....
   951   //
   952   // Handle secure referrals.
   953   //
   954   // Support referrals from a secure server if this is a secure site
   955   // and (optionally) if the host names are the same.
   956   //
   957   rv = referrer->SchemeIs("https", &match);
   958   if (NS_FAILED(rv)) return rv;
   959   if (match) {
   960     rv = mURI->SchemeIs("https", &match);
   961     if (NS_FAILED(rv)) return rv;
   962     if (!match)
   963       return NS_OK;
   965     if (!gHttpHandler->SendSecureXSiteReferrer()) {
   966       nsAutoCString referrerHost;
   967       nsAutoCString host;
   969       rv = referrer->GetAsciiHost(referrerHost);
   970       if (NS_FAILED(rv)) return rv;
   972       rv = mURI->GetAsciiHost(host);
   973       if (NS_FAILED(rv)) return rv;
   975       // GetAsciiHost returns lowercase hostname.
   976       if (!referrerHost.Equals(host))
   977         return NS_OK;
   978     }
   979   }
   981   nsCOMPtr<nsIURI> clone;
   982   //
   983   // we need to clone the referrer, so we can:
   984   //  (1) modify it
   985   //  (2) keep a reference to it after returning from this function
   986   //
   987   // Use CloneIgnoringRef to strip away any fragment per RFC 2616 section 14.36
   988   rv = referrer->CloneIgnoringRef(getter_AddRefs(clone));
   989   if (NS_FAILED(rv)) return rv;
   991   nsAutoCString currentHost;
   992   nsAutoCString referrerHost;
   994   rv = mURI->GetAsciiHost(currentHost);
   995   if (NS_FAILED(rv)) return rv;
   997   rv = clone->GetAsciiHost(referrerHost);
   998   if (NS_FAILED(rv)) return rv;
  1000   // check policy for sending ref only when hosts match
  1001   if (userReferrerXOriginPolicy == 2 && !currentHost.Equals(referrerHost))
  1002     return NS_OK;
  1004   if (userReferrerXOriginPolicy == 1) {
  1005     nsAutoCString currentDomain = currentHost;
  1006     nsAutoCString referrerDomain = referrerHost;
  1007     uint32_t extraDomains = 0;
  1008     nsCOMPtr<nsIEffectiveTLDService> eTLDService = do_GetService(
  1009       NS_EFFECTIVETLDSERVICE_CONTRACTID);
  1010     if (eTLDService) {
  1011       rv = eTLDService->GetBaseDomain(mURI, extraDomains, currentDomain);
  1012       if (NS_FAILED(rv)) return rv;
  1013       rv = eTLDService->GetBaseDomain(clone, extraDomains, referrerDomain); 
  1014       if (NS_FAILED(rv)) return rv;
  1017     // check policy for sending only when effective top level domain matches.
  1018     // this falls back on using host if eTLDService does not work
  1019     if (!currentDomain.Equals(referrerDomain))
  1020       return NS_OK;
  1023   // send spoofed referrer if desired
  1024   if (userSpoofReferrerSource) {
  1025     nsCOMPtr<nsIURI> mURIclone;
  1026     rv = mURI->CloneIgnoringRef(getter_AddRefs(mURIclone));
  1027     if (NS_FAILED(rv)) return rv;
  1028     clone = mURIclone;
  1029     currentHost = referrerHost;
  1032   // strip away any userpass; we don't want to be giving out passwords ;-)
  1033   rv = clone->SetUserPass(EmptyCString());
  1034   if (NS_FAILED(rv)) return rv;
  1036   nsAutoCString spec;
  1038   // check how much referer to send
  1039   switch (userReferrerTrimmingPolicy) {
  1041   case 1: {
  1042     // scheme+host+port+path
  1043     nsAutoCString prepath, path;
  1044     rv = clone->GetPrePath(prepath);
  1045     if (NS_FAILED(rv)) return rv;
  1047     nsCOMPtr<nsIURL> url(do_QueryInterface(clone));
  1048     if (!url) {
  1049       // if this isn't a url, play it safe
  1050       // and just send the prepath
  1051       spec = prepath;
  1052       break;
  1054     rv = url->GetFilePath(path);
  1055     if (NS_FAILED(rv)) return rv;
  1056     spec = prepath + path;
  1057     break;
  1059   case 2:
  1060     // scheme+host+port
  1061     rv = clone->GetPrePath(spec);
  1062     if (NS_FAILED(rv)) return rv;
  1063     break;
  1065   default:
  1066     // full URI
  1067     rv = clone->GetAsciiSpec(spec);
  1068     if (NS_FAILED(rv)) return rv;
  1069     break;
  1072   // finally, remember the referrer URI and set the Referer header.
  1073   mReferrer = clone;
  1074   mRequestHead.SetHeader(nsHttp::Referer, spec);
  1075   return NS_OK;
  1078 NS_IMETHODIMP
  1079 HttpBaseChannel::GetProxyURI(nsIURI** proxyURI)
  1081   NS_ENSURE_ARG_POINTER(proxyURI);
  1082   *proxyURI = mProxyURI;
  1083   NS_IF_ADDREF(*proxyURI);
  1084   return NS_OK;
  1087 NS_IMETHODIMP
  1088 HttpBaseChannel::GetRequestHeader(const nsACString& aHeader,
  1089                                   nsACString& aValue)
  1091   // XXX might be better to search the header list directly instead of
  1092   // hitting the http atom hash table.
  1093   nsHttpAtom atom = nsHttp::ResolveAtom(aHeader);
  1094   if (!atom)
  1095     return NS_ERROR_NOT_AVAILABLE;
  1097   return mRequestHead.GetHeader(atom, aValue);
  1100 NS_IMETHODIMP
  1101 HttpBaseChannel::SetRequestHeader(const nsACString& aHeader,
  1102                                   const nsACString& aValue,
  1103                                   bool aMerge)
  1105   const nsCString &flatHeader = PromiseFlatCString(aHeader);
  1106   const nsCString &flatValue  = PromiseFlatCString(aValue);
  1108   LOG(("HttpBaseChannel::SetRequestHeader [this=%p header=\"%s\" value=\"%s\" merge=%u]\n",
  1109       this, flatHeader.get(), flatValue.get(), aMerge));
  1111   // Header names are restricted to valid HTTP tokens.
  1112   if (!nsHttp::IsValidToken(flatHeader))
  1113     return NS_ERROR_INVALID_ARG;
  1115   // Header values MUST NOT contain line-breaks.  RFC 2616 technically
  1116   // permits CTL characters, including CR and LF, in header values provided
  1117   // they are quoted.  However, this can lead to problems if servers do not
  1118   // interpret quoted strings properly.  Disallowing CR and LF here seems
  1119   // reasonable and keeps things simple.  We also disallow a null byte.
  1120   if (flatValue.FindCharInSet("\r\n") != kNotFound ||
  1121       flatValue.Length() != strlen(flatValue.get()))
  1122     return NS_ERROR_INVALID_ARG;
  1124   nsHttpAtom atom = nsHttp::ResolveAtom(flatHeader.get());
  1125   if (!atom) {
  1126     NS_WARNING("failed to resolve atom");
  1127     return NS_ERROR_NOT_AVAILABLE;
  1130   return mRequestHead.SetHeader(atom, flatValue, aMerge);
  1133 NS_IMETHODIMP
  1134 HttpBaseChannel::VisitRequestHeaders(nsIHttpHeaderVisitor *visitor)
  1136   return mRequestHead.Headers().VisitHeaders(visitor);
  1139 NS_IMETHODIMP
  1140 HttpBaseChannel::GetResponseHeader(const nsACString &header, nsACString &value)
  1142   if (!mResponseHead)
  1143     return NS_ERROR_NOT_AVAILABLE;
  1145   nsHttpAtom atom = nsHttp::ResolveAtom(header);
  1146   if (!atom)
  1147     return NS_ERROR_NOT_AVAILABLE;
  1149   return mResponseHead->GetHeader(atom, value);
  1152 NS_IMETHODIMP
  1153 HttpBaseChannel::SetResponseHeader(const nsACString& header,
  1154                                    const nsACString& value,
  1155                                    bool merge)
  1157   LOG(("HttpBaseChannel::SetResponseHeader [this=%p header=\"%s\" value=\"%s\" merge=%u]\n",
  1158       this, PromiseFlatCString(header).get(), PromiseFlatCString(value).get(), merge));
  1160   if (!mResponseHead)
  1161     return NS_ERROR_NOT_AVAILABLE;
  1163   nsHttpAtom atom = nsHttp::ResolveAtom(header);
  1164   if (!atom)
  1165     return NS_ERROR_NOT_AVAILABLE;
  1167   // these response headers must not be changed
  1168   if (atom == nsHttp::Content_Type ||
  1169       atom == nsHttp::Content_Length ||
  1170       atom == nsHttp::Content_Encoding ||
  1171       atom == nsHttp::Trailer ||
  1172       atom == nsHttp::Transfer_Encoding)
  1173     return NS_ERROR_ILLEGAL_VALUE;
  1175   mResponseHeadersModified = true;
  1177   return mResponseHead->SetHeader(atom, value, merge);
  1180 NS_IMETHODIMP
  1181 HttpBaseChannel::VisitResponseHeaders(nsIHttpHeaderVisitor *visitor)
  1183   if (!mResponseHead)
  1184     return NS_ERROR_NOT_AVAILABLE;
  1185   return mResponseHead->Headers().VisitHeaders(visitor);
  1188 NS_IMETHODIMP
  1189 HttpBaseChannel::GetAllowPipelining(bool *value)
  1191   NS_ENSURE_ARG_POINTER(value);
  1192   *value = mAllowPipelining;
  1193   return NS_OK;
  1196 NS_IMETHODIMP
  1197 HttpBaseChannel::SetAllowPipelining(bool value)
  1199   ENSURE_CALLED_BEFORE_CONNECT();
  1201   mAllowPipelining = value;
  1202   return NS_OK;
  1205 NS_IMETHODIMP
  1206 HttpBaseChannel::GetRedirectionLimit(uint32_t *value)
  1208   NS_ENSURE_ARG_POINTER(value);
  1209   *value = mRedirectionLimit;
  1210   return NS_OK;
  1213 NS_IMETHODIMP
  1214 HttpBaseChannel::SetRedirectionLimit(uint32_t value)
  1216   ENSURE_CALLED_BEFORE_CONNECT();
  1218   mRedirectionLimit = std::min<uint32_t>(value, 0xff);
  1219   return NS_OK;
  1222 NS_IMETHODIMP
  1223 HttpBaseChannel::IsNoStoreResponse(bool *value)
  1225   if (!mResponseHead)
  1226     return NS_ERROR_NOT_AVAILABLE;
  1227   *value = mResponseHead->NoStore();
  1228   return NS_OK;
  1231 NS_IMETHODIMP
  1232 HttpBaseChannel::IsNoCacheResponse(bool *value)
  1234   if (!mResponseHead)
  1235     return NS_ERROR_NOT_AVAILABLE;
  1236   *value = mResponseHead->NoCache();
  1237   if (!*value)
  1238     *value = mResponseHead->ExpiresInPast();
  1239   return NS_OK;
  1242 NS_IMETHODIMP
  1243 HttpBaseChannel::GetResponseStatus(uint32_t *aValue)
  1245   if (!mResponseHead)
  1246     return NS_ERROR_NOT_AVAILABLE;
  1247   *aValue = mResponseHead->Status();
  1248   return NS_OK;
  1251 NS_IMETHODIMP
  1252 HttpBaseChannel::GetResponseStatusText(nsACString& aValue)
  1254   if (!mResponseHead)
  1255     return NS_ERROR_NOT_AVAILABLE;
  1256   aValue = mResponseHead->StatusText();
  1257   return NS_OK;
  1260 NS_IMETHODIMP
  1261 HttpBaseChannel::GetRequestSucceeded(bool *aValue)
  1263   if (!mResponseHead)
  1264     return NS_ERROR_NOT_AVAILABLE;
  1265   uint32_t status = mResponseHead->Status();
  1266   *aValue = (status / 100 == 2);
  1267   return NS_OK;
  1270 NS_IMETHODIMP
  1271 HttpBaseChannel::RedirectTo(nsIURI *newURI)
  1273   // We can only redirect unopened channels
  1274   ENSURE_CALLED_BEFORE_CONNECT();
  1276   // The redirect is stored internally for use in AsyncOpen
  1277   mAPIRedirectToURI = newURI;
  1279   return NS_OK;
  1282 //-----------------------------------------------------------------------------
  1283 // HttpBaseChannel::nsIHttpChannelInternal
  1284 //-----------------------------------------------------------------------------
  1286 NS_IMETHODIMP
  1287 HttpBaseChannel::GetDocumentURI(nsIURI **aDocumentURI)
  1289   NS_ENSURE_ARG_POINTER(aDocumentURI);
  1290   *aDocumentURI = mDocumentURI;
  1291   NS_IF_ADDREF(*aDocumentURI);
  1292   return NS_OK;
  1295 NS_IMETHODIMP
  1296 HttpBaseChannel::SetDocumentURI(nsIURI *aDocumentURI)
  1298   ENSURE_CALLED_BEFORE_CONNECT();
  1300   mDocumentURI = aDocumentURI;
  1301   return NS_OK;
  1304 NS_IMETHODIMP
  1305 HttpBaseChannel::GetRequestVersion(uint32_t *major, uint32_t *minor)
  1307   nsHttpVersion version = mRequestHead.Version();
  1309   if (major) { *major = version / 10; }
  1310   if (minor) { *minor = version % 10; }
  1312   return NS_OK;
  1315 NS_IMETHODIMP
  1316 HttpBaseChannel::GetResponseVersion(uint32_t *major, uint32_t *minor)
  1318   if (!mResponseHead)
  1320     *major = *minor = 0; // we should at least be kind about it
  1321     return NS_ERROR_NOT_AVAILABLE;
  1324   nsHttpVersion version = mResponseHead->Version();
  1326   if (major) { *major = version / 10; }
  1327   if (minor) { *minor = version % 10; }
  1329   return NS_OK;
  1332 namespace {
  1334 class CookieNotifierRunnable : public nsRunnable
  1336 public:
  1337   CookieNotifierRunnable(HttpBaseChannel* aChannel, char const * aCookie)
  1338     : mChannel(aChannel), mCookie(aCookie)
  1339   { }
  1341   NS_IMETHOD Run()
  1343     nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
  1344     if (obs) {
  1345       obs->NotifyObservers(static_cast<nsIChannel*>(mChannel.get()),
  1346                            "http-on-response-set-cookie",
  1347                            mCookie.get());
  1349     return NS_OK;
  1352 private:
  1353   nsRefPtr<HttpBaseChannel> mChannel;
  1354   NS_ConvertASCIItoUTF16 mCookie;
  1355 };
  1357 } // anonymous namespace
  1359 NS_IMETHODIMP
  1360 HttpBaseChannel::SetCookie(const char *aCookieHeader)
  1362   if (mLoadFlags & LOAD_ANONYMOUS)
  1363     return NS_OK;
  1365   // empty header isn't an error
  1366   if (!(aCookieHeader && *aCookieHeader))
  1367     return NS_OK;
  1369   nsICookieService *cs = gHttpHandler->GetCookieService();
  1370   NS_ENSURE_TRUE(cs, NS_ERROR_FAILURE);
  1372   nsresult rv =
  1373     cs->SetCookieStringFromHttp(mURI, nullptr, nullptr, aCookieHeader,
  1374                                 mResponseHead->PeekHeader(nsHttp::Date), this);
  1375   if (NS_SUCCEEDED(rv)) {
  1376     nsRefPtr<CookieNotifierRunnable> r =
  1377       new CookieNotifierRunnable(this, aCookieHeader);
  1378     NS_DispatchToMainThread(r);
  1380   return rv;
  1383 NS_IMETHODIMP
  1384 HttpBaseChannel::GetForceAllowThirdPartyCookie(bool *aForce)
  1386   *aForce = mForceAllowThirdPartyCookie;
  1387   return NS_OK;
  1390 NS_IMETHODIMP
  1391 HttpBaseChannel::SetForceAllowThirdPartyCookie(bool aForce)
  1393   ENSURE_CALLED_BEFORE_ASYNC_OPEN();
  1395   mForceAllowThirdPartyCookie = aForce;
  1396   return NS_OK;
  1399 NS_IMETHODIMP
  1400 HttpBaseChannel::GetCanceled(bool *aCanceled)
  1402   *aCanceled = mCanceled;
  1403   return NS_OK;
  1406 NS_IMETHODIMP
  1407 HttpBaseChannel::GetChannelIsForDownload(bool *aChannelIsForDownload)
  1409   *aChannelIsForDownload = mChannelIsForDownload;
  1410   return NS_OK;
  1413 NS_IMETHODIMP
  1414 HttpBaseChannel::SetChannelIsForDownload(bool aChannelIsForDownload)
  1416   mChannelIsForDownload = aChannelIsForDownload;
  1417   return NS_OK;
  1420 NS_IMETHODIMP
  1421 HttpBaseChannel::SetCacheKeysRedirectChain(nsTArray<nsCString> *cacheKeys)
  1423   mRedirectedCachekeys = cacheKeys;
  1424   return NS_OK;
  1427 NS_IMETHODIMP
  1428 HttpBaseChannel::GetLocalAddress(nsACString& addr)
  1430   if (mSelfAddr.raw.family == PR_AF_UNSPEC)
  1431     return NS_ERROR_NOT_AVAILABLE;
  1433   addr.SetCapacity(kIPv6CStrBufSize);
  1434   NetAddrToString(&mSelfAddr, addr.BeginWriting(), kIPv6CStrBufSize);
  1435   addr.SetLength(strlen(addr.BeginReading()));
  1437   return NS_OK;
  1440 NS_IMETHODIMP
  1441 HttpBaseChannel::TakeAllSecurityMessages(
  1442     nsCOMArray<nsISecurityConsoleMessage> &aMessages)
  1444   aMessages.Clear();
  1445   aMessages.SwapElements(mSecurityConsoleMessages);
  1446   return NS_OK;
  1449 /* Please use this method with care. This can cause the message
  1450  * queue to grow large and cause the channel to take up a lot
  1451  * of memory. Use only static string messages and do not add
  1452  * server side data to the queue, as that can be large.
  1453  * Add only a limited number of messages to the queue to keep
  1454  * the channel size down and do so only in rare erroneous situations.
  1455  * More information can be found here:
  1456  * https://bugzilla.mozilla.org/show_bug.cgi?id=846918
  1457  */
  1458 NS_IMETHODIMP
  1459 HttpBaseChannel::AddSecurityMessage(const nsAString &aMessageTag,
  1460     const nsAString &aMessageCategory)
  1462   nsresult rv;
  1463   nsCOMPtr<nsISecurityConsoleMessage> message =
  1464     do_CreateInstance(NS_SECURITY_CONSOLE_MESSAGE_CONTRACTID, &rv);
  1465   NS_ENSURE_SUCCESS(rv, rv);
  1466   message->SetTag(aMessageTag);
  1467   message->SetCategory(aMessageCategory);
  1468   mSecurityConsoleMessages.AppendElement(message);
  1469   return NS_OK;
  1472 NS_IMETHODIMP
  1473 HttpBaseChannel::GetLocalPort(int32_t* port)
  1475   NS_ENSURE_ARG_POINTER(port);
  1477   if (mSelfAddr.raw.family == PR_AF_INET) {
  1478     *port = (int32_t)ntohs(mSelfAddr.inet.port);
  1480   else if (mSelfAddr.raw.family == PR_AF_INET6) {
  1481     *port = (int32_t)ntohs(mSelfAddr.inet6.port);
  1483   else
  1484     return NS_ERROR_NOT_AVAILABLE;
  1486   return NS_OK;
  1489 NS_IMETHODIMP
  1490 HttpBaseChannel::GetRemoteAddress(nsACString& addr)
  1492   if (mPeerAddr.raw.family == PR_AF_UNSPEC)
  1493     return NS_ERROR_NOT_AVAILABLE;
  1495   addr.SetCapacity(kIPv6CStrBufSize);
  1496   NetAddrToString(&mPeerAddr, addr.BeginWriting(), kIPv6CStrBufSize);
  1497   addr.SetLength(strlen(addr.BeginReading()));
  1499   return NS_OK;
  1502 NS_IMETHODIMP
  1503 HttpBaseChannel::GetRemotePort(int32_t* port)
  1505   NS_ENSURE_ARG_POINTER(port);
  1507   if (mPeerAddr.raw.family == PR_AF_INET) {
  1508     *port = (int32_t)ntohs(mPeerAddr.inet.port);
  1510   else if (mPeerAddr.raw.family == PR_AF_INET6) {
  1511     *port = (int32_t)ntohs(mPeerAddr.inet6.port);
  1513   else
  1514     return NS_ERROR_NOT_AVAILABLE;
  1516   return NS_OK;
  1519 NS_IMETHODIMP
  1520 HttpBaseChannel::HTTPUpgrade(const nsACString &aProtocolName,
  1521                              nsIHttpUpgradeListener *aListener)
  1523     NS_ENSURE_ARG(!aProtocolName.IsEmpty());
  1524     NS_ENSURE_ARG_POINTER(aListener);
  1526     mUpgradeProtocol = aProtocolName;
  1527     mUpgradeProtocolCallback = aListener;
  1528     return NS_OK;
  1531 NS_IMETHODIMP
  1532 HttpBaseChannel::GetAllowSpdy(bool *aAllowSpdy)
  1534   NS_ENSURE_ARG_POINTER(aAllowSpdy);
  1536   *aAllowSpdy = mAllowSpdy;
  1537   return NS_OK;
  1540 NS_IMETHODIMP
  1541 HttpBaseChannel::SetAllowSpdy(bool aAllowSpdy)
  1543   mAllowSpdy = aAllowSpdy;
  1544   return NS_OK;
  1547 NS_IMETHODIMP
  1548 HttpBaseChannel::GetLoadAsBlocking(bool *aLoadAsBlocking)
  1550   NS_ENSURE_ARG_POINTER(aLoadAsBlocking);
  1551   *aLoadAsBlocking = mLoadAsBlocking;
  1552   return NS_OK;
  1555 NS_IMETHODIMP
  1556 HttpBaseChannel::SetLoadAsBlocking(bool aLoadAsBlocking)
  1558   mLoadAsBlocking = aLoadAsBlocking;
  1559   return NS_OK;
  1562 NS_IMETHODIMP
  1563 HttpBaseChannel::GetLoadUnblocked(bool *aLoadUnblocked)
  1565   NS_ENSURE_ARG_POINTER(aLoadUnblocked);
  1566   *aLoadUnblocked = mLoadUnblocked;
  1567   return NS_OK;
  1570 NS_IMETHODIMP
  1571 HttpBaseChannel::SetLoadUnblocked(bool aLoadUnblocked)
  1573   mLoadUnblocked = aLoadUnblocked;
  1574   return NS_OK;
  1577 NS_IMETHODIMP
  1578 HttpBaseChannel::GetApiRedirectToURI(nsIURI ** aResult)
  1580   NS_ENSURE_ARG_POINTER(aResult);
  1581   NS_IF_ADDREF(*aResult = mAPIRedirectToURI);
  1582   return NS_OK;
  1585 NS_IMETHODIMP
  1586 HttpBaseChannel::GetResponseTimeoutEnabled(bool *aEnable)
  1588   if (NS_WARN_IF(!aEnable)) {
  1589     return NS_ERROR_NULL_POINTER;
  1591   *aEnable = mResponseTimeoutEnabled;
  1592   return NS_OK;
  1595 NS_IMETHODIMP
  1596 HttpBaseChannel::SetResponseTimeoutEnabled(bool aEnable)
  1598   mResponseTimeoutEnabled = aEnable;
  1599   return NS_OK;
  1602 //-----------------------------------------------------------------------------
  1603 // HttpBaseChannel::nsISupportsPriority
  1604 //-----------------------------------------------------------------------------
  1606 NS_IMETHODIMP
  1607 HttpBaseChannel::GetPriority(int32_t *value)
  1609   *value = mPriority;
  1610   return NS_OK;
  1613 NS_IMETHODIMP
  1614 HttpBaseChannel::AdjustPriority(int32_t delta)
  1616   return SetPriority(mPriority + delta);
  1619 //-----------------------------------------------------------------------------
  1620 // HttpBaseChannel::nsIResumableChannel
  1621 //-----------------------------------------------------------------------------
  1623 NS_IMETHODIMP
  1624 HttpBaseChannel::GetEntityID(nsACString& aEntityID)
  1626   // Don't return an entity ID for Non-GET requests which require
  1627   // additional data
  1628   if (!mRequestHead.IsGet()) {
  1629     return NS_ERROR_NOT_RESUMABLE;
  1632   uint64_t size = UINT64_MAX;
  1633   nsAutoCString etag, lastmod;
  1634   if (mResponseHead) {
  1635     // Don't return an entity if the server sent the following header:
  1636     // Accept-Ranges: none
  1637     // Not sending the Accept-Ranges header means we can still try
  1638     // sending range requests.
  1639     const char* acceptRanges =
  1640         mResponseHead->PeekHeader(nsHttp::Accept_Ranges);
  1641     if (acceptRanges &&
  1642         !nsHttp::FindToken(acceptRanges, "bytes", HTTP_HEADER_VALUE_SEPS)) {
  1643       return NS_ERROR_NOT_RESUMABLE;
  1646     size = mResponseHead->TotalEntitySize();
  1647     const char* cLastMod = mResponseHead->PeekHeader(nsHttp::Last_Modified);
  1648     if (cLastMod)
  1649       lastmod = cLastMod;
  1650     const char* cEtag = mResponseHead->PeekHeader(nsHttp::ETag);
  1651     if (cEtag)
  1652       etag = cEtag;
  1654   nsCString entityID;
  1655   NS_EscapeURL(etag.BeginReading(), etag.Length(), esc_AlwaysCopy |
  1656                esc_FileBaseName | esc_Forced, entityID);
  1657   entityID.Append('/');
  1658   entityID.AppendInt(int64_t(size));
  1659   entityID.Append('/');
  1660   entityID.Append(lastmod);
  1661   // NOTE: Appending lastmod as the last part avoids having to escape it
  1663   aEntityID = entityID;
  1665   return NS_OK;
  1668 //-----------------------------------------------------------------------------
  1669 // nsHttpChannel::nsITraceableChannel
  1670 //-----------------------------------------------------------------------------
  1672 NS_IMETHODIMP
  1673 HttpBaseChannel::SetNewListener(nsIStreamListener *aListener, nsIStreamListener **_retval)
  1675   if (!mTracingEnabled)
  1676     return NS_ERROR_FAILURE;
  1678   NS_ENSURE_ARG_POINTER(aListener);
  1680   nsCOMPtr<nsIStreamListener> wrapper = new nsStreamListenerWrapper(mListener);
  1682   wrapper.forget(_retval);
  1683   mListener = aListener;
  1684   return NS_OK;
  1687 //-----------------------------------------------------------------------------
  1688 // HttpBaseChannel helpers
  1689 //-----------------------------------------------------------------------------
  1691 void
  1692 HttpBaseChannel::ReleaseListeners()
  1694   MOZ_ASSERT(NS_IsMainThread(), "Should only be called on the main thread.");
  1696   mListener = nullptr;
  1697   mListenerContext = nullptr;
  1698   mCallbacks = nullptr;
  1699   mProgressSink = nullptr;
  1702 void
  1703 HttpBaseChannel::DoNotifyListener()
  1705   // Make sure mIsPending is set to false. At this moment we are done from
  1706   // the point of view of our consumer and we have to report our self
  1707   // as not-pending.
  1708   if (mListener) {
  1709     mListener->OnStartRequest(this, mListenerContext);
  1710     mIsPending = false;
  1711     mListener->OnStopRequest(this, mListenerContext, mStatus);
  1712   } else {
  1713     mIsPending = false;
  1715   // We have to make sure to drop the references to listeners and callbacks
  1716   // no longer  needed
  1717   ReleaseListeners();
  1719   DoNotifyListenerCleanup();
  1722 void
  1723 HttpBaseChannel::AddCookiesToRequest()
  1725   if (mLoadFlags & LOAD_ANONYMOUS) {
  1726     return;
  1729   bool useCookieService =
  1730     (XRE_GetProcessType() == GeckoProcessType_Default);
  1731   nsXPIDLCString cookie;
  1732   if (useCookieService) {
  1733     nsICookieService *cs = gHttpHandler->GetCookieService();
  1734     if (cs) {
  1735       cs->GetCookieStringFromHttp(mURI,
  1736                                   nullptr,
  1737                                   this, getter_Copies(cookie));
  1740     if (cookie.IsEmpty()) {
  1741       cookie = mUserSetCookieHeader;
  1743     else if (!mUserSetCookieHeader.IsEmpty()) {
  1744       cookie.Append(NS_LITERAL_CSTRING("; ") + mUserSetCookieHeader);
  1747   else {
  1748     cookie = mUserSetCookieHeader;
  1751   // If we are in the child process, we want the parent seeing any
  1752   // cookie headers that might have been set by SetRequestHeader()
  1753   SetRequestHeader(nsDependentCString(nsHttp::Cookie), cookie, false);
  1756 static PLDHashOperator
  1757 CopyProperties(const nsAString& aKey, nsIVariant *aData, void *aClosure)
  1759   nsIWritablePropertyBag* bag = static_cast<nsIWritablePropertyBag*>
  1760                                            (aClosure);
  1761   bag->SetProperty(aKey, aData);
  1762   return PL_DHASH_NEXT;
  1765 bool
  1766 HttpBaseChannel::ShouldRewriteRedirectToGET(uint32_t httpStatus,
  1767                                             nsHttpRequestHead::ParsedMethodType method)
  1769   // for 301 and 302, only rewrite POST
  1770   if (httpStatus == 301 || httpStatus == 302)
  1771     return method == nsHttpRequestHead::kMethod_Post;
  1773   // rewrite for 303 unless it was HEAD
  1774   if (httpStatus == 303)
  1775     return method != nsHttpRequestHead::kMethod_Head;
  1777   // otherwise, such as for 307, do not rewrite
  1778   return false;
  1781 nsresult
  1782 HttpBaseChannel::SetupReplacementChannel(nsIURI       *newURI,
  1783                                          nsIChannel   *newChannel,
  1784                                          bool          preserveMethod)
  1786   LOG(("HttpBaseChannel::SetupReplacementChannel "
  1787      "[this=%p newChannel=%p preserveMethod=%d]",
  1788      this, newChannel, preserveMethod));
  1789   uint32_t newLoadFlags = mLoadFlags | LOAD_REPLACE;
  1790   // if the original channel was using SSL and this channel is not using
  1791   // SSL, then no need to inhibit persistent caching.  however, if the
  1792   // original channel was not using SSL and has INHIBIT_PERSISTENT_CACHING
  1793   // set, then allow the flag to apply to the redirected channel as well.
  1794   // since we force set INHIBIT_PERSISTENT_CACHING on all HTTPS channels,
  1795   // we only need to check if the original channel was using SSL.
  1796   bool usingSSL = false;
  1797   nsresult rv = mURI->SchemeIs("https", &usingSSL);
  1798   if (NS_SUCCEEDED(rv) && usingSSL)
  1799     newLoadFlags &= ~INHIBIT_PERSISTENT_CACHING;
  1801   // Do not pass along LOAD_CHECK_OFFLINE_CACHE
  1802   newLoadFlags &= ~nsICachingChannel::LOAD_CHECK_OFFLINE_CACHE;
  1804   newChannel->SetLoadGroup(mLoadGroup);
  1805   newChannel->SetNotificationCallbacks(mCallbacks);
  1806   newChannel->SetLoadFlags(newLoadFlags);
  1808   // If our owner is a null principal it will have been set as a security
  1809   // measure, so we want to propagate it to the new channel.
  1810   nsCOMPtr<nsIPrincipal> ownerPrincipal = do_QueryInterface(mOwner);
  1811   if (ownerPrincipal && ownerPrincipal->GetIsNullPrincipal()) {
  1812     newChannel->SetOwner(mOwner);
  1815   // Try to preserve the privacy bit if it has been overridden
  1816   if (mPrivateBrowsingOverriden) {
  1817     nsCOMPtr<nsIPrivateBrowsingChannel> newPBChannel =
  1818       do_QueryInterface(newChannel);
  1819     if (newPBChannel) {
  1820       newPBChannel->SetPrivate(mPrivateBrowsing);
  1824   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(newChannel);
  1825   if (!httpChannel)
  1826     return NS_OK; // no other options to set
  1828   if (preserveMethod) {
  1829     nsCOMPtr<nsIUploadChannel> uploadChannel =
  1830       do_QueryInterface(httpChannel);
  1831     nsCOMPtr<nsIUploadChannel2> uploadChannel2 =
  1832       do_QueryInterface(httpChannel);
  1833     if (mUploadStream && (uploadChannel2 || uploadChannel)) {
  1834       // rewind upload stream
  1835       nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mUploadStream);
  1836       if (seekable)
  1837         seekable->Seek(nsISeekableStream::NS_SEEK_SET, 0);
  1839       // replicate original call to SetUploadStream...
  1840       if (uploadChannel2) {
  1841         const char *ctype = mRequestHead.PeekHeader(nsHttp::Content_Type);
  1842         if (!ctype)
  1843           ctype = "";
  1844         const char *clen  = mRequestHead.PeekHeader(nsHttp::Content_Length);
  1845         int64_t len = clen ? nsCRT::atoll(clen) : -1;
  1846         uploadChannel2->ExplicitSetUploadStream(
  1847                                   mUploadStream, nsDependentCString(ctype), len,
  1848                                   mRequestHead.Method(),
  1849                                   mUploadStreamHasHeaders);
  1850       } else {
  1851         if (mUploadStreamHasHeaders) {
  1852           uploadChannel->SetUploadStream(mUploadStream, EmptyCString(),
  1853                            -1);
  1854         } else {
  1855           const char *ctype =
  1856             mRequestHead.PeekHeader(nsHttp::Content_Type);
  1857           const char *clen =
  1858             mRequestHead.PeekHeader(nsHttp::Content_Length);
  1859           if (!ctype) {
  1860             ctype = "application/octet-stream";
  1862           if (clen) {
  1863             uploadChannel->SetUploadStream(mUploadStream,
  1864                                            nsDependentCString(ctype),
  1865                                            nsCRT::atoll(clen));
  1870     // since preserveMethod is true, we need to ensure that the appropriate
  1871     // request method gets set on the channel, regardless of whether or not
  1872     // we set the upload stream above. This means SetRequestMethod() will
  1873     // be called twice if ExplicitSetUploadStream() gets called above.
  1875     httpChannel->SetRequestMethod(mRequestHead.Method());
  1877   // convey the referrer if one was used for this channel to the next one
  1878   if (mReferrer)
  1879     httpChannel->SetReferrer(mReferrer);
  1880   // convey the mAllowPipelining flag
  1881   httpChannel->SetAllowPipelining(mAllowPipelining);
  1882   // convey the new redirection limit
  1883   httpChannel->SetRedirectionLimit(mRedirectionLimit - 1);
  1885   // convey the Accept header value
  1887     nsAutoCString oldAcceptValue;
  1888     nsresult hasHeader = mRequestHead.GetHeader(nsHttp::Accept, oldAcceptValue);
  1889     if (NS_SUCCEEDED(hasHeader)) {
  1890       httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
  1891                                     oldAcceptValue,
  1892                                     false);
  1896   nsCOMPtr<nsIHttpChannelInternal> httpInternal = do_QueryInterface(newChannel);
  1897   if (httpInternal) {
  1898     // convey the mForceAllowThirdPartyCookie flag
  1899     httpInternal->SetForceAllowThirdPartyCookie(mForceAllowThirdPartyCookie);
  1900     // convey the spdy flag
  1901     httpInternal->SetAllowSpdy(mAllowSpdy);
  1903     // update the DocumentURI indicator since we are being redirected.
  1904     // if this was a top-level document channel, then the new channel
  1905     // should have its mDocumentURI point to newURI; otherwise, we
  1906     // just need to pass along our mDocumentURI to the new channel.
  1907     if (newURI && (mURI == mDocumentURI))
  1908       httpInternal->SetDocumentURI(newURI);
  1909     else
  1910       httpInternal->SetDocumentURI(mDocumentURI);
  1912     // if there is a chain of keys for redirect-responses we transfer it to
  1913     // the new channel (see bug #561276)
  1914     if (mRedirectedCachekeys) {
  1915         LOG(("HttpBaseChannel::SetupReplacementChannel "
  1916              "[this=%p] transferring chain of redirect cache-keys", this));
  1917         httpInternal->SetCacheKeysRedirectChain(mRedirectedCachekeys.forget());
  1921   // transfer application cache information
  1922   nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel =
  1923     do_QueryInterface(newChannel);
  1924   if (appCacheChannel) {
  1925     appCacheChannel->SetApplicationCache(mApplicationCache);
  1926     appCacheChannel->SetInheritApplicationCache(mInheritApplicationCache);
  1927     // We purposely avoid transfering mChooseApplicationCache.
  1930   // transfer any properties
  1931   nsCOMPtr<nsIWritablePropertyBag> bag(do_QueryInterface(newChannel));
  1932   if (bag)
  1933     mPropertyHash.EnumerateRead(CopyProperties, bag.get());
  1935   // Transfer the timing data (if we are dealing with an nsITimedChannel).
  1936   nsCOMPtr<nsITimedChannel> newTimedChannel(do_QueryInterface(newChannel));
  1937   nsCOMPtr<nsITimedChannel> oldTimedChannel(
  1938       do_QueryInterface(static_cast<nsIHttpChannel*>(this)));
  1939   if (oldTimedChannel && newTimedChannel) {
  1940     newTimedChannel->SetTimingEnabled(mTimingEnabled);
  1941     newTimedChannel->SetRedirectCount(mRedirectCount + 1);
  1943     // If the RedirectStart is null, we will use the AsyncOpen value of the
  1944     // previous channel (this is the first redirect in the redirects chain).
  1945     if (mRedirectStartTimeStamp.IsNull()) {
  1946       TimeStamp asyncOpen;
  1947       oldTimedChannel->GetAsyncOpen(&asyncOpen);
  1948       newTimedChannel->SetRedirectStart(asyncOpen);
  1950     else {
  1951       newTimedChannel->SetRedirectStart(mRedirectStartTimeStamp);
  1954     // The RedirectEnd timestamp is equal to the previous channel response end.
  1955     TimeStamp prevResponseEnd;
  1956     oldTimedChannel->GetResponseEnd(&prevResponseEnd);
  1957     newTimedChannel->SetRedirectEnd(prevResponseEnd);
  1959     // Check whether or not this was a cross-domain redirect.
  1960     newTimedChannel->SetAllRedirectsSameOrigin(
  1961         mAllRedirectsSameOrigin && SameOriginWithOriginalUri(newURI));
  1964   return NS_OK;
  1967 // Redirect Tracking
  1968 bool
  1969 HttpBaseChannel::SameOriginWithOriginalUri(nsIURI *aURI)
  1971   nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
  1972   nsresult rv = ssm->CheckSameOriginURI(aURI, mOriginalURI, false);
  1973   return (NS_SUCCEEDED(rv));
  1978 //-----------------------------------------------------------------------------
  1979 // HttpBaseChannel::nsITimedChannel
  1980 //-----------------------------------------------------------------------------
  1982 NS_IMETHODIMP
  1983 HttpBaseChannel::SetTimingEnabled(bool enabled) {
  1984   mTimingEnabled = enabled;
  1985   return NS_OK;
  1988 NS_IMETHODIMP
  1989 HttpBaseChannel::GetTimingEnabled(bool* _retval) {
  1990   *_retval = mTimingEnabled;
  1991   return NS_OK;
  1994 NS_IMETHODIMP
  1995 HttpBaseChannel::GetChannelCreation(TimeStamp* _retval) {
  1996   *_retval = mChannelCreationTimestamp;
  1997   return NS_OK;
  2000 NS_IMETHODIMP
  2001 HttpBaseChannel::GetAsyncOpen(TimeStamp* _retval) {
  2002   *_retval = mAsyncOpenTime;
  2003   return NS_OK;
  2006 /**
  2007  * @return the number of redirects. There is no check for cross-domain
  2008  * redirects. This check must be done by the consumers.
  2009  */
  2010 NS_IMETHODIMP
  2011 HttpBaseChannel::GetRedirectCount(uint16_t *aRedirectCount)
  2013   *aRedirectCount = mRedirectCount;
  2014   return NS_OK;
  2017 NS_IMETHODIMP
  2018 HttpBaseChannel::SetRedirectCount(uint16_t aRedirectCount)
  2020   mRedirectCount = aRedirectCount;
  2021   return NS_OK;
  2024 NS_IMETHODIMP
  2025 HttpBaseChannel::GetRedirectStart(TimeStamp* _retval)
  2027   *_retval = mRedirectStartTimeStamp;
  2028   return NS_OK;
  2031 NS_IMETHODIMP
  2032 HttpBaseChannel::SetRedirectStart(TimeStamp aRedirectStart)
  2034   mRedirectStartTimeStamp = aRedirectStart;
  2035   return NS_OK;
  2038 NS_IMETHODIMP
  2039 HttpBaseChannel::GetRedirectEnd(TimeStamp* _retval)
  2041   *_retval = mRedirectEndTimeStamp;
  2042   return NS_OK;
  2045 NS_IMETHODIMP
  2046 HttpBaseChannel::SetRedirectEnd(TimeStamp aRedirectEnd)
  2048   mRedirectEndTimeStamp = aRedirectEnd;
  2049   return NS_OK;
  2052 NS_IMETHODIMP
  2053 HttpBaseChannel::GetAllRedirectsSameOrigin(bool *aAllRedirectsSameOrigin)
  2055   *aAllRedirectsSameOrigin = mAllRedirectsSameOrigin;
  2056   return NS_OK;
  2059 NS_IMETHODIMP
  2060 HttpBaseChannel::SetAllRedirectsSameOrigin(bool aAllRedirectsSameOrigin)
  2062   mAllRedirectsSameOrigin = aAllRedirectsSameOrigin;
  2063   return NS_OK;
  2066 NS_IMETHODIMP
  2067 HttpBaseChannel::GetDomainLookupStart(TimeStamp* _retval) {
  2068   *_retval = mTransactionTimings.domainLookupStart;
  2069   return NS_OK;
  2072 NS_IMETHODIMP
  2073 HttpBaseChannel::GetDomainLookupEnd(TimeStamp* _retval) {
  2074   *_retval = mTransactionTimings.domainLookupEnd;
  2075   return NS_OK;
  2078 NS_IMETHODIMP
  2079 HttpBaseChannel::GetConnectStart(TimeStamp* _retval) {
  2080   *_retval = mTransactionTimings.connectStart;
  2081   return NS_OK;
  2084 NS_IMETHODIMP
  2085 HttpBaseChannel::GetConnectEnd(TimeStamp* _retval) {
  2086   *_retval = mTransactionTimings.connectEnd;
  2087   return NS_OK;
  2090 NS_IMETHODIMP
  2091 HttpBaseChannel::GetRequestStart(TimeStamp* _retval) {
  2092   *_retval = mTransactionTimings.requestStart;
  2093   return NS_OK;
  2096 NS_IMETHODIMP
  2097 HttpBaseChannel::GetResponseStart(TimeStamp* _retval) {
  2098   *_retval = mTransactionTimings.responseStart;
  2099   return NS_OK;
  2102 NS_IMETHODIMP
  2103 HttpBaseChannel::GetResponseEnd(TimeStamp* _retval) {
  2104   *_retval = mTransactionTimings.responseEnd;
  2105   return NS_OK;
  2108 NS_IMETHODIMP
  2109 HttpBaseChannel::GetCacheReadStart(TimeStamp* _retval) {
  2110   *_retval = mCacheReadStart;
  2111   return NS_OK;
  2114 NS_IMETHODIMP
  2115 HttpBaseChannel::GetCacheReadEnd(TimeStamp* _retval) {
  2116   *_retval = mCacheReadEnd;
  2117   return NS_OK;
  2120 NS_IMETHODIMP
  2121 HttpBaseChannel::GetInitiatorType(nsAString & aInitiatorType)
  2123   aInitiatorType = mInitiatorType;
  2124   return NS_OK;
  2127 NS_IMETHODIMP
  2128 HttpBaseChannel::SetInitiatorType(const nsAString & aInitiatorType)
  2130   mInitiatorType = aInitiatorType;
  2131   return NS_OK;
  2134 #define IMPL_TIMING_ATTR(name)                                 \
  2135 NS_IMETHODIMP                                                  \
  2136 HttpBaseChannel::Get##name##Time(PRTime* _retval) {            \
  2137     TimeStamp stamp;                                           \
  2138     Get##name(&stamp);                                         \
  2139     if (stamp.IsNull()) {                                      \
  2140         *_retval = 0;                                          \
  2141         return NS_OK;                                          \
  2142     }                                                          \
  2143     *_retval = mChannelCreationTime +                          \
  2144         (PRTime) ((stamp - mChannelCreationTimestamp).ToSeconds() * 1e6); \
  2145     return NS_OK;                                              \
  2148 IMPL_TIMING_ATTR(ChannelCreation)
  2149 IMPL_TIMING_ATTR(AsyncOpen)
  2150 IMPL_TIMING_ATTR(DomainLookupStart)
  2151 IMPL_TIMING_ATTR(DomainLookupEnd)
  2152 IMPL_TIMING_ATTR(ConnectStart)
  2153 IMPL_TIMING_ATTR(ConnectEnd)
  2154 IMPL_TIMING_ATTR(RequestStart)
  2155 IMPL_TIMING_ATTR(ResponseStart)
  2156 IMPL_TIMING_ATTR(ResponseEnd)
  2157 IMPL_TIMING_ATTR(CacheReadStart)
  2158 IMPL_TIMING_ATTR(CacheReadEnd)
  2159 IMPL_TIMING_ATTR(RedirectStart)
  2160 IMPL_TIMING_ATTR(RedirectEnd)
  2162 #undef IMPL_TIMING_ATTR
  2165 //------------------------------------------------------------------------------
  2167 }  // namespace net
  2168 }  // namespace mozilla

mercurial