LCOV - code coverage report
Current view: directory - netwerk/protocol/http - HttpBaseChannel.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 775 537 69.3 %
Date: 2012-06-02 Functions: 103 76 73.8 %

       1                 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* vim: set sw=2 ts=8 et tw=80 : */
       3                 : 
       4                 : /* ***** BEGIN LICENSE BLOCK *****
       5                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       6                 :  *
       7                 :  * The contents of this file are subject to the Mozilla Public License Version
       8                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       9                 :  * the License. You may obtain a copy of the License at
      10                 :  * http://www.mozilla.org/MPL/
      11                 :  *
      12                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      13                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      14                 :  * for the specific language governing rights and limitations under the
      15                 :  * License.
      16                 :  *
      17                 :  * The Original Code is mozilla.org code.
      18                 :  *
      19                 :  * The Initial Developer of the Original Code is
      20                 :  *  The Mozilla Foundation.
      21                 :  * Portions created by the Initial Developer are Copyright (C) 2010
      22                 :  * the Initial Developer. All Rights Reserved.
      23                 :  *
      24                 :  * Contributor(s):
      25                 :  *   Daniel Witte <dwitte@mozilla.com>
      26                 :  *   Frederic Plourde <bugzillaFred@gmail.com>
      27                 :  *   Jason Duell <jduell.mcbugs@gmail.com>
      28                 :  *
      29                 :  * Alternatively, the contents of this file may be used under the terms of
      30                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      31                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      32                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      33                 :  * of those above. If you wish to allow use of your version of this file only
      34                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      35                 :  * use your version of this file under the terms of the MPL, indicate your
      36                 :  * decision by deleting the provisions above and replace them with the notice
      37                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      38                 :  * the provisions above, a recipient may use your version of this file under
      39                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      40                 :  *
      41                 :  * ***** END LICENSE BLOCK ***** */
      42                 : 
      43                 : #include "mozilla/net/HttpBaseChannel.h"
      44                 : 
      45                 : #include "nsHttpHandler.h"
      46                 : #include "nsMimeTypes.h"
      47                 : #include "nsNetUtil.h"
      48                 : 
      49                 : #include "nsICachingChannel.h"
      50                 : #include "nsISeekableStream.h"
      51                 : #include "nsITimedChannel.h"
      52                 : #include "nsIEncodedChannel.h"
      53                 : #include "nsIResumableChannel.h"
      54                 : #include "nsIApplicationCacheChannel.h"
      55                 : #include "nsEscape.h"
      56                 : 
      57                 : #include "prnetdb.h"
      58                 : 
      59                 : namespace mozilla {
      60                 : namespace net {
      61                 : 
      62            3514 : HttpBaseChannel::HttpBaseChannel()
      63                 :   : mStartPos(LL_MAXUINT)
      64                 :   , mStatus(NS_OK)
      65                 :   , mLoadFlags(LOAD_NORMAL)
      66                 :   , mPriority(PRIORITY_NORMAL)
      67                 :   , mCaps(0)
      68            3514 :   , mRedirectionLimit(gHttpHandler->RedirectionLimit())
      69                 :   , mApplyConversion(true)
      70                 :   , mCanceled(false)
      71                 :   , mIsPending(false)
      72                 :   , mWasOpened(false)
      73                 :   , mResponseHeadersModified(false)
      74                 :   , mAllowPipelining(true)
      75                 :   , mForceAllowThirdPartyCookie(false)
      76                 :   , mUploadStreamHasHeaders(false)
      77                 :   , mInheritApplicationCache(true)
      78                 :   , mChooseApplicationCache(false)
      79                 :   , mLoadedFromApplicationCache(false)
      80                 :   , mChannelIsForDownload(false)
      81                 :   , mTracingEnabled(true)
      82                 :   , mTimingEnabled(false)
      83                 :   , mAllowSpdy(true)
      84                 :   , mSuspendCount(0)
      85            7028 :   , mRedirectedCachekeys(nsnull)
      86                 : {
      87            3514 :   LOG(("Creating HttpBaseChannel @%x\n", this));
      88                 : 
      89                 :   // grab a reference to the handler to ensure that it doesn't go away.
      90            3514 :   NS_ADDREF(gHttpHandler);
      91                 : 
      92                 :   // Subfields of unions cannot be targeted in an initializer list
      93            3514 :   mSelfAddr.raw.family = PR_AF_UNSPEC;
      94            3514 :   mPeerAddr.raw.family = PR_AF_UNSPEC;
      95            3514 : }
      96                 : 
      97            6480 : HttpBaseChannel::~HttpBaseChannel()
      98                 : {
      99            3240 :   LOG(("Destroying HttpBaseChannel @%x\n", this));
     100                 : 
     101                 :   // Make sure we don't leak
     102            3240 :   CleanRedirectCacheChainIfNecessary();
     103                 : 
     104            3240 :   gHttpHandler->Release();
     105            6480 : }
     106                 : 
     107                 : nsresult
     108            3514 : HttpBaseChannel::Init(nsIURI *aURI,
     109                 :                       PRUint8 aCaps,
     110                 :                       nsProxyInfo *aProxyInfo)
     111                 : {
     112            3514 :   LOG(("HttpBaseChannel::Init [this=%p]\n", this));
     113                 : 
     114            3514 :   NS_PRECONDITION(aURI, "null uri");
     115                 : 
     116            3514 :   nsresult rv = nsHashPropertyBag::Init();
     117            3514 :   if (NS_FAILED(rv)) return rv;
     118                 : 
     119            3514 :   mURI = aURI;
     120            3514 :   mOriginalURI = aURI;
     121            3514 :   mDocumentURI = nsnull;
     122            3514 :   mCaps = aCaps;
     123                 : 
     124                 :   // Construct connection info object
     125            7028 :   nsCAutoString host;
     126            3514 :   PRInt32 port = -1;
     127            3514 :   bool usingSSL = false;
     128                 : 
     129            3514 :   rv = mURI->SchemeIs("https", &usingSSL);
     130            3514 :   if (NS_FAILED(rv)) return rv;
     131                 : 
     132            3514 :   rv = mURI->GetAsciiHost(host);
     133            3514 :   if (NS_FAILED(rv)) return rv;
     134                 : 
     135                 :   // Reject the URL if it doesn't specify a host
     136            3514 :   if (host.IsEmpty())
     137               0 :     return NS_ERROR_MALFORMED_URI;
     138                 : 
     139            3514 :   rv = mURI->GetPort(&port);
     140            3514 :   if (NS_FAILED(rv)) return rv;
     141                 : 
     142            3514 :   LOG(("host=%s port=%d\n", host.get(), port));
     143                 : 
     144            3514 :   rv = mURI->GetAsciiSpec(mSpec);
     145            3514 :   if (NS_FAILED(rv)) return rv;
     146            3514 :   LOG(("uri=%s\n", mSpec.get()));
     147                 : 
     148                 :   mConnectionInfo = new nsHttpConnectionInfo(host, port,
     149            3514 :                                              aProxyInfo, usingSSL);
     150            3514 :   if (!mConnectionInfo)
     151               0 :     return NS_ERROR_OUT_OF_MEMORY;
     152                 : 
     153                 :   // Set default request method
     154            3514 :   mRequestHead.SetMethod(nsHttp::Get);
     155                 : 
     156                 :   // Set request headers
     157            7028 :   nsCAutoString hostLine;
     158            3514 :   rv = nsHttpHandler::GenerateHostPort(host, port, hostLine);
     159            3514 :   if (NS_FAILED(rv)) return rv;
     160                 : 
     161            3514 :   rv = mRequestHead.SetHeader(nsHttp::Host, hostLine);
     162            3514 :   if (NS_FAILED(rv)) return rv;
     163                 : 
     164                 :   rv = gHttpHandler->
     165            3514 :       AddStandardRequestHeaders(&mRequestHead.Headers(), aCaps,
     166            3514 :                                 !mConnectionInfo->UsingSSL() &&
     167            7028 :                                 mConnectionInfo->UsingHttpProxy());
     168                 : 
     169            3514 :   return rv;
     170                 : }
     171                 : 
     172                 : //-----------------------------------------------------------------------------
     173                 : // HttpBaseChannel::nsISupports
     174                 : //-----------------------------------------------------------------------------
     175                 : 
     176          274081 : NS_IMPL_ISUPPORTS_INHERITED9(HttpBaseChannel,
     177                 :                              nsHashPropertyBag, 
     178                 :                              nsIRequest,
     179                 :                              nsIChannel,
     180                 :                              nsIEncodedChannel,
     181                 :                              nsIHttpChannel,
     182                 :                              nsIHttpChannelInternal,
     183                 :                              nsIUploadChannel,
     184                 :                              nsIUploadChannel2,
     185                 :                              nsISupportsPriority,
     186                 :                              nsITraceableChannel)
     187                 : 
     188                 : //-----------------------------------------------------------------------------
     189                 : // HttpBaseChannel::nsIRequest
     190                 : //-----------------------------------------------------------------------------
     191                 : 
     192                 : NS_IMETHODIMP
     193               8 : HttpBaseChannel::GetName(nsACString& aName)
     194                 : {
     195               8 :   aName = mSpec;
     196               8 :   return NS_OK;
     197                 : }
     198                 : 
     199                 : NS_IMETHODIMP
     200             374 : HttpBaseChannel::IsPending(bool *aIsPending)
     201                 : {
     202             374 :   NS_ENSURE_ARG_POINTER(aIsPending);
     203             374 :   *aIsPending = mIsPending;
     204             374 :   return NS_OK;
     205                 : }
     206                 : 
     207                 : NS_IMETHODIMP
     208            1714 : HttpBaseChannel::GetStatus(nsresult *aStatus)
     209                 : {
     210            1714 :   NS_ENSURE_ARG_POINTER(aStatus);
     211            1714 :   *aStatus = mStatus;
     212            1714 :   return NS_OK;
     213                 : }
     214                 : 
     215                 : NS_IMETHODIMP
     216             784 : HttpBaseChannel::GetLoadGroup(nsILoadGroup **aLoadGroup)
     217                 : {
     218             784 :   NS_ENSURE_ARG_POINTER(aLoadGroup);
     219             784 :   *aLoadGroup = mLoadGroup;
     220             784 :   NS_IF_ADDREF(*aLoadGroup);
     221             784 :   return NS_OK;
     222                 : }
     223                 : 
     224                 : NS_IMETHODIMP
     225             167 : HttpBaseChannel::SetLoadGroup(nsILoadGroup *aLoadGroup)
     226                 : {
     227             167 :   mLoadGroup = aLoadGroup;
     228             167 :   mProgressSink = nsnull;
     229             167 :   return NS_OK;
     230                 : }
     231                 : 
     232                 : NS_IMETHODIMP
     233           12499 : HttpBaseChannel::GetLoadFlags(nsLoadFlags *aLoadFlags)
     234                 : {
     235           12499 :   NS_ENSURE_ARG_POINTER(aLoadFlags);
     236           12499 :   *aLoadFlags = mLoadFlags;
     237           12499 :   return NS_OK;
     238                 : }
     239                 : 
     240                 : NS_IMETHODIMP
     241            4439 : HttpBaseChannel::SetLoadFlags(nsLoadFlags aLoadFlags)
     242                 : {
     243            4439 :   mLoadFlags = aLoadFlags;
     244            4439 :   return NS_OK;
     245                 : }
     246                 : 
     247                 : //-----------------------------------------------------------------------------
     248                 : // HttpBaseChannel::nsIChannel
     249                 : //-----------------------------------------------------------------------------
     250                 : 
     251                 : NS_IMETHODIMP
     252            1333 : HttpBaseChannel::GetOriginalURI(nsIURI **aOriginalURI)
     253                 : {
     254            1333 :   NS_ENSURE_ARG_POINTER(aOriginalURI);
     255            1333 :   *aOriginalURI = mOriginalURI;
     256            1333 :   NS_ADDREF(*aOriginalURI);
     257            1333 :   return NS_OK;
     258                 : }
     259                 : 
     260                 : NS_IMETHODIMP
     261             143 : HttpBaseChannel::SetOriginalURI(nsIURI *aOriginalURI)
     262                 : {
     263             143 :   ENSURE_CALLED_BEFORE_ASYNC_OPEN();
     264                 : 
     265             143 :   NS_ENSURE_ARG_POINTER(aOriginalURI);
     266             143 :   mOriginalURI = aOriginalURI;
     267             143 :   return NS_OK;
     268                 : }
     269                 : 
     270                 : NS_IMETHODIMP
     271           11346 : HttpBaseChannel::GetURI(nsIURI **aURI)
     272                 : {
     273           11346 :   NS_ENSURE_ARG_POINTER(aURI);
     274           11346 :   *aURI = mURI;
     275           11346 :   NS_ADDREF(*aURI);
     276           11346 :   return NS_OK;
     277                 : }
     278                 : 
     279                 : NS_IMETHODIMP
     280             628 : HttpBaseChannel::GetOwner(nsISupports **aOwner)
     281                 : {
     282             628 :   NS_ENSURE_ARG_POINTER(aOwner);
     283             628 :   *aOwner = mOwner;
     284             628 :   NS_IF_ADDREF(*aOwner);
     285             628 :   return NS_OK;
     286                 : }
     287                 : 
     288                 : NS_IMETHODIMP
     289             583 : HttpBaseChannel::SetOwner(nsISupports *aOwner)
     290                 : {
     291             583 :   mOwner = aOwner;
     292             583 :   return NS_OK;
     293                 : }
     294                 : 
     295                 : NS_IMETHODIMP
     296             955 : HttpBaseChannel::GetNotificationCallbacks(nsIInterfaceRequestor **aCallbacks)
     297                 : {
     298             955 :   *aCallbacks = mCallbacks;
     299             955 :   NS_IF_ADDREF(*aCallbacks);
     300             955 :   return NS_OK;
     301                 : }
     302                 : 
     303                 : NS_IMETHODIMP
     304            3926 : HttpBaseChannel::SetNotificationCallbacks(nsIInterfaceRequestor *aCallbacks)
     305                 : {
     306            3926 :   mCallbacks = aCallbacks;
     307            3926 :   mProgressSink = nsnull;
     308            3926 :   return NS_OK;
     309                 : }
     310                 : 
     311                 : NS_IMETHODIMP
     312            1502 : HttpBaseChannel::GetContentType(nsACString& aContentType)
     313                 : {
     314            1502 :   if (!mResponseHead) {
     315               0 :     aContentType.Truncate();
     316               0 :     return NS_ERROR_NOT_AVAILABLE;
     317                 :   }
     318                 : 
     319            1502 :   if (!mResponseHead->ContentType().IsEmpty()) {
     320            1502 :     aContentType = mResponseHead->ContentType();
     321            1502 :     return NS_OK;
     322                 :   }
     323                 : 
     324               0 :   aContentType.AssignLiteral(UNKNOWN_CONTENT_TYPE);
     325               0 :   return NS_OK;
     326                 : }
     327                 : 
     328                 : NS_IMETHODIMP
     329            2014 : HttpBaseChannel::SetContentType(const nsACString& aContentType)
     330                 : {
     331            2014 :   if (mListener || mWasOpened) {
     332            1419 :     if (!mResponseHead)
     333              69 :       return NS_ERROR_NOT_AVAILABLE;
     334                 : 
     335            2700 :     nsCAutoString contentTypeBuf, charsetBuf;
     336                 :     bool hadCharset;
     337            1350 :     net_ParseContentType(aContentType, contentTypeBuf, charsetBuf, &hadCharset);
     338                 : 
     339            1350 :     mResponseHead->SetContentType(contentTypeBuf);
     340                 : 
     341                 :     // take care not to stomp on an existing charset
     342            1350 :     if (hadCharset)
     343               0 :       mResponseHead->SetContentCharset(charsetBuf);
     344                 : 
     345                 :   } else {
     346                 :     // We are being given a content-type hint.
     347                 :     bool dummy;
     348                 :     net_ParseContentType(aContentType, mContentTypeHint, mContentCharsetHint,
     349             595 :                          &dummy);
     350                 :   }
     351                 :   
     352            1945 :   return NS_OK;
     353                 : }
     354                 : 
     355                 : NS_IMETHODIMP
     356            1051 : HttpBaseChannel::GetContentCharset(nsACString& aContentCharset)
     357                 : {
     358            1051 :   if (!mResponseHead)
     359              71 :     return NS_ERROR_NOT_AVAILABLE;
     360                 : 
     361             980 :   aContentCharset = mResponseHead->ContentCharset();
     362             980 :   return NS_OK;
     363                 : }
     364                 : 
     365                 : NS_IMETHODIMP
     366               1 : HttpBaseChannel::SetContentCharset(const nsACString& aContentCharset)
     367                 : {
     368               1 :   if (mListener) {
     369               1 :     if (!mResponseHead)
     370               0 :       return NS_ERROR_NOT_AVAILABLE;
     371                 : 
     372               1 :     mResponseHead->SetContentCharset(aContentCharset);
     373                 :   } else {
     374                 :     // Charset hint
     375               0 :     mContentCharsetHint = aContentCharset;
     376                 :   }
     377               1 :   return NS_OK;
     378                 : }
     379                 : 
     380                 : NS_IMETHODIMP
     381              17 : HttpBaseChannel::GetContentDisposition(PRUint32 *aContentDisposition)
     382                 : {
     383                 :   nsresult rv;
     384              34 :   nsCString header;
     385                 : 
     386              17 :   rv = GetContentDispositionHeader(header);
     387              17 :   if (NS_FAILED(rv))
     388               0 :     return rv;
     389                 : 
     390              17 :   *aContentDisposition = NS_GetContentDispositionFromHeader(header, this);
     391                 : 
     392              17 :   return NS_OK;
     393                 : }
     394                 : 
     395                 : NS_IMETHODIMP
     396              11 : HttpBaseChannel::GetContentDispositionFilename(nsAString& aContentDispositionFilename)
     397                 : {
     398              11 :   aContentDispositionFilename.Truncate();
     399                 : 
     400                 :   nsresult rv;
     401              22 :   nsCString header;
     402                 : 
     403              11 :   rv = GetContentDispositionHeader(header);
     404              11 :   if (NS_FAILED(rv))
     405               0 :     return rv;
     406                 : 
     407                 :   return NS_GetFilenameFromDisposition(aContentDispositionFilename,
     408              11 :                                        header, mURI);
     409                 : }
     410                 : 
     411                 : NS_IMETHODIMP
     412              37 : HttpBaseChannel::GetContentDispositionHeader(nsACString& aContentDispositionHeader)
     413                 : {
     414              37 :   if (!mResponseHead)
     415               0 :     return NS_ERROR_NOT_AVAILABLE;
     416                 : 
     417                 :   nsresult rv = mResponseHead->GetHeader(nsHttp::Content_Disposition,
     418              37 :                                          aContentDispositionHeader);
     419              37 :   if (NS_FAILED(rv) || aContentDispositionHeader.IsEmpty())
     420               4 :     return NS_ERROR_NOT_AVAILABLE;
     421                 : 
     422              33 :   return NS_OK;
     423                 : }
     424                 : 
     425                 : NS_IMETHODIMP
     426             477 : HttpBaseChannel::GetContentLength(PRInt32 *aContentLength)
     427                 : {
     428             477 :   NS_ENSURE_ARG_POINTER(aContentLength);
     429                 : 
     430             477 :   if (!mResponseHead)
     431              16 :     return NS_ERROR_NOT_AVAILABLE;
     432                 : 
     433                 :   // XXX truncates to 32 bit
     434             461 :   *aContentLength = mResponseHead->ContentLength();
     435             461 :   return NS_OK;
     436                 : }
     437                 : 
     438                 : NS_IMETHODIMP
     439               0 : HttpBaseChannel::SetContentLength(PRInt32 value)
     440                 : {
     441               0 :   NS_NOTYETIMPLEMENTED("HttpBaseChannel::SetContentLength");
     442               0 :   return NS_ERROR_NOT_IMPLEMENTED;
     443                 : }
     444                 : 
     445                 : NS_IMETHODIMP
     446               3 : HttpBaseChannel::Open(nsIInputStream **aResult)
     447                 : {
     448               3 :   NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_IN_PROGRESS);
     449               1 :   return NS_ImplementChannelOpen(this, aResult);
     450                 : }
     451                 : 
     452                 : //-----------------------------------------------------------------------------
     453                 : // HttpBaseChannel::nsIUploadChannel
     454                 : //-----------------------------------------------------------------------------
     455                 : 
     456                 : NS_IMETHODIMP
     457               0 : HttpBaseChannel::GetUploadStream(nsIInputStream **stream)
     458                 : {
     459               0 :   NS_ENSURE_ARG_POINTER(stream);
     460               0 :   *stream = mUploadStream;
     461               0 :   NS_IF_ADDREF(*stream);
     462               0 :   return NS_OK;
     463                 : }
     464                 : 
     465                 : NS_IMETHODIMP
     466             379 : HttpBaseChannel::SetUploadStream(nsIInputStream *stream,
     467                 :                                const nsACString &contentType,
     468                 :                                PRInt32 contentLength)
     469                 : {
     470                 :   // NOTE: for backwards compatibility and for compatibility with old style
     471                 :   // plugins, |stream| may include headers, specifically Content-Type and
     472                 :   // Content-Length headers.  in this case, |contentType| and |contentLength|
     473                 :   // would be unspecified.  this is traditionally the case of a POST request,
     474                 :   // and so we select POST as the request method if contentType and
     475                 :   // contentLength are unspecified.
     476                 : 
     477             379 :   if (stream) {
     478             379 :     if (contentType.IsEmpty()) {
     479               2 :       mUploadStreamHasHeaders = true;
     480               2 :       mRequestHead.SetMethod(nsHttp::Post); // POST request
     481                 :     } else {
     482             377 :       if (contentLength < 0) {
     483                 :         // Not really kosher to assume Available == total length of
     484                 :         // stream, but apparently works for the streams we see here.
     485               7 :         stream->Available((PRUint32 *) &contentLength);
     486               7 :         if (contentLength < 0) {
     487               0 :           NS_ERROR("unable to determine content length");
     488               0 :           return NS_ERROR_FAILURE;
     489                 :         }
     490                 :       }
     491                 :       // SetRequestHeader propagates headers to chrome if HttpChannelChild 
     492             754 :       nsCAutoString contentLengthStr;
     493             377 :       contentLengthStr.AppendInt(PRInt64(contentLength));
     494             377 :       SetRequestHeader(NS_LITERAL_CSTRING("Content-Length"), contentLengthStr, 
     495             377 :                        false);
     496             377 :       SetRequestHeader(NS_LITERAL_CSTRING("Content-Type"), contentType, 
     497             377 :                        false);
     498             377 :       mUploadStreamHasHeaders = false;
     499             377 :       mRequestHead.SetMethod(nsHttp::Put); // PUT request
     500                 :     }
     501                 :   } else {
     502               0 :     mUploadStreamHasHeaders = false;
     503               0 :     mRequestHead.SetMethod(nsHttp::Get); // revert to GET request
     504                 :   }
     505             379 :   mUploadStream = stream;
     506             379 :   return NS_OK;
     507                 : }
     508                 : 
     509                 : //-----------------------------------------------------------------------------
     510                 : // HttpBaseChannel::nsIUploadChannel2
     511                 : //-----------------------------------------------------------------------------
     512                 : 
     513                 : NS_IMETHODIMP
     514               6 : HttpBaseChannel::ExplicitSetUploadStream(nsIInputStream *aStream,
     515                 :                                        const nsACString &aContentType,
     516                 :                                        PRInt64 aContentLength,
     517                 :                                        const nsACString &aMethod,
     518                 :                                        bool aStreamHasHeaders)
     519                 : {
     520                 :   // Ensure stream is set and method is valid 
     521               6 :   NS_ENSURE_TRUE(aStream, NS_ERROR_FAILURE);
     522                 : 
     523               6 :   if (aContentLength < 0 && !aStreamHasHeaders) {
     524                 :     PRUint32 streamLength;
     525               4 :     aStream->Available(&streamLength);
     526               4 :     aContentLength = streamLength;
     527               4 :     if (aContentLength < 0) {
     528               0 :       NS_ERROR("unable to determine content length");
     529               0 :       return NS_ERROR_FAILURE;
     530                 :     }
     531                 :   }
     532                 : 
     533               6 :   nsresult rv = SetRequestMethod(aMethod);
     534               6 :   NS_ENSURE_SUCCESS(rv, rv);
     535                 : 
     536               6 :   if (!aStreamHasHeaders) {
     537                 :     // SetRequestHeader propagates headers to chrome if HttpChannelChild 
     538              10 :     nsCAutoString contentLengthStr;
     539               5 :     contentLengthStr.AppendInt(aContentLength);
     540               5 :     SetRequestHeader(NS_LITERAL_CSTRING("Content-Length"), contentLengthStr, 
     541               5 :                      false);
     542               5 :     SetRequestHeader(NS_LITERAL_CSTRING("Content-Type"), aContentType, 
     543               5 :                      false);
     544                 :   }
     545                 : 
     546               6 :   mUploadStreamHasHeaders = aStreamHasHeaders;
     547               6 :   mUploadStream = aStream;
     548               6 :   return NS_OK;
     549                 : }
     550                 : 
     551                 : NS_IMETHODIMP
     552               0 : HttpBaseChannel::GetUploadStreamHasHeaders(bool *hasHeaders)
     553                 : {
     554               0 :   NS_ENSURE_ARG(hasHeaders);
     555                 : 
     556               0 :   *hasHeaders = mUploadStreamHasHeaders;
     557               0 :   return NS_OK;
     558                 : }
     559                 : 
     560                 : //-----------------------------------------------------------------------------
     561                 : // HttpBaseChannel::nsIEncodedChannel
     562                 : //-----------------------------------------------------------------------------
     563                 : 
     564                 : NS_IMETHODIMP
     565               0 : HttpBaseChannel::GetApplyConversion(bool *value)
     566                 : {
     567               0 :   *value = mApplyConversion;
     568               0 :   return NS_OK;
     569                 : }
     570                 : 
     571                 : NS_IMETHODIMP
     572             234 : HttpBaseChannel::SetApplyConversion(bool value)
     573                 : {
     574             234 :   LOG(("HttpBaseChannel::SetApplyConversion [this=%p value=%d]\n", this, value));
     575             234 :   mApplyConversion = value;
     576             234 :   return NS_OK;
     577                 : }
     578                 : 
     579                 : nsresult
     580            3021 : HttpBaseChannel::ApplyContentConversions()
     581                 : {
     582            3021 :   if (!mResponseHead)
     583             150 :     return NS_OK;
     584                 : 
     585            2871 :   LOG(("HttpBaseChannel::ApplyContentConversions [this=%p]\n", this));
     586                 : 
     587            2871 :   if (!mApplyConversion) {
     588              24 :     LOG(("not applying conversion per mApplyConversion\n"));
     589              24 :     return NS_OK;
     590                 :   }
     591                 : 
     592            5694 :   nsCAutoString contentEncoding;
     593                 :   char *cePtr, *val;
     594                 :   nsresult rv;
     595                 : 
     596            2847 :   rv = mResponseHead->GetHeader(nsHttp::Content_Encoding, contentEncoding);
     597            2847 :   if (NS_FAILED(rv) || contentEncoding.IsEmpty())
     598            2844 :     return NS_OK;
     599                 : 
     600                 :   // The encodings are listed in the order they were applied
     601                 :   // (see rfc 2616 section 14.11), so they need to removed in reverse
     602                 :   // order. This is accomplished because the converter chain ends up
     603                 :   // being a stack with the last converter created being the first one
     604                 :   // to accept the raw network data.
     605                 : 
     606               3 :   cePtr = contentEncoding.BeginWriting();
     607               3 :   PRUint32 count = 0;
     608              10 :   while ((val = nsCRT::strtok(cePtr, HTTP_LWS ",", &cePtr))) {
     609               4 :     if (++count > 16) {
     610                 :       // That's ridiculous. We only understand 2 different ones :)
     611                 :       // but for compatibility with old code, we will just carry on without
     612                 :       // removing the encodings
     613               0 :       LOG(("Too many Content-Encodings. Ignoring remainder.\n"));
     614               0 :       break;
     615                 :     }
     616                 : 
     617               4 :     if (gHttpHandler->IsAcceptableEncoding(val)) {
     618               8 :       nsCOMPtr<nsIStreamConverterService> serv;
     619               4 :       rv = gHttpHandler->GetStreamConverterService(getter_AddRefs(serv));
     620                 : 
     621                 :       // we won't fail to load the page just because we couldn't load the
     622                 :       // stream converter service.. carry on..
     623               4 :       if (NS_FAILED(rv)) {
     624               0 :         if (val)
     625               0 :           LOG(("Unknown content encoding '%s', ignoring\n", val));
     626               0 :         continue;
     627                 :       }
     628                 : 
     629               8 :       nsCOMPtr<nsIStreamListener> converter;
     630               8 :       nsCAutoString from(val);
     631               4 :       ToLowerCase(from);
     632               4 :       rv = serv->AsyncConvertData(from.get(),
     633                 :                                   "uncompressed",
     634                 :                                   mListener,
     635                 :                                   mListenerContext,
     636               4 :                                   getter_AddRefs(converter));
     637               4 :       if (NS_FAILED(rv)) {
     638               0 :         LOG(("Unexpected failure of AsyncConvertData %s\n", val));
     639               0 :         return rv;
     640                 :       }
     641                 : 
     642               4 :       LOG(("converter removed '%s' content-encoding\n", val));
     643               8 :       mListener = converter;
     644                 :     }
     645                 :     else {
     646               0 :       if (val)
     647               0 :         LOG(("Unknown content encoding '%s', ignoring\n", val));
     648                 :     }
     649                 :   }
     650                 : 
     651               3 :   return NS_OK;
     652                 : }
     653                 : 
     654                 : NS_IMETHODIMP
     655              81 : HttpBaseChannel::GetContentEncodings(nsIUTF8StringEnumerator** aEncodings)
     656                 : {
     657              81 :   if (!mResponseHead) {
     658              51 :     *aEncodings = nsnull;
     659              51 :     return NS_OK;
     660                 :   }
     661                 :     
     662              30 :   const char *encoding = mResponseHead->PeekHeader(nsHttp::Content_Encoding);
     663              30 :   if (!encoding) {
     664              30 :     *aEncodings = nsnull;
     665              30 :     return NS_OK;
     666                 :   }
     667               0 :   nsContentEncodings* enumerator = new nsContentEncodings(this, encoding);
     668               0 :   NS_ADDREF(*aEncodings = enumerator);
     669               0 :   return NS_OK;
     670                 : }
     671                 : 
     672                 : //-----------------------------------------------------------------------------
     673                 : // HttpBaseChannel::nsContentEncodings <public>
     674                 : //-----------------------------------------------------------------------------
     675                 : 
     676               0 : HttpBaseChannel::nsContentEncodings::nsContentEncodings(nsIHttpChannel* aChannel,
     677                 :                                                         const char* aEncodingHeader)
     678                 :   : mEncodingHeader(aEncodingHeader)
     679                 :   , mChannel(aChannel)
     680               0 :   , mReady(false)
     681                 : {
     682               0 :   mCurEnd = aEncodingHeader + strlen(aEncodingHeader);
     683               0 :   mCurStart = mCurEnd;
     684               0 : }
     685                 :     
     686               0 : HttpBaseChannel::nsContentEncodings::~nsContentEncodings()
     687                 : {
     688               0 : }
     689                 : 
     690                 : //-----------------------------------------------------------------------------
     691                 : // HttpBaseChannel::nsContentEncodings::nsISimpleEnumerator
     692                 : //-----------------------------------------------------------------------------
     693                 : 
     694                 : NS_IMETHODIMP
     695               0 : HttpBaseChannel::nsContentEncodings::HasMore(bool* aMoreEncodings)
     696                 : {
     697               0 :   if (mReady) {
     698               0 :     *aMoreEncodings = true;
     699               0 :     return NS_OK;
     700                 :   }
     701                 : 
     702               0 :   nsresult rv = PrepareForNext();
     703               0 :   *aMoreEncodings = NS_SUCCEEDED(rv);
     704               0 :   return NS_OK;
     705                 : }
     706                 : 
     707                 : NS_IMETHODIMP
     708               0 : HttpBaseChannel::nsContentEncodings::GetNext(nsACString& aNextEncoding)
     709                 : {
     710               0 :   aNextEncoding.Truncate();
     711               0 :   if (!mReady) {
     712               0 :     nsresult rv = PrepareForNext();
     713               0 :     if (NS_FAILED(rv)) {
     714               0 :       return NS_ERROR_FAILURE;
     715                 :     }
     716                 :   }
     717                 : 
     718               0 :   const nsACString & encoding = Substring(mCurStart, mCurEnd);
     719                 : 
     720               0 :   nsACString::const_iterator start, end;
     721               0 :   encoding.BeginReading(start);
     722               0 :   encoding.EndReading(end);
     723                 : 
     724               0 :   bool haveType = false;
     725               0 :   if (CaseInsensitiveFindInReadable(NS_LITERAL_CSTRING("gzip"), start, end)) {
     726               0 :     aNextEncoding.AssignLiteral(APPLICATION_GZIP);
     727               0 :     haveType = true;
     728                 :   }
     729                 : 
     730               0 :   if (!haveType) {
     731               0 :     encoding.BeginReading(start);
     732               0 :     if (CaseInsensitiveFindInReadable(NS_LITERAL_CSTRING("compress"), start, end)) {
     733               0 :       aNextEncoding.AssignLiteral(APPLICATION_COMPRESS);
     734               0 :       haveType = true;
     735                 :     }
     736                 :   }
     737                 :     
     738               0 :   if (!haveType) {
     739               0 :     encoding.BeginReading(start);
     740               0 :     if (CaseInsensitiveFindInReadable(NS_LITERAL_CSTRING("deflate"), start, end)) {
     741               0 :       aNextEncoding.AssignLiteral(APPLICATION_ZIP);
     742               0 :       haveType = true;
     743                 :     }
     744                 :   }
     745                 : 
     746                 :   // Prepare to fetch the next encoding
     747               0 :   mCurEnd = mCurStart;
     748               0 :   mReady = false;
     749                 :   
     750               0 :   if (haveType)
     751               0 :     return NS_OK;
     752                 : 
     753               0 :   NS_WARNING("Unknown encoding type");
     754               0 :   return NS_ERROR_FAILURE;
     755                 : }
     756                 : 
     757                 : //-----------------------------------------------------------------------------
     758                 : // HttpBaseChannel::nsContentEncodings::nsISupports
     759                 : //-----------------------------------------------------------------------------
     760                 : 
     761               0 : NS_IMPL_ISUPPORTS1(HttpBaseChannel::nsContentEncodings, nsIUTF8StringEnumerator)
     762                 : 
     763                 : //-----------------------------------------------------------------------------
     764                 : // HttpBaseChannel::nsContentEncodings <private>
     765                 : //-----------------------------------------------------------------------------
     766                 : 
     767                 : nsresult
     768               0 : HttpBaseChannel::nsContentEncodings::PrepareForNext(void)
     769                 : {
     770               0 :   NS_ASSERTION(mCurStart == mCurEnd, "Indeterminate state");
     771                 :     
     772                 :   // At this point both mCurStart and mCurEnd point to somewhere
     773                 :   // past the end of the next thing we want to return
     774                 :     
     775               0 :   while (mCurEnd != mEncodingHeader) {
     776               0 :     --mCurEnd;
     777               0 :     if (*mCurEnd != ',' && !nsCRT::IsAsciiSpace(*mCurEnd))
     778               0 :       break;
     779                 :   }
     780               0 :   if (mCurEnd == mEncodingHeader)
     781               0 :     return NS_ERROR_NOT_AVAILABLE; // no more encodings
     782               0 :   ++mCurEnd;
     783                 :         
     784                 :   // At this point mCurEnd points to the first char _after_ the
     785                 :   // header we want.  Furthermore, mCurEnd - 1 != mEncodingHeader
     786                 :     
     787               0 :   mCurStart = mCurEnd - 1;
     788               0 :   while (mCurStart != mEncodingHeader &&
     789               0 :          *mCurStart != ',' && !nsCRT::IsAsciiSpace(*mCurStart))
     790               0 :     --mCurStart;
     791               0 :   if (*mCurStart == ',' || nsCRT::IsAsciiSpace(*mCurStart))
     792               0 :     ++mCurStart; // we stopped because of a weird char, so move up one
     793                 :         
     794                 :   // At this point mCurStart and mCurEnd bracket the encoding string
     795                 :   // we want.  Check that it's not "identity"
     796               0 :   if (Substring(mCurStart, mCurEnd).Equals("identity",
     797               0 :                                            nsCaseInsensitiveCStringComparator())) {
     798               0 :     mCurEnd = mCurStart;
     799               0 :     return PrepareForNext();
     800                 :   }
     801                 :         
     802               0 :   mReady = true;
     803               0 :   return NS_OK;
     804                 : }
     805                 : 
     806                 : 
     807                 : //-----------------------------------------------------------------------------
     808                 : // HttpBaseChannel::nsIHttpChannel
     809                 : //-----------------------------------------------------------------------------
     810                 : 
     811                 : NS_IMETHODIMP
     812            5400 : HttpBaseChannel::GetRequestMethod(nsACString& aMethod)
     813                 : {
     814            5400 :   aMethod = mRequestHead.Method();
     815            5400 :   return NS_OK;
     816                 : }
     817                 : 
     818                 : NS_IMETHODIMP
     819            2266 : HttpBaseChannel::SetRequestMethod(const nsACString& aMethod)
     820                 : {
     821            2266 :   ENSURE_CALLED_BEFORE_ASYNC_OPEN();
     822                 : 
     823            4532 :   const nsCString& flatMethod = PromiseFlatCString(aMethod);
     824                 : 
     825                 :   // Method names are restricted to valid HTTP tokens.
     826            2266 :   if (!nsHttp::IsValidToken(flatMethod))
     827               0 :     return NS_ERROR_INVALID_ARG;
     828                 : 
     829            2266 :   nsHttpAtom atom = nsHttp::ResolveAtom(flatMethod.get());
     830            2266 :   if (!atom)
     831               0 :     return NS_ERROR_FAILURE;
     832                 : 
     833            2266 :   mRequestHead.SetMethod(atom);
     834            2266 :   return NS_OK;
     835                 : }
     836                 : 
     837                 : NS_IMETHODIMP
     838              24 : HttpBaseChannel::GetReferrer(nsIURI **referrer)
     839                 : {
     840              24 :   NS_ENSURE_ARG_POINTER(referrer);
     841              24 :   *referrer = mReferrer;
     842              24 :   NS_IF_ADDREF(*referrer);
     843              24 :   return NS_OK;
     844                 : }
     845                 : 
     846                 : NS_IMETHODIMP
     847              36 : HttpBaseChannel::SetReferrer(nsIURI *referrer)
     848                 : {
     849              36 :   ENSURE_CALLED_BEFORE_ASYNC_OPEN();
     850                 : 
     851                 :   // clear existing referrer, if any
     852              36 :   mReferrer = nsnull;
     853              36 :   mRequestHead.ClearHeader(nsHttp::Referer);
     854                 : 
     855              36 :   if (!referrer)
     856               2 :       return NS_OK;
     857                 : 
     858                 :   // check referrer blocking pref
     859                 :   PRUint32 referrerLevel;
     860              34 :   if (mLoadFlags & LOAD_INITIAL_DOCUMENT_URI)
     861               0 :     referrerLevel = 1; // user action
     862                 :   else
     863              34 :     referrerLevel = 2; // inline content
     864              34 :   if (gHttpHandler->ReferrerLevel() < referrerLevel)
     865               0 :     return NS_OK;
     866                 : 
     867              68 :   nsCOMPtr<nsIURI> referrerGrip;
     868                 :   nsresult rv;
     869                 :   bool match;
     870                 : 
     871                 :   //
     872                 :   // Strip off "wyciwyg://123/" from wyciwyg referrers.
     873                 :   //
     874                 :   // XXX this really belongs elsewhere since wyciwyg URLs aren't part of necko.
     875                 :   //     perhaps some sort of generic nsINestedURI could be used.  then, if an URI
     876                 :   //     fails the whitelist test, then we could check for an inner URI and try
     877                 :   //     that instead.  though, that might be too automatic.
     878                 :   // 
     879              34 :   rv = referrer->SchemeIs("wyciwyg", &match);
     880              34 :   if (NS_FAILED(rv)) return rv;
     881              34 :   if (match) {
     882               0 :     nsCAutoString path;
     883               0 :     rv = referrer->GetPath(path);
     884               0 :     if (NS_FAILED(rv)) return rv;
     885                 : 
     886               0 :     PRUint32 pathLength = path.Length();
     887               0 :     if (pathLength <= 2) return NS_ERROR_FAILURE;
     888                 : 
     889                 :     // Path is of the form "//123/http://foo/bar", with a variable number of digits.
     890                 :     // To figure out where the "real" URL starts, search path for a '/', starting at 
     891                 :     // the third character.
     892               0 :     PRInt32 slashIndex = path.FindChar('/', 2);
     893               0 :     if (slashIndex == kNotFound) return NS_ERROR_FAILURE;
     894                 : 
     895                 :     // Get the charset of the original URI so we can pass it to our fixed up URI.
     896               0 :     nsCAutoString charset;
     897               0 :     referrer->GetOriginCharset(charset);
     898                 : 
     899                 :     // Replace |referrer| with a URI without wyciwyg://123/.
     900               0 :     rv = NS_NewURI(getter_AddRefs(referrerGrip),
     901               0 :                    Substring(path, slashIndex + 1, pathLength - slashIndex - 1),
     902               0 :                    charset.get());
     903               0 :     if (NS_FAILED(rv)) return rv;
     904                 : 
     905               0 :     referrer = referrerGrip.get();
     906                 :   }
     907                 : 
     908                 :   //
     909                 :   // block referrer if not on our white list...
     910                 :   //
     911                 :   static const char *const referrerWhiteList[] = {
     912                 :     "http",
     913                 :     "https",
     914                 :     "ftp",
     915                 :     "gopher",
     916                 :     nsnull
     917                 :   };
     918              34 :   match = false;
     919              34 :   const char *const *scheme = referrerWhiteList;
     920              68 :   for (; *scheme && !match; ++scheme) {
     921              34 :     rv = referrer->SchemeIs(*scheme, &match);
     922              34 :     if (NS_FAILED(rv)) return rv;
     923                 :   }
     924              34 :   if (!match)
     925               0 :     return NS_OK; // kick out....
     926                 : 
     927                 :   //
     928                 :   // Handle secure referrals.
     929                 :   //
     930                 :   // Support referrals from a secure server if this is a secure site
     931                 :   // and (optionally) if the host names are the same.
     932                 :   //
     933              34 :   rv = referrer->SchemeIs("https", &match);
     934              34 :   if (NS_FAILED(rv)) return rv;
     935              34 :   if (match) {
     936               0 :     rv = mURI->SchemeIs("https", &match);
     937               0 :     if (NS_FAILED(rv)) return rv;
     938               0 :     if (!match)
     939               0 :       return NS_OK;
     940                 : 
     941               0 :     if (!gHttpHandler->SendSecureXSiteReferrer()) {
     942               0 :       nsCAutoString referrerHost;
     943               0 :       nsCAutoString host;
     944                 : 
     945               0 :       rv = referrer->GetAsciiHost(referrerHost);
     946               0 :       if (NS_FAILED(rv)) return rv;
     947                 : 
     948               0 :       rv = mURI->GetAsciiHost(host);
     949               0 :       if (NS_FAILED(rv)) return rv;
     950                 : 
     951                 :       // GetAsciiHost returns lowercase hostname.
     952               0 :       if (!referrerHost.Equals(host))
     953               0 :         return NS_OK;
     954                 :     }
     955                 :   }
     956                 : 
     957              68 :   nsCOMPtr<nsIURI> clone;
     958                 :   //
     959                 :   // we need to clone the referrer, so we can:
     960                 :   //  (1) modify it
     961                 :   //  (2) keep a reference to it after returning from this function
     962                 :   //
     963                 :   // Use CloneIgnoringRef to strip away any fragment per RFC 2616 section 14.36
     964              34 :   rv = referrer->CloneIgnoringRef(getter_AddRefs(clone));
     965              34 :   if (NS_FAILED(rv)) return rv;
     966                 : 
     967                 :   // strip away any userpass; we don't want to be giving out passwords ;-)
     968              34 :   rv = clone->SetUserPass(EmptyCString());
     969              34 :   if (NS_FAILED(rv)) return rv;
     970                 : 
     971              68 :   nsCAutoString spec;
     972              34 :   rv = clone->GetAsciiSpec(spec);
     973              34 :   if (NS_FAILED(rv)) return rv;
     974                 : 
     975                 :   // finally, remember the referrer URI and set the Referer header.
     976              34 :   mReferrer = clone;
     977              34 :   mRequestHead.SetHeader(nsHttp::Referer, spec);
     978              34 :   return NS_OK;
     979                 : }
     980                 : 
     981                 : NS_IMETHODIMP
     982            1178 : HttpBaseChannel::GetRequestHeader(const nsACString& aHeader,
     983                 :                                   nsACString& aValue)
     984                 : {
     985                 :   // XXX might be better to search the header list directly instead of
     986                 :   // hitting the http atom hash table.
     987            1178 :   nsHttpAtom atom = nsHttp::ResolveAtom(aHeader);
     988            1178 :   if (!atom)
     989               0 :     return NS_ERROR_NOT_AVAILABLE;
     990                 : 
     991            1178 :   return mRequestHead.GetHeader(atom, aValue);
     992                 : }
     993                 : 
     994                 : NS_IMETHODIMP
     995            7628 : HttpBaseChannel::SetRequestHeader(const nsACString& aHeader,
     996                 :                                   const nsACString& aValue,
     997                 :                                   bool aMerge)
     998                 : {
     999           15256 :   const nsCString &flatHeader = PromiseFlatCString(aHeader);
    1000           15256 :   const nsCString &flatValue  = PromiseFlatCString(aValue);
    1001                 : 
    1002            7628 :   LOG(("HttpBaseChannel::SetRequestHeader [this=%p header=\"%s\" value=\"%s\" merge=%u]\n",
    1003                 :       this, flatHeader.get(), flatValue.get(), aMerge));
    1004                 : 
    1005                 :   // Header names are restricted to valid HTTP tokens.
    1006            7628 :   if (!nsHttp::IsValidToken(flatHeader))
    1007               2 :     return NS_ERROR_INVALID_ARG;
    1008                 :   
    1009                 :   // Header values MUST NOT contain line-breaks.  RFC 2616 technically
    1010                 :   // permits CTL characters, including CR and LF, in header values provided
    1011                 :   // they are quoted.  However, this can lead to problems if servers do not
    1012                 :   // interpret quoted strings properly.  Disallowing CR and LF here seems
    1013                 :   // reasonable and keeps things simple.  We also disallow a null byte.
    1014           15251 :   if (flatValue.FindCharInSet("\r\n") != kNotFound ||
    1015            7625 :       flatValue.Length() != strlen(flatValue.get()))
    1016               2 :     return NS_ERROR_INVALID_ARG;
    1017                 : 
    1018            7624 :   nsHttpAtom atom = nsHttp::ResolveAtom(flatHeader.get());
    1019            7624 :   if (!atom) {
    1020               0 :     NS_WARNING("failed to resolve atom");
    1021               0 :     return NS_ERROR_NOT_AVAILABLE;
    1022                 :   }
    1023                 : 
    1024            7624 :   return mRequestHead.SetHeader(atom, flatValue, aMerge);
    1025                 : }
    1026                 : 
    1027                 : NS_IMETHODIMP
    1028               0 : HttpBaseChannel::VisitRequestHeaders(nsIHttpHeaderVisitor *visitor)
    1029                 : {
    1030               0 :   return mRequestHead.Headers().VisitHeaders(visitor);
    1031                 : }
    1032                 : 
    1033                 : NS_IMETHODIMP
    1034            7605 : HttpBaseChannel::GetResponseHeader(const nsACString &header, nsACString &value)
    1035                 : {
    1036            7605 :   if (!mResponseHead)
    1037              22 :     return NS_ERROR_NOT_AVAILABLE;
    1038                 : 
    1039            7583 :   nsHttpAtom atom = nsHttp::ResolveAtom(header);
    1040            7583 :   if (!atom)
    1041               0 :     return NS_ERROR_NOT_AVAILABLE;
    1042                 : 
    1043            7583 :   return mResponseHead->GetHeader(atom, value);
    1044                 : }
    1045                 : 
    1046                 : NS_IMETHODIMP
    1047               1 : HttpBaseChannel::SetResponseHeader(const nsACString& header, 
    1048                 :                                    const nsACString& value, 
    1049                 :                                    bool merge)
    1050                 : {
    1051               1 :   LOG(("HttpBaseChannel::SetResponseHeader [this=%p header=\"%s\" value=\"%s\" merge=%u]\n",
    1052                 :       this, PromiseFlatCString(header).get(), PromiseFlatCString(value).get(), merge));
    1053                 : 
    1054               1 :   if (!mResponseHead)
    1055               0 :     return NS_ERROR_NOT_AVAILABLE;
    1056                 : 
    1057               1 :   nsHttpAtom atom = nsHttp::ResolveAtom(header);
    1058               1 :   if (!atom)
    1059               0 :     return NS_ERROR_NOT_AVAILABLE;
    1060                 : 
    1061                 :   // these response headers must not be changed 
    1062               5 :   if (atom == nsHttp::Content_Type ||
    1063               1 :       atom == nsHttp::Content_Length ||
    1064               1 :       atom == nsHttp::Content_Encoding ||
    1065               1 :       atom == nsHttp::Trailer ||
    1066               1 :       atom == nsHttp::Transfer_Encoding)
    1067               0 :     return NS_ERROR_ILLEGAL_VALUE;
    1068                 : 
    1069               1 :   mResponseHeadersModified = true;
    1070                 : 
    1071               1 :   return mResponseHead->SetHeader(atom, value, merge);
    1072                 : }
    1073                 : 
    1074                 : NS_IMETHODIMP
    1075            1387 : HttpBaseChannel::VisitResponseHeaders(nsIHttpHeaderVisitor *visitor)
    1076                 : {
    1077            1387 :   if (!mResponseHead)
    1078               1 :     return NS_ERROR_NOT_AVAILABLE;
    1079            1386 :   return mResponseHead->Headers().VisitHeaders(visitor);
    1080                 : }
    1081                 : 
    1082                 : NS_IMETHODIMP
    1083               0 : HttpBaseChannel::GetAllowPipelining(bool *value)
    1084                 : {
    1085               0 :   NS_ENSURE_ARG_POINTER(value);
    1086               0 :   *value = mAllowPipelining;
    1087               0 :   return NS_OK;
    1088                 : }
    1089                 : 
    1090                 : NS_IMETHODIMP
    1091             153 : HttpBaseChannel::SetAllowPipelining(bool value)
    1092                 : {
    1093             153 :   ENSURE_CALLED_BEFORE_ASYNC_OPEN();
    1094                 : 
    1095             153 :   mAllowPipelining = value;
    1096             153 :   return NS_OK;
    1097                 : }
    1098                 : 
    1099                 : NS_IMETHODIMP
    1100               0 : HttpBaseChannel::GetRedirectionLimit(PRUint32 *value)
    1101                 : {
    1102               0 :   NS_ENSURE_ARG_POINTER(value);
    1103               0 :   *value = mRedirectionLimit;
    1104               0 :   return NS_OK;
    1105                 : }
    1106                 : 
    1107                 : NS_IMETHODIMP
    1108             153 : HttpBaseChannel::SetRedirectionLimit(PRUint32 value)
    1109                 : {
    1110             153 :   ENSURE_CALLED_BEFORE_ASYNC_OPEN();
    1111                 : 
    1112             153 :   mRedirectionLimit = NS_MIN<PRUint32>(value, 0xff);
    1113             153 :   return NS_OK;
    1114                 : }
    1115                 : 
    1116                 : NS_IMETHODIMP
    1117               8 : HttpBaseChannel::IsNoStoreResponse(bool *value)
    1118                 : {
    1119               8 :   if (!mResponseHead)
    1120               0 :     return NS_ERROR_NOT_AVAILABLE;
    1121               8 :   *value = mResponseHead->NoStore();
    1122               8 :   return NS_OK;
    1123                 : }
    1124                 : 
    1125                 : NS_IMETHODIMP
    1126               4 : HttpBaseChannel::IsNoCacheResponse(bool *value)
    1127                 : {
    1128               4 :   if (!mResponseHead)
    1129               0 :     return NS_ERROR_NOT_AVAILABLE;
    1130               4 :   *value = mResponseHead->NoCache();
    1131               4 :   if (!*value)
    1132               4 :     *value = mResponseHead->ExpiresInPast();
    1133               4 :   return NS_OK;
    1134                 : }
    1135                 : 
    1136                 : NS_IMETHODIMP
    1137            2623 : HttpBaseChannel::GetResponseStatus(PRUint32 *aValue)
    1138                 : {
    1139            2623 :   if (!mResponseHead)
    1140              73 :     return NS_ERROR_NOT_AVAILABLE;
    1141            2550 :   *aValue = mResponseHead->Status();
    1142            2550 :   return NS_OK;
    1143                 : }
    1144                 : 
    1145                 : NS_IMETHODIMP
    1146              99 : HttpBaseChannel::GetResponseStatusText(nsACString& aValue)
    1147                 : {
    1148              99 :   if (!mResponseHead)
    1149               0 :     return NS_ERROR_NOT_AVAILABLE;
    1150              99 :   aValue = mResponseHead->StatusText();
    1151              99 :   return NS_OK;
    1152                 : }
    1153                 : 
    1154                 : NS_IMETHODIMP
    1155            6333 : HttpBaseChannel::GetRequestSucceeded(bool *aValue)
    1156                 : {
    1157            6333 :   if (!mResponseHead)
    1158             120 :     return NS_ERROR_NOT_AVAILABLE;
    1159            6213 :   PRUint32 status = mResponseHead->Status();
    1160            6213 :   *aValue = (status / 100 == 2);
    1161            6213 :   return NS_OK;
    1162                 : }
    1163                 : 
    1164                 : //-----------------------------------------------------------------------------
    1165                 : // HttpBaseChannel::nsIHttpChannelInternal
    1166                 : //-----------------------------------------------------------------------------
    1167                 : 
    1168                 : NS_IMETHODIMP
    1169               0 : HttpBaseChannel::GetDocumentURI(nsIURI **aDocumentURI)
    1170                 : {
    1171               0 :   NS_ENSURE_ARG_POINTER(aDocumentURI);
    1172               0 :   *aDocumentURI = mDocumentURI;
    1173               0 :   NS_IF_ADDREF(*aDocumentURI);
    1174               0 :   return NS_OK;
    1175                 : }
    1176                 : 
    1177                 : NS_IMETHODIMP
    1178             155 : HttpBaseChannel::SetDocumentURI(nsIURI *aDocumentURI)
    1179                 : {
    1180             155 :   ENSURE_CALLED_BEFORE_ASYNC_OPEN();
    1181                 : 
    1182             155 :   mDocumentURI = aDocumentURI;
    1183             155 :   return NS_OK;
    1184                 : }
    1185                 : 
    1186                 : NS_IMETHODIMP
    1187               2 : HttpBaseChannel::GetRequestVersion(PRUint32 *major, PRUint32 *minor)
    1188                 : {
    1189               2 :   nsHttpVersion version = mRequestHead.Version();
    1190                 : 
    1191               2 :   if (major) { *major = version / 10; }
    1192               2 :   if (minor) { *minor = version % 10; }
    1193                 : 
    1194               2 :   return NS_OK;
    1195                 : }
    1196                 : 
    1197                 : NS_IMETHODIMP
    1198              13 : HttpBaseChannel::GetResponseVersion(PRUint32 *major, PRUint32 *minor)
    1199                 : {
    1200              13 :   if (!mResponseHead)
    1201                 :   {
    1202               0 :     *major = *minor = 0; // we should at least be kind about it
    1203               0 :     return NS_ERROR_NOT_AVAILABLE;
    1204                 :   }
    1205                 : 
    1206              13 :   nsHttpVersion version = mResponseHead->Version();
    1207                 : 
    1208              13 :   if (major) { *major = version / 10; }
    1209              13 :   if (minor) { *minor = version % 10; }
    1210                 : 
    1211              13 :   return NS_OK;
    1212                 : }
    1213                 : 
    1214                 : NS_IMETHODIMP
    1215            2819 : HttpBaseChannel::SetCookie(const char *aCookieHeader)
    1216                 : {
    1217            2819 :   if (mLoadFlags & LOAD_ANONYMOUS)
    1218               1 :     return NS_OK;
    1219                 : 
    1220                 :   // empty header isn't an error
    1221            2818 :   if (!(aCookieHeader && *aCookieHeader))
    1222            2816 :     return NS_OK;
    1223                 : 
    1224               2 :   nsICookieService *cs = gHttpHandler->GetCookieService();
    1225               2 :   NS_ENSURE_TRUE(cs, NS_ERROR_FAILURE);
    1226                 : 
    1227                 :   return cs->SetCookieStringFromHttp(mURI, nsnull, nsnull, aCookieHeader,
    1228                 :                                      mResponseHead->PeekHeader(nsHttp::Date),
    1229               2 :                                      this);
    1230                 : }
    1231                 : 
    1232                 : NS_IMETHODIMP
    1233              21 : HttpBaseChannel::GetForceAllowThirdPartyCookie(bool *aForce)
    1234                 : {
    1235              21 :   *aForce = mForceAllowThirdPartyCookie;
    1236              21 :   return NS_OK;
    1237                 : }
    1238                 : 
    1239                 : NS_IMETHODIMP
    1240             409 : HttpBaseChannel::SetForceAllowThirdPartyCookie(bool aForce)
    1241                 : {
    1242             409 :   ENSURE_CALLED_BEFORE_ASYNC_OPEN();
    1243                 : 
    1244             409 :   mForceAllowThirdPartyCookie = aForce;
    1245             409 :   return NS_OK;
    1246                 : }
    1247                 : 
    1248                 : NS_IMETHODIMP
    1249             526 : HttpBaseChannel::GetCanceled(bool *aCanceled)
    1250                 : {
    1251             526 :   *aCanceled = mCanceled;
    1252             526 :   return NS_OK;
    1253                 : }
    1254                 : 
    1255                 : NS_IMETHODIMP
    1256               0 : HttpBaseChannel::GetChannelIsForDownload(bool *aChannelIsForDownload)
    1257                 : {
    1258               0 :   *aChannelIsForDownload = mChannelIsForDownload;
    1259               0 :   return NS_OK;
    1260                 : }
    1261                 : 
    1262                 : NS_IMETHODIMP
    1263               6 : HttpBaseChannel::SetChannelIsForDownload(bool aChannelIsForDownload)
    1264                 : {
    1265               6 :   mChannelIsForDownload = aChannelIsForDownload;
    1266               6 :   return NS_OK;
    1267                 : }
    1268                 : 
    1269                 : NS_IMETHODIMP
    1270              11 : HttpBaseChannel::SetCacheKeysRedirectChain(nsTArray<nsCString> *cacheKeys)
    1271                 : {
    1272              11 :   mRedirectedCachekeys = cacheKeys;
    1273              11 :   return NS_OK;
    1274                 : }
    1275                 : 
    1276                 : NS_IMETHODIMP
    1277               0 : HttpBaseChannel::GetLocalAddress(nsACString& addr)
    1278                 : {
    1279               0 :   if (mSelfAddr.raw.family == PR_AF_UNSPEC)
    1280               0 :     return NS_ERROR_NOT_AVAILABLE;
    1281                 : 
    1282               0 :   addr.SetCapacity(64);
    1283               0 :   PR_NetAddrToString(&mSelfAddr, addr.BeginWriting(), 64);
    1284               0 :   addr.SetLength(strlen(addr.BeginReading()));
    1285                 : 
    1286               0 :   return NS_OK;
    1287                 : }
    1288                 : 
    1289                 : NS_IMETHODIMP
    1290               0 : HttpBaseChannel::GetLocalPort(PRInt32* port)
    1291                 : {
    1292               0 :   NS_ENSURE_ARG_POINTER(port);
    1293                 : 
    1294               0 :   if (mSelfAddr.raw.family == PR_AF_INET) {
    1295               0 :     *port = (PRInt32)PR_ntohs(mSelfAddr.inet.port);
    1296                 :   }
    1297               0 :   else if (mSelfAddr.raw.family == PR_AF_INET6) {
    1298               0 :     *port = (PRInt32)PR_ntohs(mSelfAddr.ipv6.port);
    1299                 :   }
    1300                 :   else
    1301               0 :     return NS_ERROR_NOT_AVAILABLE;
    1302                 : 
    1303               0 :   return NS_OK;
    1304                 : }
    1305                 : 
    1306                 : NS_IMETHODIMP
    1307               0 : HttpBaseChannel::GetRemoteAddress(nsACString& addr)
    1308                 : {
    1309               0 :   if (mPeerAddr.raw.family == PR_AF_UNSPEC)
    1310               0 :     return NS_ERROR_NOT_AVAILABLE;
    1311                 : 
    1312               0 :   addr.SetCapacity(64);
    1313               0 :   PR_NetAddrToString(&mPeerAddr, addr.BeginWriting(), 64);
    1314               0 :   addr.SetLength(strlen(addr.BeginReading()));
    1315                 : 
    1316               0 :   return NS_OK;
    1317                 : }
    1318                 : 
    1319                 : NS_IMETHODIMP
    1320               0 : HttpBaseChannel::GetRemotePort(PRInt32* port)
    1321                 : {
    1322               0 :   NS_ENSURE_ARG_POINTER(port);
    1323                 : 
    1324               0 :   if (mPeerAddr.raw.family == PR_AF_INET) {
    1325               0 :     *port = (PRInt32)PR_ntohs(mPeerAddr.inet.port);
    1326                 :   }
    1327               0 :   else if (mPeerAddr.raw.family == PR_AF_INET6) {
    1328               0 :     *port = (PRInt32)PR_ntohs(mPeerAddr.ipv6.port);
    1329                 :   }
    1330                 :   else
    1331               0 :     return NS_ERROR_NOT_AVAILABLE;
    1332                 : 
    1333               0 :   return NS_OK;
    1334                 : }
    1335                 : 
    1336                 : NS_IMETHODIMP
    1337               0 : HttpBaseChannel::HTTPUpgrade(const nsACString &aProtocolName,
    1338                 :                              nsIHttpUpgradeListener *aListener)
    1339                 : {
    1340               0 :     NS_ENSURE_ARG(!aProtocolName.IsEmpty());
    1341               0 :     NS_ENSURE_ARG_POINTER(aListener);
    1342                 :     
    1343               0 :     mUpgradeProtocol = aProtocolName;
    1344               0 :     mUpgradeProtocolCallback = aListener;
    1345               0 :     return NS_OK;
    1346                 : }
    1347                 : 
    1348                 : NS_IMETHODIMP
    1349               0 : HttpBaseChannel::GetAllowSpdy(bool *aAllowSpdy)
    1350                 : {
    1351               0 :   NS_ENSURE_ARG_POINTER(aAllowSpdy);
    1352                 : 
    1353               0 :   *aAllowSpdy = mAllowSpdy;
    1354               0 :   return NS_OK;
    1355                 : }
    1356                 : 
    1357                 : NS_IMETHODIMP
    1358             153 : HttpBaseChannel::SetAllowSpdy(bool aAllowSpdy)
    1359                 : {
    1360             153 :   mAllowSpdy = aAllowSpdy;
    1361             153 :   return NS_OK;
    1362                 : }
    1363                 : 
    1364                 : //-----------------------------------------------------------------------------
    1365                 : // HttpBaseChannel::nsISupportsPriority
    1366                 : //-----------------------------------------------------------------------------
    1367                 : 
    1368                 : NS_IMETHODIMP
    1369               0 : HttpBaseChannel::GetPriority(PRInt32 *value)
    1370                 : {
    1371               0 :   *value = mPriority;
    1372               0 :   return NS_OK;
    1373                 : }
    1374                 : 
    1375                 : NS_IMETHODIMP
    1376               2 : HttpBaseChannel::AdjustPriority(PRInt32 delta)
    1377                 : {
    1378               2 :   return SetPriority(mPriority + delta);
    1379                 : }
    1380                 : 
    1381                 : //-----------------------------------------------------------------------------
    1382                 : // HttpBaseChannel::nsIResumableChannel
    1383                 : //-----------------------------------------------------------------------------
    1384                 : 
    1385                 : NS_IMETHODIMP
    1386              38 : HttpBaseChannel::GetEntityID(nsACString& aEntityID)
    1387                 : {
    1388                 :   // Don't return an entity ID for Non-GET requests which require
    1389                 :   // additional data
    1390              38 :   if (mRequestHead.Method() != nsHttp::Get) {
    1391               0 :     return NS_ERROR_NOT_RESUMABLE;
    1392                 :   }
    1393                 : 
    1394              38 :   PRUint64 size = LL_MAXUINT;
    1395              76 :   nsCAutoString etag, lastmod;
    1396              38 :   if (mResponseHead) {
    1397                 :     // Don't return an entity if the server sent the following header:
    1398                 :     // Accept-Ranges: none
    1399                 :     // Not sending the Accept-Ranges header means we can still try
    1400                 :     // sending range requests.
    1401                 :     const char* acceptRanges =
    1402              38 :         mResponseHead->PeekHeader(nsHttp::Accept_Ranges);
    1403              51 :     if (acceptRanges &&
    1404              13 :         !nsHttp::FindToken(acceptRanges, "bytes", HTTP_HEADER_VALUE_SEPS)) {
    1405               5 :       return NS_ERROR_NOT_RESUMABLE;
    1406                 :     }
    1407                 : 
    1408              33 :     size = mResponseHead->TotalEntitySize();
    1409              33 :     const char* cLastMod = mResponseHead->PeekHeader(nsHttp::Last_Modified);
    1410              33 :     if (cLastMod)
    1411               7 :       lastmod = cLastMod;
    1412              33 :     const char* cEtag = mResponseHead->PeekHeader(nsHttp::ETag);
    1413              33 :     if (cEtag)
    1414               0 :       etag = cEtag;
    1415                 :   }
    1416              66 :   nsCString entityID;
    1417              33 :   NS_EscapeURL(etag.BeginReading(), etag.Length(), esc_AlwaysCopy |
    1418              33 :                esc_FileBaseName | esc_Forced, entityID);
    1419              33 :   entityID.Append('/');
    1420              33 :   entityID.AppendInt(PRInt64(size));
    1421              33 :   entityID.Append('/');
    1422              33 :   entityID.Append(lastmod);
    1423                 :   // NOTE: Appending lastmod as the last part avoids having to escape it
    1424                 : 
    1425              33 :   aEntityID = entityID;
    1426                 : 
    1427              33 :   return NS_OK;
    1428                 : }
    1429                 : 
    1430                 : //-----------------------------------------------------------------------------
    1431                 : // nsStreamListenerWrapper <private>
    1432                 : //-----------------------------------------------------------------------------
    1433                 : 
    1434                 : // Wrapper class to make replacement of nsHttpChannel's listener
    1435                 : // from JavaScript possible. It is workaround for bug 433711.
    1436                 : class nsStreamListenerWrapper : public nsIStreamListener
    1437                 : {
    1438                 : public:
    1439                 :   nsStreamListenerWrapper(nsIStreamListener *listener);
    1440                 : 
    1441                 :   NS_DECL_ISUPPORTS
    1442               2 :   NS_FORWARD_NSIREQUESTOBSERVER(mListener->)
    1443               1 :   NS_FORWARD_NSISTREAMLISTENER(mListener->)
    1444                 : 
    1445                 : private:
    1446               1 :   ~nsStreamListenerWrapper() {}
    1447                 :   nsCOMPtr<nsIStreamListener> mListener;
    1448                 : };
    1449                 : 
    1450               1 : nsStreamListenerWrapper::nsStreamListenerWrapper(nsIStreamListener *listener)
    1451               1 :   : mListener(listener)
    1452                 : {
    1453               1 :   NS_ASSERTION(mListener, "no stream listener specified");
    1454               1 : }
    1455                 : 
    1456              26 : NS_IMPL_ISUPPORTS2(nsStreamListenerWrapper,
    1457                 :                    nsIStreamListener,
    1458                 :                    nsIRequestObserver)
    1459                 : 
    1460                 : //-----------------------------------------------------------------------------
    1461                 : // nsHttpChannel::nsITraceableChannel
    1462                 : //-----------------------------------------------------------------------------
    1463                 : 
    1464                 : NS_IMETHODIMP
    1465               2 : HttpBaseChannel::SetNewListener(nsIStreamListener *aListener, nsIStreamListener **_retval)
    1466                 : {
    1467               2 :   if (!mTracingEnabled)
    1468               1 :     return NS_ERROR_FAILURE;
    1469                 : 
    1470               1 :   NS_ENSURE_ARG_POINTER(aListener);
    1471                 : 
    1472               3 :   nsCOMPtr<nsIStreamListener> wrapper = new nsStreamListenerWrapper(mListener);
    1473                 : 
    1474               1 :   wrapper.forget(_retval);
    1475               1 :   mListener = aListener;
    1476               1 :   return NS_OK;
    1477                 : }
    1478                 : 
    1479                 : //-----------------------------------------------------------------------------
    1480                 : // HttpBaseChannel helpers
    1481                 : //-----------------------------------------------------------------------------
    1482                 : 
    1483                 : void
    1484              42 : HttpBaseChannel::DoNotifyListener()
    1485                 : {
    1486                 :   // Make sure mIsPending is set to false. At this moment we are done from
    1487                 :   // the point of view of our consumer and we have to report our self
    1488                 :   // as not-pending.
    1489              42 :   if (mListener) {
    1490              42 :     mListener->OnStartRequest(this, mListenerContext);
    1491              42 :     mIsPending = false;
    1492              42 :     mListener->OnStopRequest(this, mListenerContext, mStatus);
    1493              42 :     mListener = 0;
    1494              42 :     mListenerContext = 0;
    1495                 :   } else {
    1496               0 :     mIsPending = false;
    1497                 :   }
    1498                 :   // We have to make sure to drop the reference to the callbacks too
    1499              42 :   mCallbacks = nsnull;
    1500              42 :   mProgressSink = nsnull;
    1501                 : 
    1502              42 :   DoNotifyListenerCleanup();
    1503              42 : }
    1504                 : 
    1505                 : void
    1506            3506 : HttpBaseChannel::AddCookiesToRequest()
    1507                 : {
    1508            3506 :   if (mLoadFlags & LOAD_ANONYMOUS) {
    1509               1 :     return;
    1510                 :   }
    1511                 : 
    1512                 :   bool useCookieService = 
    1513            3505 :     (XRE_GetProcessType() == GeckoProcessType_Default);
    1514            7010 :   nsXPIDLCString cookie;
    1515            3505 :   if (useCookieService) {
    1516            3505 :     nsICookieService *cs = gHttpHandler->GetCookieService();
    1517            3505 :     if (cs) {
    1518                 :       cs->GetCookieStringFromHttp(mURI,
    1519                 :                                   nsnull,
    1520            3505 :                                   this, getter_Copies(cookie));
    1521                 :     }
    1522                 : 
    1523            3505 :     if (cookie.IsEmpty()) {
    1524            3498 :       cookie = mUserSetCookieHeader;
    1525                 :     }
    1526               7 :     else if (!mUserSetCookieHeader.IsEmpty()) {
    1527               1 :       cookie.Append(NS_LITERAL_CSTRING("; ") + mUserSetCookieHeader);
    1528                 :     }
    1529                 :   }
    1530                 :   else {
    1531               0 :     cookie = mUserSetCookieHeader;
    1532                 :   }
    1533                 : 
    1534                 :   // If we are in the child process, we want the parent seeing any
    1535                 :   // cookie headers that might have been set by SetRequestHeader()
    1536            3505 :   SetRequestHeader(nsDependentCString(nsHttp::Cookie), cookie, false);
    1537                 : }
    1538                 : 
    1539                 : static PLDHashOperator
    1540               0 : CopyProperties(const nsAString& aKey, nsIVariant *aData, void *aClosure)
    1541                 : {
    1542                 :   nsIWritablePropertyBag* bag = static_cast<nsIWritablePropertyBag*>
    1543               0 :                                            (aClosure);
    1544               0 :   bag->SetProperty(aKey, aData);
    1545               0 :   return PL_DHASH_NEXT;
    1546                 : }
    1547                 : 
    1548                 : // Return whether upon a redirect code of httpStatus for method, the
    1549                 : // request method should be rewritten to GET.
    1550                 : //
    1551                 : bool
    1552             151 : HttpBaseChannel::ShouldRewriteRedirectToGET(PRUint32 httpStatus,
    1553                 :                                             nsHttpAtom method)
    1554                 : {
    1555                 :   // for 301 and 302, only rewrite POST
    1556             151 :   if (httpStatus == 301 || httpStatus == 302)
    1557             123 :     return method == nsHttp::Post;
    1558                 : 
    1559                 :   // rewrite for 303 unless it was HEAD
    1560              28 :   if (httpStatus == 303)
    1561              12 :     return method != nsHttp::Head;
    1562                 : 
    1563                 :   // otherwise, such as for 307, do not rewrite
    1564              16 :   return false;
    1565                 : }   
    1566                 : 
    1567                 : // Return whether the specified method is safe as per RFC 2616, Section 9.1.1.
    1568                 : bool
    1569             135 : HttpBaseChannel::IsSafeMethod(nsHttpAtom method)
    1570                 : {
    1571                 :   // This code will need to be extended for new safe methods, otherwise
    1572                 :   // they'll default to "not safe".
    1573             135 :   return method == nsHttp::Get ||
    1574              30 :          method == nsHttp::Head ||
    1575              22 :          method == nsHttp::Options ||
    1576              22 :          method == nsHttp::Propfind ||
    1577              16 :          method == nsHttp::Report ||
    1578              16 :          method == nsHttp::Search ||
    1579             241 :          method == nsHttp::Trace;
    1580                 : }
    1581                 : 
    1582                 : nsresult
    1583             155 : HttpBaseChannel::SetupReplacementChannel(nsIURI       *newURI, 
    1584                 :                                          nsIChannel   *newChannel,
    1585                 :                                          bool          preserveMethod,
    1586                 :                                          bool          forProxy)
    1587                 : {
    1588             155 :   LOG(("HttpBaseChannel::SetupReplacementChannel "
    1589                 :      "[this=%p newChannel=%p preserveMethod=%d forProxy=%d]",
    1590                 :      this, newChannel, preserveMethod, forProxy));
    1591             155 :   PRUint32 newLoadFlags = mLoadFlags | LOAD_REPLACE;
    1592                 :   // if the original channel was using SSL and this channel is not using
    1593                 :   // SSL, then no need to inhibit persistent caching.  however, if the
    1594                 :   // original channel was not using SSL and has INHIBIT_PERSISTENT_CACHING
    1595                 :   // set, then allow the flag to apply to the redirected channel as well.
    1596                 :   // since we force set INHIBIT_PERSISTENT_CACHING on all HTTPS channels,
    1597                 :   // we only need to check if the original channel was using SSL.
    1598             155 :   if (mConnectionInfo->UsingSSL())
    1599               0 :     newLoadFlags &= ~INHIBIT_PERSISTENT_CACHING;
    1600                 : 
    1601                 :   // Do not pass along LOAD_CHECK_OFFLINE_CACHE
    1602             155 :   newLoadFlags &= ~nsICachingChannel::LOAD_CHECK_OFFLINE_CACHE;
    1603                 : 
    1604             155 :   newChannel->SetLoadGroup(mLoadGroup); 
    1605             155 :   newChannel->SetNotificationCallbacks(mCallbacks);
    1606             155 :   newChannel->SetLoadFlags(newLoadFlags);
    1607                 : 
    1608             310 :   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(newChannel);
    1609             155 :   if (!httpChannel)
    1610               2 :     return NS_OK; // no other options to set
    1611                 : 
    1612             153 :   if (preserveMethod) {
    1613                 :     nsCOMPtr<nsIUploadChannel> uploadChannel =
    1614             274 :       do_QueryInterface(httpChannel);
    1615                 :     nsCOMPtr<nsIUploadChannel2> uploadChannel2 =
    1616             274 :       do_QueryInterface(httpChannel);
    1617             137 :     if (mUploadStream && (uploadChannel2 || uploadChannel)) {
    1618                 :       // rewind upload stream
    1619               4 :       nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mUploadStream);
    1620               2 :       if (seekable)
    1621               2 :         seekable->Seek(nsISeekableStream::NS_SEEK_SET, 0);
    1622                 : 
    1623                 :       // replicate original call to SetUploadStream...
    1624               2 :       if (uploadChannel2) {
    1625               2 :         const char *ctype = mRequestHead.PeekHeader(nsHttp::Content_Type);
    1626               2 :         if (!ctype)
    1627               1 :           ctype = "";
    1628               2 :         const char *clen  = mRequestHead.PeekHeader(nsHttp::Content_Length);
    1629               2 :         PRInt64 len = clen ? nsCRT::atoll(clen) : -1;
    1630               2 :         uploadChannel2->ExplicitSetUploadStream(
    1631               2 :                                   mUploadStream, nsDependentCString(ctype), len,
    1632               4 :                                   nsDependentCString(mRequestHead.Method()),
    1633               4 :                                   mUploadStreamHasHeaders);
    1634                 :       } else {
    1635               0 :         if (mUploadStreamHasHeaders) {
    1636               0 :           uploadChannel->SetUploadStream(mUploadStream, EmptyCString(),
    1637               0 :                            -1);
    1638                 :         } else {
    1639                 :           const char *ctype =
    1640               0 :             mRequestHead.PeekHeader(nsHttp::Content_Type);
    1641                 :           const char *clen =
    1642               0 :             mRequestHead.PeekHeader(nsHttp::Content_Length);
    1643               0 :           if (!ctype) {
    1644               0 :             ctype = "application/octet-stream";
    1645                 :           }
    1646               0 :           if (clen) {
    1647               0 :             uploadChannel->SetUploadStream(mUploadStream,
    1648               0 :                                            nsDependentCString(ctype),
    1649               0 :                                            atoi(clen));
    1650                 :           }
    1651                 :         }
    1652                 :       }
    1653                 :     }
    1654                 :     // since preserveMethod is true, we need to ensure that the appropriate 
    1655                 :     // request method gets set on the channel, regardless of whether or not 
    1656                 :     // we set the upload stream above. This means SetRequestMethod() will
    1657                 :     // be called twice if ExplicitSetUploadStream() gets called above.
    1658                 : 
    1659             137 :     httpChannel->SetRequestMethod(nsDependentCString(mRequestHead.Method()));
    1660                 :   }
    1661                 :   // convey the referrer if one was used for this channel to the next one
    1662             153 :   if (mReferrer)
    1663               0 :     httpChannel->SetReferrer(mReferrer);
    1664                 :   // convey the mAllowPipelining flag
    1665             153 :   httpChannel->SetAllowPipelining(mAllowPipelining);
    1666                 :   // convey the new redirection limit
    1667             153 :   httpChannel->SetRedirectionLimit(mRedirectionLimit - 1);
    1668                 : 
    1669             306 :   nsCOMPtr<nsIHttpChannelInternal> httpInternal = do_QueryInterface(newChannel);
    1670             153 :   if (httpInternal) {
    1671                 :     // convey the mForceAllowThirdPartyCookie flag
    1672             153 :     httpInternal->SetForceAllowThirdPartyCookie(mForceAllowThirdPartyCookie);
    1673                 :     // convey the spdy flag
    1674             153 :     httpInternal->SetAllowSpdy(mAllowSpdy);
    1675                 : 
    1676                 :     // update the DocumentURI indicator since we are being redirected.
    1677                 :     // if this was a top-level document channel, then the new channel
    1678                 :     // should have its mDocumentURI point to newURI; otherwise, we
    1679                 :     // just need to pass along our mDocumentURI to the new channel.
    1680             153 :     if (newURI && (mURI == mDocumentURI))
    1681               0 :       httpInternal->SetDocumentURI(newURI);
    1682                 :     else
    1683             153 :       httpInternal->SetDocumentURI(mDocumentURI);
    1684                 : 
    1685                 :     // if there is a chain of keys for redirect-responses we transfer it to
    1686                 :     // the new channel (see bug #561276)
    1687             153 :     if (mRedirectedCachekeys) {
    1688              11 :         LOG(("HttpBaseChannel::SetupReplacementChannel "
    1689                 :              "[this=%p] transferring chain of redirect cache-keys", this));
    1690              11 :         httpInternal->SetCacheKeysRedirectChain(mRedirectedCachekeys);
    1691              11 :         mRedirectedCachekeys = nsnull;
    1692                 :     }
    1693                 :   }
    1694                 :   
    1695                 :   // transfer application cache information
    1696                 :   nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel =
    1697             306 :     do_QueryInterface(newChannel);
    1698             153 :   if (appCacheChannel) {
    1699             153 :     appCacheChannel->SetApplicationCache(mApplicationCache);
    1700             153 :     appCacheChannel->SetInheritApplicationCache(mInheritApplicationCache);
    1701                 :     // We purposely avoid transfering mChooseApplicationCache.
    1702                 :   }
    1703                 : 
    1704                 :   // transfer any properties
    1705             306 :   nsCOMPtr<nsIWritablePropertyBag> bag(do_QueryInterface(newChannel));
    1706             153 :   if (bag)
    1707             153 :     mPropertyHash.EnumerateRead(CopyProperties, bag.get());
    1708                 : 
    1709                 :   // transfer timed channel enabled status
    1710             306 :   nsCOMPtr<nsITimedChannel> timed(do_QueryInterface(newChannel));
    1711             153 :   if (timed)
    1712             153 :     timed->SetTimingEnabled(mTimingEnabled);
    1713                 : 
    1714             153 :   if (forProxy) {
    1715                 :     // Transfer all the headers from the previous channel
    1716                 :     //  this is needed for any headers that are not covered by the code above
    1717                 :     //  or have been set separately. e.g. manually setting Referer without
    1718                 :     //  setting up mReferrer
    1719              12 :     PRUint32 count = mRequestHead.Headers().Count();
    1720              87 :     for (PRUint32 i = 0; i < count; ++i) {
    1721                 :       nsHttpAtom header;
    1722              75 :       const char *value = mRequestHead.Headers().PeekHeaderAt(i, header);
    1723                 : 
    1724             150 :       httpChannel->SetRequestHeader(nsDependentCString(header),
    1725             150 :                                     nsDependentCString(value), false);
    1726                 :     }
    1727                 :   }
    1728                 : 
    1729             153 :   return NS_OK;
    1730                 : }
    1731                 : 
    1732                 : //------------------------------------------------------------------------------
    1733                 : 
    1734                 : }  // namespace net
    1735                 : }  // namespace mozilla
    1736                 : 

Generated by: LCOV version 1.7